-
Notifications
You must be signed in to change notification settings - Fork 112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Expose a safe interface for EVP_AEAD #68
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like a good start :) I left a lot of comments - none of them are critical, but it would be nice to address at least some before merging.
Could you add EVP_aead_aes_256_gcm_randnonce
and EVP_aead_aes_128_gcm_randnonce
under a cfg(feature = "fips")
flag? EVP_aead_aes_128_ccm_bluetooth
, EVP_aead_aes_128_ccm_bluetooth_8
, and EVP_has_aes_hardware
also seem to be missing, I think you can add those unconditionally.
|
||
/// Returns the length of nonces used with this AEAD. | ||
pub fn nonce_len(&self) -> usize { | ||
unsafe { EVP_AEAD_nonce_length(self.0) as usize } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Casting here doesn't seem correct - can you change this to return libc::size_t
instead? Same for all the other functions returning usize
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to maintain parity with symm.rs
which uses this pattern when returning lengths:
Lines 187 to 191 in e6ddc40
/// Returns the length of keys used with this cipher. | |
#[allow(clippy::trivially_copy_pass_by_ref)] | |
pub fn key_len(&self) -> usize { | |
unsafe { EVP_CIPHER_key_length(self.0) as usize } | |
} |
boring/src/aead.rs
Outdated
unsafe { EVP_AEAD_nonce_length(self.0) as usize } | ||
} | ||
|
||
/// Returns the maximum ciphertext overhead with this AEAD. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's use the upstream documentation here, I'd prefer not to reuse the word "overhead" when defining what it means.
/// Returns the maximum ciphertext overhead with this AEAD. | |
/// Returns the maximum number of additional bytes added by the act of sealing data with `self`. | |
/// | |
/// Corresponds to [`EVP_AEAD_max_overhead`](https://commondatastorage.googleapis.com/chromium-boringssl-docs/aead.h.html#EVP_AEAD_max_overhead). |
} | ||
|
||
pub fn as_ptr(&self) -> *const ffi::EVP_AEAD { | ||
self.0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
boring does this elsewhere in the codebase with ForeignType
- is there a reason you didn't use that here? https://docs.rs/boring/latest/boring/dh/struct.Dh.html#impl-ForeignType
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to follow the one in symm.rs
.
Lines 182 to 185 in e6ddc40
#[allow(clippy::trivially_copy_pass_by_ref)] | |
pub fn as_ptr(&self) -> *const ffi::EVP_CIPHER { | |
self.0 | |
} |
boring/src/aead.rs
Outdated
} | ||
|
||
unsafe impl Sync for Aead {} | ||
unsafe impl Send for Aead {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do you know the cipher is thread-safe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, I don't, I accidentally assumed that it was, and the the documentation doesn't seem explicit on this, so I'll remove the lines.
boring/src/aead.rs
Outdated
unsafe impl Send for Aead {} | ||
|
||
/// Represents an AEAD context. | ||
pub struct AeadCrypter { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you mentioned wanting to come up with a better name - I think AeadContext
would be a good fit. But this also seems fine as-is.
/// Encrypts the provided data and authenticates the ciphertext and the provided aad. | ||
/// | ||
/// Returns the sealed data as a vector. | ||
pub fn encrypt_aead( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this be an inherent method on Aead
maybe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. I defined them separately for parity with symm.rs
.
Lines 635 to 685 in e6ddc40
/// Like `encrypt`, but for AEAD ciphers such as AES GCM. | |
/// | |
/// Additional Authenticated Data can be provided in the `aad` field, and the authentication tag | |
/// will be copied into the `tag` field. | |
/// | |
/// The size of the `tag` buffer indicates the required size of the tag. While some ciphers support | |
/// a range of tag sizes, it is recommended to pick the maximum size. For AES GCM, this is 16 bytes, | |
/// for example. | |
pub fn encrypt_aead( | |
t: Cipher, | |
key: &[u8], | |
iv: Option<&[u8]>, | |
aad: &[u8], | |
data: &[u8], | |
tag: &mut [u8], | |
) -> Result<Vec<u8>, ErrorStack> { | |
let mut c = Crypter::new(t, Mode::Encrypt, key, iv)?; | |
let mut out = vec![0; data.len() + t.block_size()]; | |
c.aad_update(aad)?; | |
let count = c.update(data, &mut out)?; | |
let rest = c.finalize(&mut out[count..])?; | |
c.get_tag(tag)?; | |
out.truncate(count + rest); | |
Ok(out) | |
} | |
/// Like `decrypt`, but for AEAD ciphers such as AES GCM. | |
/// | |
/// Additional Authenticated Data can be provided in the `aad` field, and the authentication tag | |
/// should be provided in the `tag` field. | |
pub fn decrypt_aead( | |
t: Cipher, | |
key: &[u8], | |
iv: Option<&[u8]>, | |
aad: &[u8], | |
data: &[u8], | |
tag: &[u8], | |
) -> Result<Vec<u8>, ErrorStack> { | |
let mut c = Crypter::new(t, Mode::Decrypt, key, iv)?; | |
let mut out = vec![0; data.len() + t.block_size()]; | |
c.aad_update(aad)?; | |
let count = c.update(data, &mut out)?; | |
c.set_tag(tag)?; | |
let rest = c.finalize(&mut out[count..])?; | |
out.truncate(count + rest); | |
Ok(out) | |
} |
boring/src/aead.rs
Outdated
let mut aeadcrypter = AeadCrypter::new(aead, key)?; | ||
let mut output = vec![0u8; data.len() + aead.max_ciphertext_overhead()]; | ||
let bytes_written_to_output = aeadcrypter.seal(nonce, aad, data, &mut output)?; | ||
Ok(output[..bytes_written_to_output].to_vec()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok(output[..bytes_written_to_output].to_vec()) | |
output.truncate(bytes_written_to_output); | |
Ok(output) |
/// Authenticates the provided data and aad and decrypts the provided data. | ||
/// | ||
/// Returns the unsealed data as a vector. | ||
pub fn decrypt_aead( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto, this seems better as an inherent method.
boring/src/aead.rs
Outdated
let key = [0u8; 16]; | ||
let nonce = [0u8; 16]; | ||
let aad = [0u8; 16]; | ||
let data = [0u8; 16]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you use something other than zeros here? I'm not sure what boringssl does on zeros, and it seems better to be closer to a real scenario anyway.
Thank you for detailed comments! I made a few of the suggested changes; the others seem to break parity with |
Fix #58