When I provide a certain combination of key, iv and data, I get different results from the openssl
and the aes-ctr
encryption.
In particular, I used this wrapper:
pub extern crate generic_array;
extern crate crypto;
use aes_ctr::Aes128Ctr;
use aes_ctr::Aes192Ctr;
use aes_ctr::Aes256Ctr;
use aes_ctr::stream_cipher::generic_array::GenericArray;
use aes_ctr::stream_cipher::{
NewStreamCipher, SyncStreamCipher, SyncStreamCipherSeek
};
use openssl::symm;
use std::fs;
use std::env;
//use crypto::aes::{ctr, KeySize};
//use crypto::symmetriccipher::SynchronousStreamCipher;
use crypto::aes;
use std::vec::from_elem;
fn transform_data(key_size: usize,nonce_size: usize, data: &[u8])
-> Result<(Vec<u8>,Vec<u8>, Vec<u8>),&'static str>
{
if data.len() < key_size+nonce_size+1 {
return Err("Data too short");
}
let key = data[0..key_size].to_owned();
let nonce = data[key_size..key_size+nonce_size].to_owned();
let mut crypto_data = data[key_size+nonce_size..].to_owned();
Ok((key,nonce,crypto_data))
}
macro_rules! generate_aes_call {
(128,$key_generic:expr,$nonce_generic:expr) => {
Aes128Ctr::new(&$key_generic, &$nonce_generic);
};
(256,$key_generic:expr,$nonce_generic:expr) => {
Aes256Ctr::new(&$key_generic, &$nonce_generic);
}
}
macro_rules! generate_aes_openssl {
(128) => {
openssl::symm::Cipher::aes_128_ctr();
};
(256) => {
openssl::symm::Cipher::aes_256_ctr();
}
}
macro_rules! generate_crypto_aes_call {
(128,$key:expr,$nonce:expr) => {
crypto::aes::ctr(crypto::aes::KeySize::KeySize128, $key.as_slice(), $nonce.as_slice());
};
(256,$key:expr,$nonce:expr) => {
crypto::aes::ctr(crypto::aes::KeySize::KeySize256, $key.as_slice(), $nonce.as_slice());
};
}
fn main(){
let args: Vec<String> = env::args().collect();
let data = &fs::read(&args[1]).unwrap();
let (key, nonce, crypto_data) = match(transform_data((128 / 8), 16, data)){
Ok((key,nonce,crypto_data)) => (key,nonce,crypto_data),
Err(err_str) => {println!("Err: {:?}", err_str); return}
};
let original_data = crypto_data.to_owned();
let mut aes_ctr_crypto_data = crypto_data.to_owned();
let key_generic = GenericArray::from_slice(&key);
let nonce_generic = GenericArray::from_slice(&nonce);
let mut cipher = Aes128Ctr::new(&key_generic, &nonce_generic);
// apply keystream (encrypt)
cipher.apply_keystream(&mut aes_ctr_crypto_data);
println!("Keysize: {:?}", 128);
let openssl_cipher = generate_aes_openssl!(128);
let openssl_ciphertext = openssl::symm::encrypt(
openssl_cipher,
&key,
Some(&nonce),
&original_data).unwrap();
let mut cipher_crypto_aes = generate_crypto_aes_call!(128,key,nonce);
let mut output_crypto_aes: Vec<u8> = vec![0; original_data.len()];
cipher_crypto_aes.process(&original_data, output_crypto_aes.as_mut_slice());
println!("Key: {:?}",key);
println!("Nonce: {:?}", nonce);
println!("Key generic array: {:?}", key_generic);
println!("Nonce generic array: {:?}", nonce_generic);
println!("Data:\naes-ctr: {:?}\nopenssl: {:?}\ncrypto::aes: {:?}\noriginal_text: {:?}",aes_ctr_crypto_data,openssl_ciphertext,output_crypto_aes,original_data);
assert_eq!(output_crypto_aes,openssl_ciphertext,"Opensll and rust::crypto::aes not equal!");
assert_eq!(crypto_data,openssl_ciphertext, "Openssl and aes_ctr not equal");
println!("All equal\n");
// seek to the keystream beginning and apply it again to the `data` (decrypt)
cipher.seek(0);
cipher.apply_keystream(&mut aes_ctr_crypto_data);
assert_eq!(aes_ctr_crypto_data, original_data, "Decrypted data not equal");
}
And caledl it like so:
cargo run debug.crash
(file is attached), which reveals the following difference in encryption results between openssl and aes-ctr is revealed:
aes-ctr: [108, 253, 73, 159, 41, 43, 94, 79, 15, 121, 128, 186, 135, 246, 194, 87, 210, 245, 143, 26, 252, 148, 40, 251, 221, 123, 151, 112, 198, 148, 194, 86, 112, 124, 212, 82, 16, 202, 32, 36, 21, 69, 127, 56, 201, 111, 252, 108, 123, 166, 116, 191, 155, 79, 254, 41, 214, 68, 210, 96, 235, 239, 143, 101, 236, 141, 110, 227, 88, 157, 94, 39, 237, 104, 244, 167, 255, 124, 114, 238, 9, 185, 155, 13, 123, 34, 248, 104, 110, 165, 81, 34, 14, 84, 153, 97, 166, 34, 52, 106, 75, 253]
openssl: [108, 253, 73, 159, 41, 43, 94, 79, 15, 121, 128, 186, 135, 246, 194, 87, 27, 222, 233, 216, 2, 74, 106, 79, 70, 239, 105, 93, 125, 169, 59, 243, 171, 225, 15, 165, 102, 87, 79, 1, 31, 125, 151, 72, 199, 184, 71, 14, 69, 200, 13, 5, 171, 26, 106, 86, 129, 55, 254, 219, 166, 51, 34, 105, 154, 166, 12, 108, 239, 100, 153, 125, 229, 136, 86, 30, 233, 149, 169, 77, 154, 25, 226, 107, 205, 53, 144, 233, 62, 225, 237, 218, 7, 246, 61, 146, 31, 189, 212, 178, 104, 88]
Oddly enough, if I change the nonce in the file, openssl and aes-ctr produce the same result. Is this a bug or am I misusing the library?
Attached is a zip to easily reproduce this and the input the triggers the difference:
poc.zip
Run like so:
cd poc/
cargo run debug.crash