diff --git a/examples/crypto_bench.rs b/examples/crypto_bench.rs index a6208d7..cebe9a1 100644 --- a/examples/crypto_bench.rs +++ b/examples/crypto_bench.rs @@ -20,9 +20,7 @@ extern crate lang_items; use alloc::format; use alloc::vec::Vec; use core::fmt::Write; -use crypto::{ - aes256, cbc, ecdsa, rng256, sha256, Decrypt16BytesBlock, Encrypt16BytesBlock, Hash256, -}; +use crypto::{aes256, cbc, ecdsa, rng256, sha256, Hash256}; use libtock_drivers::console::Console; use libtock_drivers::result::FlexUnwrap; use libtock_drivers::timer; @@ -78,11 +76,11 @@ fn main() { // CBC let mut blocks = Vec::new(); for i in 0..8 { - blocks.resize(1 << i, [0; 16]); + blocks.resize(1 << (i + 4), 0); bench( &mut console, &timer, - &format!("cbc::cbc_encrypt({} bytes)", blocks.len() * 16), + &format!("cbc::cbc_encrypt({} bytes)", blocks.len()), || { cbc::cbc_encrypt(&ek, [0; 16], &mut blocks); }, @@ -92,11 +90,11 @@ fn main() { let mut blocks = Vec::new(); for i in 0..8 { - blocks.resize(1 << i, [0; 16]); + blocks.resize(1 << (i + 4), 0); bench( &mut console, &timer, - &format!("cbc::cbc_decrypt({} bytes)", blocks.len() * 16), + &format!("cbc::cbc_decrypt({} bytes)", blocks.len()), || { cbc::cbc_decrypt(&dk, [0; 16], &mut blocks); }, diff --git a/libraries/crypto/src/aes256.rs b/libraries/crypto/src/aes256.rs index 9c16bd4..da78810 100644 --- a/libraries/crypto/src/aes256.rs +++ b/libraries/crypto/src/aes256.rs @@ -13,7 +13,6 @@ // limitations under the License. use super::util::{xor_block_16, Block16}; -use super::{Decrypt16BytesBlock, Encrypt16BytesBlock}; use arrayref::{array_mut_ref, array_ref}; /** A portable and naive textbook implementation of AES-256 **/ @@ -54,11 +53,9 @@ impl EncryptionKey { EncryptionKey { enc_round_keys } } -} -impl Encrypt16BytesBlock for EncryptionKey { // Encrypt an AES block in place. - fn encrypt_block(&self, block: &mut Block16) { + pub fn encrypt_block(&self, block: &mut Block16) { add_round_key(block, &self.enc_round_keys[0]); for i in 1..14 { aes_enc(block, &self.enc_round_keys[i]); @@ -82,11 +79,9 @@ impl DecryptionKey { DecryptionKey { dec_round_keys } } -} -impl Decrypt16BytesBlock for DecryptionKey { // Decrypt an AES block in place. - fn decrypt_block(&self, block: &mut Block16) { + pub fn decrypt_block(&self, block: &mut Block16) { add_round_key(block, &self.dec_round_keys[0]); for i in 1..14 { aes_dec(block, &self.dec_round_keys[i]); diff --git a/libraries/crypto/src/cbc.rs b/libraries/crypto/src/cbc.rs index fd7dcc2..8c56c45 100644 --- a/libraries/crypto/src/cbc.rs +++ b/libraries/crypto/src/cbc.rs @@ -13,24 +13,21 @@ // limitations under the License. use super::util::{xor_block_16, Block16}; -use super::{Decrypt16BytesBlock, Encrypt16BytesBlock}; +use crate::aes256::{DecryptionKey, EncryptionKey}; +use core::convert::TryInto; -pub fn cbc_encrypt(key: &K, mut iv: Block16, blocks: &mut [Block16]) -where - K: Encrypt16BytesBlock, -{ - for block in blocks { +pub fn cbc_encrypt(key: &EncryptionKey, mut iv: Block16, blocks: &mut [u8]) { + for block in blocks.chunks_mut(16) { + let block: &mut Block16 = block.try_into().unwrap(); xor_block_16(block, &iv); key.encrypt_block(block); iv = *block; } } -pub fn cbc_decrypt(key: &K, mut iv: Block16, blocks: &mut [Block16]) -where - K: Decrypt16BytesBlock, -{ - for block in blocks { +pub fn cbc_decrypt(key: &DecryptionKey, mut iv: Block16, blocks: &mut [u8]) { + for block in blocks.chunks_mut(16) { + let block: &mut Block16 = block.try_into().unwrap(); let tmp = *block; key.decrypt_block(block); xor_block_16(block, &iv); @@ -54,11 +51,9 @@ mod test { let dec_key = aes256::DecryptionKey::new(&enc_key); for len in 0..16 { - let mut blocks: Vec = vec![Default::default(); len]; - for i in 0..len { - for j in 0..16 { - blocks[i][j] = ((len + i) * 16 + j) as u8; - } + let mut blocks: Vec = vec![0; 16 * len]; + for (i, x) in blocks.iter_mut().enumerate() { + *x = (16 * len + i) as u8; } let iv = [ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, @@ -80,10 +75,10 @@ mod test { 0x1c, 0x1d, 0x1e, 0x1f, ]); - let mut blocks = [[ + let mut blocks = [ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, - ]]; + ]; let iv = [0; 16]; cbc_encrypt(&key, iv, &mut blocks); @@ -93,7 +88,7 @@ mod test { ]; key.encrypt_block(&mut expected); - assert_eq!(blocks, [expected]); + assert_eq!(blocks, expected); } #[test] @@ -104,10 +99,10 @@ mod test { 0x1c, 0x1d, 0x1e, 0x1f, ])); - let mut blocks = [[ + let mut blocks = [ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, - ]]; + ]; let iv = [0; 16]; cbc_decrypt(&key, iv, &mut blocks); @@ -117,7 +112,7 @@ mod test { ]; key.decrypt_block(&mut expected); - assert_eq!(blocks, [expected]); + assert_eq!(blocks, expected); } #[test] @@ -128,10 +123,10 @@ mod test { 0x1c, 0x1d, 0x1e, 0x1f, ]); - let mut blocks = [[ + let mut blocks = [ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, - ]]; + ]; let iv = [ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, @@ -145,7 +140,7 @@ mod test { xor_block_16(&mut expected, &iv); key.encrypt_block(&mut expected); - assert_eq!(blocks, [expected]); + assert_eq!(blocks, expected); } #[test] @@ -156,10 +151,10 @@ mod test { 0x1c, 0x1d, 0x1e, 0x1f, ])); - let mut blocks = [[ + let mut blocks = [ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, - ]]; + ]; let iv = [ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, @@ -173,7 +168,7 @@ mod test { key.decrypt_block(&mut expected); xor_block_16(&mut expected, &iv); - assert_eq!(blocks, [expected]); + assert_eq!(blocks, expected); } #[test] @@ -185,14 +180,9 @@ mod test { ]); let mut blocks = [ - [ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, - 0x2e, 0x2f, - ], - [ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, - 0x4e, 0x4f, - ], + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, + 0x2e, 0x2f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, ]; let iv = [ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, @@ -200,20 +190,20 @@ mod test { ]; cbc_encrypt(&key, iv, &mut blocks); - let mut expected0 = [ + let mut expected = [ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, - 0x2e, 0x2f, - ]; - let mut expected1 = [ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, - 0x4e, 0x4f, + 0x2e, 0x2f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, ]; + let (expected0, expected1) = expected.split_at_mut(16); + let mut expected0: &mut Block16 = expected0.try_into().unwrap(); + let mut expected1: &mut Block16 = expected1.try_into().unwrap(); xor_block_16(&mut expected0, &iv); key.encrypt_block(&mut expected0); xor_block_16(&mut expected1, &expected0); key.encrypt_block(&mut expected1); - assert_eq!(blocks, [expected0, expected1]); + assert_eq!(blocks, expected); } #[test] @@ -225,14 +215,9 @@ mod test { ])); let mut blocks = [ - [ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, - 0x2e, 0x2f, - ], - [ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, - 0x4e, 0x4f, - ], + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, + 0x2e, 0x2f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, ]; let iv = [ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, @@ -240,19 +225,19 @@ mod test { ]; cbc_decrypt(&key, iv, &mut blocks); - let mut expected0 = [ + let mut expected = [ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, - 0x2e, 0x2f, - ]; - let mut expected1 = [ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, - 0x4e, 0x4f, + 0x2e, 0x2f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, ]; + let (expected0, expected1) = expected.split_at_mut(16); + let mut expected0: &mut Block16 = expected0.try_into().unwrap(); + let mut expected1: &mut Block16 = expected1.try_into().unwrap(); key.decrypt_block(&mut expected1); xor_block_16(&mut expected1, &expected0); key.decrypt_block(&mut expected0); xor_block_16(&mut expected0, &iv); - assert_eq!(blocks, [expected0, expected1]); + assert_eq!(blocks, expected); } } diff --git a/libraries/crypto/src/lib.rs b/libraries/crypto/src/lib.rs index 3281351..9f44983 100644 --- a/libraries/crypto/src/lib.rs +++ b/libraries/crypto/src/lib.rs @@ -47,15 +47,6 @@ pub trait Hash256: Sized { } } -// Traits for block ciphers that operate on 16-byte blocks. -pub trait Encrypt16BytesBlock { - fn encrypt_block(&self, block: &mut [u8; 16]); -} - -pub trait Decrypt16BytesBlock { - fn decrypt_block(&self, block: &mut [u8; 16]); -} - // Trait for hash functions that operate on 64-byte input blocks. pub trait HashBlockSize64Bytes { type State; diff --git a/libraries/crypto/tests/aesavs.rs b/libraries/crypto/tests/aesavs.rs index 5b6731a..4592d01 100644 --- a/libraries/crypto/tests/aesavs.rs +++ b/libraries/crypto/tests/aesavs.rs @@ -16,7 +16,7 @@ /// /// See also https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/aes/AESAVS.pdf use arrayref::array_ref; -use crypto::{aes256, Decrypt16BytesBlock, Encrypt16BytesBlock}; +use crypto::aes256; use regex::Regex; use std::fs::File; use std::io::{BufRead, BufReader}; diff --git a/src/ctap/crypto_wrapper.rs b/src/ctap/crypto_wrapper.rs index 2587e76..6de0c9a 100644 --- a/src/ctap/crypto_wrapper.rs +++ b/src/ctap/crypto_wrapper.rs @@ -13,7 +13,6 @@ // limitations under the License. use crate::ctap::status_code::Ctap2StatusCode; -use alloc::vec; use alloc::vec::Vec; use crypto::cbc::{cbc_decrypt, cbc_encrypt}; use crypto::rng256::Rng256; @@ -28,20 +27,17 @@ pub fn aes256_cbc_encrypt( if plaintext.len() % 16 != 0 { return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER); } + let mut ciphertext = Vec::with_capacity(plaintext.len() + 16 * embeds_iv as usize); let iv = if embeds_iv { let random_bytes = rng.gen_uniform_u8x32(); - *array_ref!(random_bytes, 0, 16) + ciphertext.extend_from_slice(&random_bytes[..16]); + *array_ref!(ciphertext, 0, 16) } else { [0u8; 16] }; - let mut blocks = Vec::with_capacity(plaintext.len() / 16); - // TODO(https://github.com/rust-lang/rust/issues/74985) Use array_chunks when stable. - for block in plaintext.chunks_exact(16) { - blocks.push(*array_ref!(block, 0, 16)); - } - cbc_encrypt(aes_enc_key, iv, &mut blocks); - let mut ciphertext = if embeds_iv { iv.to_vec() } else { vec![] }; - ciphertext.extend(blocks.iter().flatten()); + let start = ciphertext.len(); + ciphertext.extend_from_slice(plaintext); + cbc_encrypt(aes_enc_key, iv, &mut ciphertext[start..]); Ok(ciphertext) } @@ -51,28 +47,19 @@ pub fn aes256_cbc_decrypt( ciphertext: &[u8], embeds_iv: bool, ) -> Result, Ctap2StatusCode> { - if ciphertext.len() % 16 != 0 { + if ciphertext.len() % 16 != 0 || (embeds_iv && ciphertext.is_empty()) { return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER); } - let mut block_len = ciphertext.len() / 16; - // TODO(https://github.com/rust-lang/rust/issues/74985) Use array_chunks when stable. - let mut block_iter = ciphertext.chunks_exact(16); - let iv = if embeds_iv { - block_len -= 1; - let iv_block = block_iter - .next() - .ok_or(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)?; - *array_ref!(iv_block, 0, 16) + let (iv, ciphertext) = if embeds_iv { + let (iv, ciphertext) = ciphertext.split_at(16); + (*array_ref!(iv, 0, 16), ciphertext) } else { - [0u8; 16] + ([0u8; 16], ciphertext) }; - let mut blocks = Vec::with_capacity(block_len); - for block in block_iter { - blocks.push(*array_ref!(block, 0, 16)); - } + let mut plaintext = ciphertext.to_vec(); let aes_dec_key = crypto::aes256::DecryptionKey::new(aes_enc_key); - cbc_decrypt(&aes_dec_key, iv, &mut blocks); - Ok(blocks.iter().flatten().cloned().collect::>()) + cbc_decrypt(&aes_dec_key, iv, &mut plaintext); + Ok(plaintext) } #[cfg(test)]