diff options
Diffstat (limited to 'third_party/rust/neqo-crypto/src/aead.rs')
-rw-r--r-- | third_party/rust/neqo-crypto/src/aead.rs | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/third_party/rust/neqo-crypto/src/aead.rs b/third_party/rust/neqo-crypto/src/aead.rs new file mode 100644 index 0000000000..74f0ae0ce2 --- /dev/null +++ b/third_party/rust/neqo-crypto/src/aead.rs @@ -0,0 +1,161 @@ +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use crate::constants::{Cipher, Version}; +use crate::err::Res; +use crate::p11::{PK11SymKey, SymKey}; +use crate::ssl; +use crate::ssl::{PRUint16, PRUint64, PRUint8, SSLAeadContext}; + +use std::convert::{TryFrom, TryInto}; +use std::fmt; +use std::ops::{Deref, DerefMut}; +use std::os::raw::{c_char, c_uint}; +use std::ptr::null_mut; + +experimental_api!(SSL_MakeAead( + version: PRUint16, + cipher: PRUint16, + secret: *mut PK11SymKey, + label_prefix: *const c_char, + label_prefix_len: c_uint, + ctx: *mut *mut SSLAeadContext, +)); +experimental_api!(SSL_AeadEncrypt( + ctx: *const SSLAeadContext, + counter: PRUint64, + aad: *const PRUint8, + aad_len: c_uint, + input: *const PRUint8, + input_len: c_uint, + output: *const PRUint8, + output_len: *mut c_uint, + max_output: c_uint +)); +experimental_api!(SSL_AeadDecrypt( + ctx: *const SSLAeadContext, + counter: PRUint64, + aad: *const PRUint8, + aad_len: c_uint, + input: *const PRUint8, + input_len: c_uint, + output: *const PRUint8, + output_len: *mut c_uint, + max_output: c_uint +)); +experimental_api!(SSL_DestroyAead(ctx: *mut SSLAeadContext)); +scoped_ptr!(AeadContext, SSLAeadContext, SSL_DestroyAead); + +pub struct Aead { + ctx: AeadContext, +} + +impl Aead { + /// Create a new AEAD based on the indicated TLS version and cipher suite. + /// + /// # Errors + /// Returns `Error` when the supporting NSS functions fail. + pub fn new(version: Version, cipher: Cipher, secret: &SymKey, prefix: &str) -> Res<Self> { + let s: *mut PK11SymKey = **secret; + unsafe { Self::from_raw(version, cipher, s, prefix) } + } + + #[must_use] + #[allow(clippy::unused_self)] + pub fn expansion(&self) -> usize { + 16 + } + + unsafe fn from_raw( + version: Version, + cipher: Cipher, + secret: *mut PK11SymKey, + prefix: &str, + ) -> Res<Self> { + let p = prefix.as_bytes(); + let mut ctx: *mut ssl::SSLAeadContext = null_mut(); + SSL_MakeAead( + version, + cipher, + secret, + p.as_ptr().cast(), + c_uint::try_from(p.len())?, + &mut ctx, + )?; + Ok(Self { + ctx: AeadContext::from_ptr(ctx)?, + }) + } + + /// Decrypt a plaintext. + /// + /// The space provided in `output` needs to be larger than `input` by + /// the value provided in `Aead::expansion`. + /// + /// # Errors + /// If the input can't be protected or any input is too large for NSS. + pub fn encrypt<'a>( + &self, + count: u64, + aad: &[u8], + input: &[u8], + output: &'a mut [u8], + ) -> Res<&'a [u8]> { + let mut l: c_uint = 0; + unsafe { + SSL_AeadEncrypt( + *self.ctx.deref(), + count, + aad.as_ptr(), + c_uint::try_from(aad.len())?, + input.as_ptr(), + c_uint::try_from(input.len())?, + output.as_mut_ptr(), + &mut l, + c_uint::try_from(output.len())?, + ) + }?; + Ok(&output[0..(l.try_into()?)]) + } + + /// Decrypt a ciphertext. + /// + /// Note that NSS insists upon having extra space available for decryption, so + /// the buffer for `output` should be the same length as `input`, even though + /// the final result will be shorter. + /// + /// # Errors + /// If the input isn't authenticated or any input is too large for NSS. + pub fn decrypt<'a>( + &self, + count: u64, + aad: &[u8], + input: &[u8], + output: &'a mut [u8], + ) -> Res<&'a [u8]> { + let mut l: c_uint = 0; + unsafe { + SSL_AeadDecrypt( + *self.ctx.deref(), + count, + aad.as_ptr(), + c_uint::try_from(aad.len())?, + input.as_ptr(), + c_uint::try_from(input.len())?, + output.as_mut_ptr(), + &mut l, + c_uint::try_from(output.len())?, + ) + }?; + Ok(&output[0..(l.try_into()?)]) + } +} + +impl fmt::Debug for Aead { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "[AEAD Context]") + } +} |