//! A counter mode (CTR) for AES to work with the encryption used in zip files. //! //! This was implemented since the zip specification requires the mode to not use a nonce and uses a //! different byte order (little endian) than NIST (big endian). //! See [AesCtrZipKeyStream] for more information.
usecrate::unstable::LittleEndianWriteExt; use aes::cipher::generic_array::GenericArray; use aes::cipher::{BlockEncrypt, KeyInit}; use std::{any, fmt};
/// Internal block size of an AES cipher. const AES_BLOCK_SIZE: usize = 16;
/// An AES cipher kind. pubtrait AesKind { /// Key type. type Key: AsRef<[u8]>; /// Cipher used to decrypt. type Cipher: KeyInit;
}
impl AesKind for Aes128 { type Key = [u8; 16]; type Cipher = aes::Aes128;
}
impl AesKind for Aes192 { type Key = [u8; 24]; type Cipher = aes::Aes192;
}
impl AesKind for Aes256 { type Key = [u8; 32]; type Cipher = aes::Aes256;
}
/// An AES-CTR key stream generator. /// /// Implements the slightly non-standard AES-CTR variant used by WinZip AES encryption. /// /// Typical AES-CTR implementations combine a nonce with a 64 bit counter. WinZIP AES instead uses /// no nonce and also uses a different byte order (little endian) than NIST (big endian). /// /// The stream implements the `Read` trait; encryption or decryption is performed by XOR-ing the /// bytes from the key stream with the ciphertext/plaintext. pubstruct AesCtrZipKeyStream<C: AesKind> { /// Current AES counter.
counter: u128, /// AES cipher instance.
cipher: C::Cipher, /// Stores the currently available keystream bytes.
buffer: [u8; AES_BLOCK_SIZE], /// Number of bytes already used up from `buffer`.
pos: usize,
}
/// This trait allows using generic AES ciphers with different key sizes. pubtrait AesCipher { fn crypt_in_place(&mutself, target: &mut [u8]);
}
/// XORs a slice in place with another slice. #[inline] fn xor(dest: &mut [u8], src: &[u8]) {
assert_eq!(dest.len(), src.len());
for (lhs, rhs) in dest.iter_mut().zip(src.iter()) {
*lhs ^= *rhs;
}
}
#[cfg(test)] mod tests { usesuper::{Aes128, Aes192, Aes256, AesCipher, AesCtrZipKeyStream, AesKind}; use aes::cipher::{BlockEncrypt, KeyInit};
/// Checks whether `crypt_in_place` produces the correct plaintext after one use and yields the /// cipertext again after applying it again. fn roundtrip<Aes>(key: &[u8], ciphertext: &[u8], expected_plaintext: &[u8]) where
Aes: AesKind,
Aes::Cipher: KeyInit + BlockEncrypt,
{ letmut key_stream = AesCtrZipKeyStream::<Aes>::new(key);
// The data used in these tests was generated with p7zip without any compression. // It's not possible to recreate the exact same data, since a random salt is used for encryption. // `7z a -phelloworld -mem=AES256 -mx=0 aes256_40byte.zip 40byte_data.txt` #[test] fn crypt_aes_256_0_byte() { let ciphertext = []; let expected_plaintext = &[]; let key = [ 0x0b, 0xec, 0x2e, 0xf2, 0x46, 0xf0, 0x7e, 0x35, 0x16, 0x54, 0xe0, 0x98, 0x10, 0xb3, 0x18, 0x55, 0x24, 0xa3, 0x9e, 0x0e, 0x40, 0xe7, 0x92, 0xad, 0xb2, 0x8a, 0x48, 0xf4, 0x5c, 0xd0, 0xc0, 0x54,
];
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.