diff --git a/src/crypto/aead.rs b/src/crypto/aead.rs index 29cdb560..2b8457c0 100644 --- a/src/crypto/aead.rs +++ b/src/crypto/aead.rs @@ -16,21 +16,31 @@ use bytes::{Bytes, BytesMut}; /// Encryptor API for AEAD ciphers pub trait AeadEncryptor { - /// Encrypt `input` to `output` with `tag`. `output.len()` should equals to `input.len()+tag.len()`. + /// Encrypt `input` to `output` with `tag`. `output.len()` should equals to `input.len() + tag.len()`. + /// ```plain + /// +----------------------------------------+-----------------------+ + /// | ENCRYPTED TEXT (length = input.len()) | TAG | + /// +----------------------------------------+-----------------------+ + /// ``` fn encrypt(&mut self, input: &[u8], output: &mut [u8]); } /// Decryptor API for AEAD ciphers pub trait AeadDecryptor { - /// Decrypt `input` to `output` with `tag`. `output.len()` should equals to `input.len()+tag.len()`. + /// Decrypt `input` to `output` with `tag`. `output.len()` should equals to `input.len() - tag.len()`. + /// ```plain + /// +----------------------------------------+-----------------------+ + /// | ENCRYPTED TEXT (length = output.len()) | TAG | + /// +----------------------------------------+-----------------------+ + /// ``` fn decrypt(&mut self, input: &[u8], output: &mut [u8]) -> CipherResult<()>; } /// Variant `AeadDecryptor` -pub type BoxAeadDecryptor = Box; +pub type BoxAeadDecryptor = Box; /// Variant `AeadEncryptor` -pub type BoxAeadEncryptor = Box; +pub type BoxAeadEncryptor = Box; /// Generate a specific AEAD cipher encryptor pub fn new_aead_encryptor(t: CipherType, key: &[u8], nonce: &[u8]) -> BoxAeadEncryptor { diff --git a/src/crypto/siv.rs b/src/crypto/siv.rs index 1553cba4..0a8b4970 100644 --- a/src/crypto/siv.rs +++ b/src/crypto/siv.rs @@ -69,22 +69,24 @@ impl AeadEncryptor for MiscreantCipher { let tag_len = self.cipher_type.tag_size(); let buf_len = input.len() + tag_len; + // Miscreant requires tag to be in front of text let mut buf = BytesMut::with_capacity(buf_len); unsafe { buf.set_len(buf_len); } buf[tag_len..].copy_from_slice(input); + // NOTE: Must swap tag and encrypted text to output match self.cipher { MiscreantCryptoVariant::Aes128(ref mut cipher) => { cipher.seal_in_place(&self.nonce, b"", &mut buf); - (&mut output[..input.len()]).copy_from_slice(&buf[tag_len..]); - (&mut output[input.len()..]).copy_from_slice(&buf[..tag_len]); + output[..input.len()].copy_from_slice(&buf[tag_len..]); + output[input.len()..].copy_from_slice(&buf[..tag_len]); } MiscreantCryptoVariant::Aes256(ref mut cipher) => { cipher.seal_in_place(&self.nonce, b"", &mut buf); - (&mut output[..input.len()]).copy_from_slice(&buf[tag_len..]); - (&mut output[input.len()..]).copy_from_slice(&buf[..tag_len]); + output[..input.len()].copy_from_slice(&buf[tag_len..]); + output[input.len()..].copy_from_slice(&buf[..tag_len]); } } @@ -95,6 +97,9 @@ impl AeadEncryptor for MiscreantCipher { impl AeadDecryptor for MiscreantCipher { fn decrypt(&mut self, input: &[u8], output: &mut [u8]) -> CipherResult<()> { let tag_size = self.cipher_type.tag_size(); + + // Swap encrypted text and tag + // Miscreant requires tag in front of encrypted text let mut buf = BytesMut::with_capacity(input.len() + tag_size); buf.put_slice(&input[input.len() - tag_size..]); buf.put_slice(&input[..input.len() - tag_size]); diff --git a/src/crypto/sodium.rs b/src/crypto/sodium.rs index e7966100..7dfe49ad 100644 --- a/src/crypto/sodium.rs +++ b/src/crypto/sodium.rs @@ -84,30 +84,38 @@ fn crypto_stream_xor_ic(t: CipherType, let ret = unsafe { match t { - CipherType::ChaCha20 => crypto_stream_chacha20_xor_ic(out.bytes_mut().as_mut_ptr(), - data.as_ptr(), - data.len() as c_ulonglong, - iv.as_ptr(), - ic as c_ulonglong, - key.as_ptr()), - CipherType::ChaCha20Ietf => crypto_stream_chacha20_ietf_xor_ic(out.bytes_mut().as_mut_ptr(), - data.as_ptr(), - data.len() as c_ulonglong, - iv.as_ptr(), - ic as uint32_t, - key.as_ptr()), - CipherType::Salsa20 => crypto_stream_salsa20_xor_ic(out.bytes_mut().as_mut_ptr(), - data.as_ptr(), - data.len() as c_ulonglong, - iv.as_ptr(), - ic as c_ulonglong, - key.as_ptr()), - CipherType::XSalsa20 => crypto_stream_xsalsa20_xor_ic(out.bytes_mut().as_mut_ptr(), - data.as_ptr(), - data.len() as c_ulonglong, - iv.as_ptr(), - ic as c_ulonglong, - key.as_ptr()), + CipherType::ChaCha20 => { + crypto_stream_chacha20_xor_ic(out.bytes_mut().as_mut_ptr(), + data.as_ptr(), + data.len() as c_ulonglong, + iv.as_ptr(), + ic as c_ulonglong, + key.as_ptr()) + } + CipherType::ChaCha20Ietf => { + crypto_stream_chacha20_ietf_xor_ic(out.bytes_mut().as_mut_ptr(), + data.as_ptr(), + data.len() as c_ulonglong, + iv.as_ptr(), + ic as uint32_t, + key.as_ptr()) + } + CipherType::Salsa20 => { + crypto_stream_salsa20_xor_ic(out.bytes_mut().as_mut_ptr(), + data.as_ptr(), + data.len() as c_ulonglong, + iv.as_ptr(), + ic as c_ulonglong, + key.as_ptr()) + } + CipherType::XSalsa20 => { + crypto_stream_xsalsa20_xor_ic(out.bytes_mut().as_mut_ptr(), + data.as_ptr(), + data.len() as c_ulonglong, + iv.as_ptr(), + ic as c_ulonglong, + key.as_ptr()) + } _ => unreachable!(), } }; @@ -177,10 +185,10 @@ impl AeadEncryptor for SodiumAeadCipher { let buf_len = input.len() + tag_len; assert!(output.len() >= buf_len); + let mut len: c_ulonglong = output.len() as c_ulonglong; + let ret = match self.cipher_type { CipherType::XChaCha20IetfPoly1305 => unsafe { - let mut len: c_ulonglong = output.len() as c_ulonglong; - crypto_aead_xchacha20poly1305_ietf_encrypt(output.as_mut_ptr(), &mut len, input.as_ptr(), @@ -197,6 +205,7 @@ impl AeadEncryptor for SodiumAeadCipher { self.reset(); assert_eq!(ret, 0); + assert_eq!(len, output.len() as c_ulonglong); } } @@ -205,10 +214,10 @@ impl AeadDecryptor for SodiumAeadCipher { let tag_len = self.cipher_type.tag_size(); assert!(output.len() >= input.len() - tag_len); + let mut len: c_ulonglong = output.len() as c_ulonglong; + let ret = match self.cipher_type { CipherType::XChaCha20IetfPoly1305 => unsafe { - let mut len: c_ulonglong = output.len() as c_ulonglong; - crypto_aead_xchacha20poly1305_ietf_decrypt(output.as_mut_ptr(), &mut len, ptr::null_mut(), @@ -224,7 +233,7 @@ impl AeadDecryptor for SodiumAeadCipher { self.reset(); - if ret != 0 { + if ret != 0 || len != output.len() as c_ulonglong { return Err(Error::SodiumError); }