Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6072e959b0 | |||
| 5b122b8c0c | |||
| e84f6a865e | |||
| 52a9a56d38 | |||
| 57b4e37147 | |||
| 12599b9a63 | |||
| f15ae3e323 | |||
| c32fa6c2b6 | |||
| c07fccd57c | |||
| 08be0bf9e4 | |||
| ecc29f06fa |
2
.cargo/config
Normal file
2
.cargo/config
Normal file
@@ -0,0 +1,2 @@
|
||||
[target.'cfg(any(target_arch="x86",target_arch="x86_64"))']
|
||||
rustflags = ["-C","target-feature=+aes,+ssse3"]
|
||||
412
src/aes/aesni.rs
Normal file
412
src/aes/aesni.rs
Normal file
@@ -0,0 +1,412 @@
|
||||
#[cfg(target_arch="x86")]
|
||||
use std::arch::x86::*;
|
||||
#[cfg(target_arch="x86_64")]
|
||||
use std::arch::x86_64::*;
|
||||
#[cfg(test)]
|
||||
use std::mem::transmute;
|
||||
use std::mem::uninitialized;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 128-Bit Support
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub struct AES128 {
|
||||
expanded_enc: [__m128i; 11],
|
||||
expanded_dec: [__m128i; 11],
|
||||
}
|
||||
|
||||
macro_rules! expand128 {
|
||||
($v: expr, $r: expr) => {{
|
||||
let gen0 = _mm_aeskeygenassist_si128($v, $r);
|
||||
let gen1 = _mm_shuffle_epi32(gen0, 0xff);
|
||||
let key0 = $v;
|
||||
let key1 = _mm_xor_si128(key0, _mm_slli_si128(key0, 4));
|
||||
let key2 = _mm_xor_si128(key1, _mm_slli_si128(key1, 4));
|
||||
let key3 = _mm_xor_si128(key2, _mm_slli_si128(key2, 4));
|
||||
_mm_xor_si128(gen1, key3)
|
||||
}};
|
||||
}
|
||||
|
||||
impl AES128 {
|
||||
pub fn new(base_key: &[u8]) -> AES128 {
|
||||
assert_eq!(base_key.len(), 16);
|
||||
unsafe {
|
||||
let mut expanded_enc: [__m128i; 11] = uninitialized();
|
||||
let mut expanded_dec: [__m128i; 11] = uninitialized();
|
||||
|
||||
let initial_m128 = _mm_loadu_si128(base_key.as_ptr() as *const __m128i);
|
||||
_mm_store_si128(expanded_enc.as_mut_ptr(), initial_m128);
|
||||
|
||||
expanded_enc[1] = expand128!(expanded_enc[0], 0x01);
|
||||
expanded_enc[2] = expand128!(expanded_enc[1], 0x02);
|
||||
expanded_enc[3] = expand128!(expanded_enc[2], 0x04);
|
||||
expanded_enc[4] = expand128!(expanded_enc[3], 0x08);
|
||||
expanded_enc[5] = expand128!(expanded_enc[4], 0x10);
|
||||
expanded_enc[6] = expand128!(expanded_enc[5], 0x20);
|
||||
expanded_enc[7] = expand128!(expanded_enc[6], 0x40);
|
||||
expanded_enc[8] = expand128!(expanded_enc[7], 0x80);
|
||||
expanded_enc[9] = expand128!(expanded_enc[8], 0x1B);
|
||||
expanded_enc[10] = expand128!(expanded_enc[9], 0x36);
|
||||
|
||||
expanded_dec[0] = expanded_enc[10];
|
||||
expanded_dec[1] = _mm_aesimc_si128(expanded_enc[9]);
|
||||
expanded_dec[2] = _mm_aesimc_si128(expanded_enc[8]);
|
||||
expanded_dec[3] = _mm_aesimc_si128(expanded_enc[7]);
|
||||
expanded_dec[4] = _mm_aesimc_si128(expanded_enc[6]);
|
||||
expanded_dec[5] = _mm_aesimc_si128(expanded_enc[5]);
|
||||
expanded_dec[6] = _mm_aesimc_si128(expanded_enc[4]);
|
||||
expanded_dec[7] = _mm_aesimc_si128(expanded_enc[3]);
|
||||
expanded_dec[8] = _mm_aesimc_si128(expanded_enc[2]);
|
||||
expanded_dec[9] = _mm_aesimc_si128(expanded_enc[1]);
|
||||
expanded_dec[10] = expanded_enc[0];
|
||||
|
||||
AES128 { expanded_enc, expanded_dec }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn encrypt(&self, block: &[u8]) -> Vec<u8> {
|
||||
assert_eq!(block.len(), 16);
|
||||
let mut result = Vec::with_capacity(16);
|
||||
result.resize(16, 0);
|
||||
unsafe {
|
||||
let mut val = _mm_loadu_si128(block.as_ptr() as *const __m128i);
|
||||
val = _mm_xor_si128(val, self.expanded_enc[0]);
|
||||
val = _mm_aesenc_si128(val, self.expanded_enc[1]);
|
||||
val = _mm_aesenc_si128(val, self.expanded_enc[2]);
|
||||
val = _mm_aesenc_si128(val, self.expanded_enc[3]);
|
||||
val = _mm_aesenc_si128(val, self.expanded_enc[4]);
|
||||
val = _mm_aesenc_si128(val, self.expanded_enc[5]);
|
||||
val = _mm_aesenc_si128(val, self.expanded_enc[6]);
|
||||
val = _mm_aesenc_si128(val, self.expanded_enc[7]);
|
||||
val = _mm_aesenc_si128(val, self.expanded_enc[8]);
|
||||
val = _mm_aesenc_si128(val, self.expanded_enc[9]);
|
||||
val = _mm_aesenclast_si128(val, self.expanded_enc[10]);
|
||||
_mm_storeu_si128(result.as_mut_ptr() as *mut __m128i, val);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub fn decrypt(&self, block: &[u8]) -> Vec<u8> {
|
||||
assert_eq!(block.len(), 16);
|
||||
let mut result = Vec::with_capacity(16);
|
||||
result.resize(16, 0);
|
||||
unsafe {
|
||||
let mut val = _mm_loadu_si128(block.as_ptr() as *const __m128i);
|
||||
val = _mm_xor_si128(val, self.expanded_dec[0]);
|
||||
val = _mm_aesdec_si128(val, self.expanded_dec[1]);
|
||||
val = _mm_aesdec_si128(val, self.expanded_dec[2]);
|
||||
val = _mm_aesdec_si128(val, self.expanded_dec[3]);
|
||||
val = _mm_aesdec_si128(val, self.expanded_dec[4]);
|
||||
val = _mm_aesdec_si128(val, self.expanded_dec[5]);
|
||||
val = _mm_aesdec_si128(val, self.expanded_dec[6]);
|
||||
val = _mm_aesdec_si128(val, self.expanded_dec[7]);
|
||||
val = _mm_aesdec_si128(val, self.expanded_dec[8]);
|
||||
val = _mm_aesdec_si128(val, self.expanded_dec[9]);
|
||||
val = _mm_aesdeclast_si128(val, self.expanded_dec[10]);
|
||||
_mm_storeu_si128(result.as_mut_ptr() as *mut __m128i, val);
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn unpack_m128(b: __m128i) -> (u64, u64)
|
||||
{
|
||||
unsafe {
|
||||
let data: [u64; 2] = transmute(b);
|
||||
(data[0].to_be(), data[1].to_be())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod aes128 {
|
||||
use super::*;
|
||||
use testing::run_test;
|
||||
|
||||
#[test]
|
||||
fn expansion() {
|
||||
let zero_key = AES128::new(&[0x00; 16]);
|
||||
assert_eq!(unpack_m128(zero_key.expanded_enc[0]), (0x0000000000000000, 0x0000000000000000));
|
||||
assert_eq!(unpack_m128(zero_key.expanded_enc[1]), (0x6263636362636363, 0x6263636362636363));
|
||||
assert_eq!(unpack_m128(zero_key.expanded_enc[2]), (0x9b9898c9f9fbfbaa, 0x9b9898c9f9fbfbaa));
|
||||
assert_eq!(unpack_m128(zero_key.expanded_enc[3]), (0x90973450696ccffa, 0xf2f457330b0fac99));
|
||||
assert_eq!(unpack_m128(zero_key.expanded_enc[4]), (0xee06da7b876a1581, 0x759e42b27e91ee2b));
|
||||
assert_eq!(unpack_m128(zero_key.expanded_enc[5]), (0x7f2e2b88f8443e09, 0x8dda7cbbf34b9290));
|
||||
assert_eq!(unpack_m128(zero_key.expanded_enc[6]), (0xec614b851425758c, 0x99ff09376ab49ba7));
|
||||
assert_eq!(unpack_m128(zero_key.expanded_enc[7]), (0x217517873550620b, 0xacaf6b3cc61bf09b));
|
||||
assert_eq!(unpack_m128(zero_key.expanded_enc[8]), (0x0ef903333ba96138, 0x97060a04511dfa9f));
|
||||
assert_eq!(unpack_m128(zero_key.expanded_enc[9]), (0xb1d4d8e28a7db9da, 0x1d7bb3de4c664941));
|
||||
assert_eq!(unpack_m128(zero_key.expanded_enc[10]), (0xb4ef5bcb3e92e211, 0x23e951cf6f8f188e));
|
||||
let ff_key = AES128::new(&[0xff; 16]);
|
||||
assert_eq!(unpack_m128(ff_key.expanded_enc[0]), (0xffffffffffffffff, 0xffffffffffffffff));
|
||||
assert_eq!(unpack_m128(ff_key.expanded_enc[1]), (0xe8e9e9e917161616, 0xe8e9e9e917161616));
|
||||
assert_eq!(unpack_m128(ff_key.expanded_enc[2]), (0xadaeae19bab8b80f, 0x525151e6454747f0));
|
||||
assert_eq!(unpack_m128(ff_key.expanded_enc[3]), (0x090e2277b3b69a78, 0xe1e7cb9ea4a08c6e));
|
||||
assert_eq!(unpack_m128(ff_key.expanded_enc[4]), (0xe16abd3e52dc2746, 0xb33becd8179b60b6));
|
||||
assert_eq!(unpack_m128(ff_key.expanded_enc[5]), (0xe5baf3ceb766d488, 0x045d385013c658e6));
|
||||
assert_eq!(unpack_m128(ff_key.expanded_enc[6]), (0x71d07db3c6b6a93b, 0xc2eb916bd12dc98d));
|
||||
assert_eq!(unpack_m128(ff_key.expanded_enc[7]), (0xe90d208d2fbb89b6, 0xed5018dd3c7dd150));
|
||||
assert_eq!(unpack_m128(ff_key.expanded_enc[8]), (0x96337366b988fad0, 0x54d8e20d68a5335d));
|
||||
assert_eq!(unpack_m128(ff_key.expanded_enc[9]), (0x8bf03f233278c5f3, 0x66a027fe0e0514a3));
|
||||
assert_eq!(unpack_m128(ff_key.expanded_enc[10]), (0xd60a3588e472f07b, 0x82d2d7858cd7c326));
|
||||
let nist_key = AES128::new(&[0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6,0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c]);
|
||||
assert_eq!(unpack_m128(nist_key.expanded_enc[0]), (0x2b7e151628aed2a6, 0xabf7158809cf4f3c));
|
||||
assert_eq!(unpack_m128(nist_key.expanded_enc[1]), (0xa0fafe1788542cb1, 0x23a339392a6c7605));
|
||||
assert_eq!(unpack_m128(nist_key.expanded_enc[2]), (0xf2c295f27a96b943, 0x5935807a7359f67f));
|
||||
assert_eq!(unpack_m128(nist_key.expanded_enc[3]), (0x3d80477d4716fe3e, 0x1e237e446d7a883b));
|
||||
assert_eq!(unpack_m128(nist_key.expanded_enc[4]), (0xef44a541a8525b7f, 0xb671253bdb0bad00));
|
||||
assert_eq!(unpack_m128(nist_key.expanded_enc[5]), (0xd4d1c6f87c839d87, 0xcaf2b8bc11f915bc));
|
||||
assert_eq!(unpack_m128(nist_key.expanded_enc[6]), (0x6d88a37a110b3efd, 0xdbf98641ca0093fd));
|
||||
assert_eq!(unpack_m128(nist_key.expanded_enc[7]), (0x4e54f70e5f5fc9f3, 0x84a64fb24ea6dc4f));
|
||||
assert_eq!(unpack_m128(nist_key.expanded_enc[8]), (0xead27321b58dbad2, 0x312bf5607f8d292f));
|
||||
assert_eq!(unpack_m128(nist_key.expanded_enc[9]), (0xac7766f319fadc21, 0x28d12941575c006e));
|
||||
assert_eq!(unpack_m128(nist_key.expanded_enc[10]), (0xd014f9a8c9ee2589, 0xe13f0cc8b6630ca6));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fips197_examples() {
|
||||
let input1 = [0x32,0x43,0xf6,0xa8,0x88,0x5a,0x30,0x8d,0x31,0x31,0x98,0xa2,0xe0,0x37,0x07,0x34];
|
||||
let key1 = [0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6,0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c];
|
||||
let aeskey1 = AES128::new(&key1);
|
||||
let cipher1 = aeskey1.encrypt(&input1);
|
||||
assert_eq!(cipher1, vec![0x39,0x25,0x84,0x1d,0x02,0xdc,0x09,0xfb,
|
||||
0xdc,0x11,0x85,0x97,0x19,0x6a,0x0b,0x32]);
|
||||
assert_eq!(input1.to_vec(), aeskey1.decrypt(&cipher1));
|
||||
let input2 = [0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff];
|
||||
let key2 = [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f];
|
||||
let aeskey2 = AES128::new(&key2);
|
||||
let cipher2 = aeskey2.encrypt(&input2);
|
||||
assert_eq!(cipher2, vec![0x69,0xc4,0xe0,0xd8,0x6a,0x7b,0x04,0x30,
|
||||
0xd8,0xcd,0xb7,0x80,0x70,0xb4,0xc5,0x5a]);
|
||||
assert_eq!(input2.to_vec(), aeskey2.decrypt(&cipher2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nist_test_vectors() {
|
||||
let fname = "testdata/aes/aes128.test";
|
||||
run_test(fname.to_string(), 3, |case| {
|
||||
let (negk, kbytes) = case.get("k").unwrap();
|
||||
let (negp, pbytes) = case.get("p").unwrap();
|
||||
let (negc, cbytes) = case.get("c").unwrap();
|
||||
|
||||
assert!(!negk && !negp && !negc);
|
||||
let key = AES128::new(&kbytes);
|
||||
let cipher = key.encrypt(&pbytes);
|
||||
let plain = key.decrypt(&cipher);
|
||||
assert_eq!(&cipher, cbytes);
|
||||
assert_eq!(&plain, pbytes);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 256-Bit Support
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub struct AES256 {
|
||||
expanded_enc: [__m128i; 15],
|
||||
expanded_dec: [__m128i; 15],
|
||||
}
|
||||
|
||||
macro_rules! expand256 {
|
||||
($prevprev: expr, $prev: expr, $shuffle: expr, $round: expr) => {{
|
||||
let gen0 = _mm_aeskeygenassist_si128($prev, $round);
|
||||
let gen1 = _mm_shuffle_epi32(gen0, $shuffle);
|
||||
let key0 = $prevprev;
|
||||
let key1 = _mm_xor_si128(key0, _mm_slli_si128(key0, 4));
|
||||
let key2 = _mm_xor_si128(key1, _mm_slli_si128(key1, 4));
|
||||
let key3 = _mm_xor_si128(key2, _mm_slli_si128(key2, 4));
|
||||
_mm_xor_si128(gen1, key3)
|
||||
}};
|
||||
}
|
||||
|
||||
impl AES256 {
|
||||
pub fn new(base_key: &[u8]) -> AES256 {
|
||||
assert_eq!(base_key.len(), 32);
|
||||
unsafe {
|
||||
let mut expanded_enc: [__m128i; 15] = uninitialized();
|
||||
let mut expanded_dec: [__m128i; 15] = uninitialized();
|
||||
|
||||
let keyptr = base_key.as_ptr() as *const __m128i;
|
||||
expanded_enc[00] = _mm_loadu_si128(keyptr.offset(0));
|
||||
expanded_enc[01] = _mm_loadu_si128(keyptr.offset(1));
|
||||
expanded_enc[02] = expand256!(expanded_enc[00], expanded_enc[01], 0xff, 0x01);
|
||||
expanded_enc[03] = expand256!(expanded_enc[01], expanded_enc[02], 0xaa, 0x00);
|
||||
expanded_enc[04] = expand256!(expanded_enc[02], expanded_enc[03], 0xff, 0x02);
|
||||
expanded_enc[05] = expand256!(expanded_enc[03], expanded_enc[04], 0xaa, 0x00);
|
||||
expanded_enc[06] = expand256!(expanded_enc[04], expanded_enc[05], 0xff, 0x04);
|
||||
expanded_enc[07] = expand256!(expanded_enc[05], expanded_enc[06], 0xaa, 0x00);
|
||||
expanded_enc[08] = expand256!(expanded_enc[06], expanded_enc[07], 0xff, 0x08);
|
||||
expanded_enc[09] = expand256!(expanded_enc[07], expanded_enc[08], 0xaa, 0x00);
|
||||
expanded_enc[10] = expand256!(expanded_enc[08], expanded_enc[09], 0xff, 0x10);
|
||||
expanded_enc[11] = expand256!(expanded_enc[09], expanded_enc[10], 0xaa, 0x00);
|
||||
expanded_enc[12] = expand256!(expanded_enc[10], expanded_enc[11], 0xff, 0x20);
|
||||
expanded_enc[13] = expand256!(expanded_enc[11], expanded_enc[12], 0xaa, 0x00);
|
||||
expanded_enc[14] = expand256!(expanded_enc[12], expanded_enc[13], 0xff, 0x40);
|
||||
|
||||
expanded_dec[00] = expanded_enc[14];
|
||||
expanded_dec[01] = _mm_aesimc_si128(expanded_enc[13]);
|
||||
expanded_dec[02] = _mm_aesimc_si128(expanded_enc[12]);
|
||||
expanded_dec[03] = _mm_aesimc_si128(expanded_enc[11]);
|
||||
expanded_dec[04] = _mm_aesimc_si128(expanded_enc[10]);
|
||||
expanded_dec[05] = _mm_aesimc_si128(expanded_enc[09]);
|
||||
expanded_dec[06] = _mm_aesimc_si128(expanded_enc[08]);
|
||||
expanded_dec[07] = _mm_aesimc_si128(expanded_enc[07]);
|
||||
expanded_dec[08] = _mm_aesimc_si128(expanded_enc[06]);
|
||||
expanded_dec[09] = _mm_aesimc_si128(expanded_enc[05]);
|
||||
expanded_dec[10] = _mm_aesimc_si128(expanded_enc[04]);
|
||||
expanded_dec[11] = _mm_aesimc_si128(expanded_enc[03]);
|
||||
expanded_dec[12] = _mm_aesimc_si128(expanded_enc[02]);
|
||||
expanded_dec[13] = _mm_aesimc_si128(expanded_enc[01]);
|
||||
expanded_dec[14] = expanded_enc[0];
|
||||
|
||||
AES256{ expanded_enc, expanded_dec }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn encrypt(&self, block: &[u8]) -> Vec<u8> {
|
||||
assert_eq!(block.len(), 16);
|
||||
let mut result = Vec::with_capacity(16);
|
||||
result.resize(16, 0);
|
||||
unsafe {
|
||||
let mut val = _mm_loadu_si128(block.as_ptr() as *const __m128i);
|
||||
val = _mm_xor_si128(val, self.expanded_enc[0]);
|
||||
val = _mm_aesenc_si128(val, self.expanded_enc[01]);
|
||||
val = _mm_aesenc_si128(val, self.expanded_enc[02]);
|
||||
val = _mm_aesenc_si128(val, self.expanded_enc[03]);
|
||||
val = _mm_aesenc_si128(val, self.expanded_enc[04]);
|
||||
val = _mm_aesenc_si128(val, self.expanded_enc[05]);
|
||||
val = _mm_aesenc_si128(val, self.expanded_enc[06]);
|
||||
val = _mm_aesenc_si128(val, self.expanded_enc[07]);
|
||||
val = _mm_aesenc_si128(val, self.expanded_enc[08]);
|
||||
val = _mm_aesenc_si128(val, self.expanded_enc[09]);
|
||||
val = _mm_aesenc_si128(val, self.expanded_enc[10]);
|
||||
val = _mm_aesenc_si128(val, self.expanded_enc[11]);
|
||||
val = _mm_aesenc_si128(val, self.expanded_enc[12]);
|
||||
val = _mm_aesenc_si128(val, self.expanded_enc[13]);
|
||||
val = _mm_aesenclast_si128(val, self.expanded_enc[14]);
|
||||
_mm_storeu_si128(result.as_mut_ptr() as *mut __m128i, val);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub fn decrypt(&self, block: &[u8]) -> Vec<u8> {
|
||||
assert_eq!(block.len(), 16);
|
||||
let mut result = Vec::with_capacity(16);
|
||||
result.resize(16, 0);
|
||||
unsafe {
|
||||
let mut val = _mm_loadu_si128(block.as_ptr() as *const __m128i);
|
||||
val = _mm_xor_si128(val, self.expanded_dec[00]);
|
||||
val = _mm_aesdec_si128(val, self.expanded_dec[01]);
|
||||
val = _mm_aesdec_si128(val, self.expanded_dec[02]);
|
||||
val = _mm_aesdec_si128(val, self.expanded_dec[03]);
|
||||
val = _mm_aesdec_si128(val, self.expanded_dec[04]);
|
||||
val = _mm_aesdec_si128(val, self.expanded_dec[05]);
|
||||
val = _mm_aesdec_si128(val, self.expanded_dec[06]);
|
||||
val = _mm_aesdec_si128(val, self.expanded_dec[07]);
|
||||
val = _mm_aesdec_si128(val, self.expanded_dec[08]);
|
||||
val = _mm_aesdec_si128(val, self.expanded_dec[09]);
|
||||
val = _mm_aesdec_si128(val, self.expanded_dec[10]);
|
||||
val = _mm_aesdec_si128(val, self.expanded_dec[11]);
|
||||
val = _mm_aesdec_si128(val, self.expanded_dec[12]);
|
||||
val = _mm_aesdec_si128(val, self.expanded_dec[13]);
|
||||
val = _mm_aesdeclast_si128(val, self.expanded_dec[14]);
|
||||
_mm_storeu_si128(result.as_mut_ptr() as *mut __m128i, val);
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod aes256 {
|
||||
use super::*;
|
||||
use testing::run_test;
|
||||
|
||||
#[test]
|
||||
fn expansion() {
|
||||
let zero_key = AES256::new(&[0x00; 32]);
|
||||
assert_eq!(unpack_m128(zero_key.expanded_enc[00]), (0x0000000000000000, 0x0000000000000000));
|
||||
assert_eq!(unpack_m128(zero_key.expanded_enc[01]), (0x0000000000000000, 0x0000000000000000));
|
||||
assert_eq!(unpack_m128(zero_key.expanded_enc[02]), (0x6263636362636363, 0x6263636362636363));
|
||||
assert_eq!(unpack_m128(zero_key.expanded_enc[03]), (0xaafbfbfbaafbfbfb, 0xaafbfbfbaafbfbfb));
|
||||
assert_eq!(unpack_m128(zero_key.expanded_enc[04]), (0x6f6c6ccf0d0f0fac, 0x6f6c6ccf0d0f0fac));
|
||||
assert_eq!(unpack_m128(zero_key.expanded_enc[05]), (0x7d8d8d6ad7767691, 0x7d8d8d6ad7767691));
|
||||
assert_eq!(unpack_m128(zero_key.expanded_enc[06]), (0x5354edc15e5be26d, 0x31378ea23c38810e));
|
||||
assert_eq!(unpack_m128(zero_key.expanded_enc[07]), (0x968a81c141fcf750, 0x3c717a3aeb070cab));
|
||||
assert_eq!(unpack_m128(zero_key.expanded_enc[08]), (0x9eaa8f28c0f16d45, 0xf1c6e3e7cdfe62e9));
|
||||
assert_eq!(unpack_m128(zero_key.expanded_enc[09]), (0x2b312bdf6acddc8f, 0x56bca6b5bdbbaa1e));
|
||||
assert_eq!(unpack_m128(zero_key.expanded_enc[10]), (0x6406fd52a4f79017, 0x553173f098cf1119));
|
||||
assert_eq!(unpack_m128(zero_key.expanded_enc[11]), (0x6dbba90b07767584, 0x51cad331ec71792f));
|
||||
assert_eq!(unpack_m128(zero_key.expanded_enc[12]), (0xe7b0e89c4347788b, 0x16760b7b8eb91a62));
|
||||
assert_eq!(unpack_m128(zero_key.expanded_enc[13]), (0x74ed0ba1739b7e25, 0x2251ad14ce20d43b));
|
||||
assert_eq!(unpack_m128(zero_key.expanded_enc[14]), (0x10f80a1753bf729c, 0x45c979e7cb706385));
|
||||
let ff_key = AES256::new(&[0xff; 32]);
|
||||
assert_eq!(unpack_m128(ff_key.expanded_enc[00]), (0xffffffffffffffff, 0xffffffffffffffff));
|
||||
assert_eq!(unpack_m128(ff_key.expanded_enc[01]), (0xffffffffffffffff, 0xffffffffffffffff));
|
||||
assert_eq!(unpack_m128(ff_key.expanded_enc[02]), (0xe8e9e9e917161616, 0xe8e9e9e917161616));
|
||||
assert_eq!(unpack_m128(ff_key.expanded_enc[03]), (0x0fb8b8b8f0474747, 0x0fb8b8b8f0474747));
|
||||
assert_eq!(unpack_m128(ff_key.expanded_enc[04]), (0x4a4949655d5f5f73, 0xb5b6b69aa2a0a08c));
|
||||
assert_eq!(unpack_m128(ff_key.expanded_enc[05]), (0x355858dcc51f1f9b, 0xcaa7a7233ae0e064));
|
||||
assert_eq!(unpack_m128(ff_key.expanded_enc[06]), (0xafa80ae5f2f75596, 0x4741e30ce5e14380));
|
||||
assert_eq!(unpack_m128(ff_key.expanded_enc[07]), (0xeca0421129bf5d8a, 0xe318faa9d9f81acd));
|
||||
assert_eq!(unpack_m128(ff_key.expanded_enc[08]), (0xe60ab7d014fde246, 0x53bc014ab65d42ca));
|
||||
assert_eq!(unpack_m128(ff_key.expanded_enc[09]), (0xa2ec6e658b5333ef, 0x684bc946b1b3d38b));
|
||||
assert_eq!(unpack_m128(ff_key.expanded_enc[10]), (0x9b6c8a188f91685e, 0xdc2d69146a702bde));
|
||||
assert_eq!(unpack_m128(ff_key.expanded_enc[11]), (0xa0bd9f782beeac97, 0x43a565d1f216b65a));
|
||||
assert_eq!(unpack_m128(ff_key.expanded_enc[12]), (0xfc22349173b35ccf, 0xaf9e35dbc5ee1e05));
|
||||
assert_eq!(unpack_m128(ff_key.expanded_enc[13]), (0x0695ed132d7b4184, 0x6ede24559cc8920f));
|
||||
assert_eq!(unpack_m128(ff_key.expanded_enc[14]), (0x546d424f27de1e80, 0x88402b5b4dae355e));
|
||||
let nist_key = AES256::new(&[0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe,
|
||||
0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
|
||||
0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7,
|
||||
0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4]);
|
||||
assert_eq!(unpack_m128(nist_key.expanded_enc[00]), (0x603deb1015ca71be, 0x2b73aef0857d7781));
|
||||
assert_eq!(unpack_m128(nist_key.expanded_enc[01]), (0x1f352c073b6108d7, 0x2d9810a30914dff4));
|
||||
assert_eq!(unpack_m128(nist_key.expanded_enc[02]), (0x9ba354118e6925af, 0xa51a8b5f2067fcde));
|
||||
assert_eq!(unpack_m128(nist_key.expanded_enc[03]), (0xa8b09c1a93d194cd, 0xbe49846eb75d5b9a));
|
||||
assert_eq!(unpack_m128(nist_key.expanded_enc[04]), (0xd59aecb85bf3c917, 0xfee94248de8ebe96));
|
||||
assert_eq!(unpack_m128(nist_key.expanded_enc[05]), (0xb5a9328a2678a647, 0x983122292f6c79b3));
|
||||
assert_eq!(unpack_m128(nist_key.expanded_enc[06]), (0x812c81addadf48ba, 0x24360af2fab8b464));
|
||||
assert_eq!(unpack_m128(nist_key.expanded_enc[07]), (0x98c5bfc9bebd198e, 0x268c3ba709e04214));
|
||||
assert_eq!(unpack_m128(nist_key.expanded_enc[08]), (0x68007bacb2df3316, 0x96e939e46c518d80));
|
||||
assert_eq!(unpack_m128(nist_key.expanded_enc[09]), (0xc814e20476a9fb8a, 0x5025c02d59c58239));
|
||||
assert_eq!(unpack_m128(nist_key.expanded_enc[10]), (0xde1369676ccc5a71, 0xfa2563959674ee15));
|
||||
assert_eq!(unpack_m128(nist_key.expanded_enc[11]), (0x5886ca5d2e2f31d7, 0x7e0af1fa27cf73c3));
|
||||
assert_eq!(unpack_m128(nist_key.expanded_enc[12]), (0x749c47ab18501dda, 0xe2757e4f7401905a));
|
||||
assert_eq!(unpack_m128(nist_key.expanded_enc[13]), (0xcafaaae3e4d59b34, 0x9adf6acebd10190d));
|
||||
assert_eq!(unpack_m128(nist_key.expanded_enc[14]), (0xfe4890d1e6188d0b, 0x046df344706c631e));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fips197_example() {
|
||||
let input = [0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff];
|
||||
let key = [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
|
||||
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f];
|
||||
let aeskey = AES256::new(&key);
|
||||
let cipher = aeskey.encrypt(&input);
|
||||
assert_eq!(cipher, vec![0x8e,0xa2,0xb7,0xca,0x51,0x67,0x45,0xbf,
|
||||
0xea,0xfc,0x49,0x90,0x4b,0x49,0x60,0x89]);
|
||||
assert_eq!(input.to_vec(), aeskey.decrypt(&cipher));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nist_test_vectors() {
|
||||
let fname = "testdata/aes/aes256.test";
|
||||
run_test(fname.to_string(), 3, |case| {
|
||||
let (negk, kbytes) = case.get("k").unwrap();
|
||||
let (negp, pbytes) = case.get("p").unwrap();
|
||||
let (negc, cbytes) = case.get("c").unwrap();
|
||||
|
||||
assert!(!negk && !negp && !negc);
|
||||
let key = AES256::new(&kbytes);
|
||||
let cipher = key.encrypt(&pbytes);
|
||||
let plain = key.decrypt(&cipher);
|
||||
assert_eq!(&cipher, cbytes);
|
||||
assert_eq!(&plain, pbytes);
|
||||
});
|
||||
}
|
||||
}
|
||||
205
src/aes/mod.rs
Normal file
205
src/aes/mod.rs
Normal file
@@ -0,0 +1,205 @@
|
||||
#[cfg(all(any(target_arch="x86", target_arch="x86_64"),
|
||||
target_feature = "aes"))]
|
||||
pub mod aesni;
|
||||
pub mod portable;
|
||||
|
||||
#[cfg(all(target_arch="x86", target_feature = "aes"))]
|
||||
use std::arch::x86::__cpuid;
|
||||
#[cfg(all(target_arch="x86_64", target_feature = "aes"))]
|
||||
use std::arch::x86_64::__cpuid;
|
||||
|
||||
/// This is the type to use for an AES128 key. The new() routine will select
|
||||
/// an accelerated routine, at runtime, if one is available. Otherwise, it
|
||||
/// will use a slower, portable routine.
|
||||
pub enum AES128 {
|
||||
Portable(portable::AES128),
|
||||
#[cfg(all(any(target_arch="x86", target_arch="x86_64"),
|
||||
target_feature = "aes"))]
|
||||
Accelerated(aesni::AES128),
|
||||
}
|
||||
|
||||
#[cfg(all(any(target_arch="x86", target_arch="x86_64"),
|
||||
target_feature = "aes"))]
|
||||
fn test_aesni() -> bool {
|
||||
let result = unsafe { __cpuid(1) }; // 1 == processor features
|
||||
(result.edx & 0b00000010000000000000000000000000) != 0
|
||||
}
|
||||
|
||||
impl AES128 {
|
||||
/// Returns true iff this platform has an acceleration system we support.
|
||||
pub fn accelerated() -> bool {
|
||||
#[cfg(all(any(target_arch="x86", target_arch="x86_64"),
|
||||
target_feature = "aes"))]
|
||||
return test_aesni();
|
||||
#[allow(unreachable_code)]
|
||||
false
|
||||
}
|
||||
|
||||
/// Generate a new AES128 object from the given key. This routine does a
|
||||
/// dynamic check of `AES128::accelerated()` to see if it can be
|
||||
/// accelerated; this means that you'll get acceleration where you can,
|
||||
/// and a safe default where you can't.
|
||||
pub fn new(key: [u8; 16]) -> AES128 {
|
||||
#[cfg(all(any(target_arch="x86", target_arch="x86_64"),
|
||||
target_feature = "aes"))]
|
||||
return if AES128::accelerated() {
|
||||
AES128::Accelerated(aesni::AES128::new(&key))
|
||||
} else {
|
||||
AES128::Portable(portable::AES128::new(&key))
|
||||
};
|
||||
#[allow(unreachable_code)]
|
||||
AES128::Portable(portable::AES128::new(&key))
|
||||
}
|
||||
|
||||
/// Encrypt the given block. This *must* be exactly 16 bytes long.
|
||||
pub fn encrypt(&self, block: &[u8]) -> Vec<u8> {
|
||||
match self {
|
||||
AES128::Portable(ref key) => key.encrypt(block),
|
||||
#[cfg(all(any(target_arch="x86", target_arch="x86_64"),
|
||||
target_feature = "aes"))]
|
||||
AES128::Accelerated(ref key) => key.encrypt(block),
|
||||
}
|
||||
}
|
||||
|
||||
/// Decrypt the given block. This *must* be exactly 16 bytes long.
|
||||
pub fn decrypt(&self, block: &[u8]) -> Vec<u8> {
|
||||
match self {
|
||||
AES128::Portable(ref key) => key.decrypt(block),
|
||||
#[cfg(all(any(target_arch="x86", target_arch="x86_64"),
|
||||
target_feature = "aes"))]
|
||||
AES128::Accelerated(ref key) => key.decrypt(block),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This is the type to use for an AES128 key. The new() routine will select
|
||||
/// an accelerated routine, at runtime, if one is available. Otherwise, it
|
||||
/// will use a slower, portable routine.
|
||||
pub enum AES256 {
|
||||
Portable(portable::AES256),
|
||||
#[cfg(all(any(target_arch="x86", target_arch="x86_64"),
|
||||
target_feature = "aes"))]
|
||||
Accelerated(aesni::AES256),
|
||||
}
|
||||
|
||||
impl AES256 {
|
||||
/// Returns true iff this platform has an acceleration system we support.
|
||||
pub fn accelerated() -> bool {
|
||||
#[cfg(all(any(target_arch="x86", target_arch="x86_64"),
|
||||
target_feature = "aes"))]
|
||||
return test_aesni();
|
||||
#[allow(unreachable_code)]
|
||||
false
|
||||
}
|
||||
|
||||
/// Generate a new AES256 object from the given key. This routine does a
|
||||
/// dynamic check of `AES256::accelerated()` to see if it can be
|
||||
/// accelerated; this means that you'll get acceleration where you can,
|
||||
/// and a safe default where you can't.
|
||||
pub fn new(key: [u8; 32]) -> AES256 {
|
||||
#[cfg(all(any(target_arch="x86", target_arch="x86_64"),
|
||||
target_feature = "aes"))]
|
||||
return if AES256::accelerated() {
|
||||
AES256::Accelerated(aesni::AES256::new(&key))
|
||||
} else {
|
||||
AES256::Portable(portable::AES256::new(&key))
|
||||
};
|
||||
#[allow(unreachable_code)]
|
||||
AES256::Portable(portable::AES256::new(&key))
|
||||
}
|
||||
|
||||
/// Encrypt the given block. This *must* be exactly 16 bytes long.
|
||||
pub fn encrypt(&self, block: &[u8]) -> Vec<u8> {
|
||||
match self {
|
||||
AES256::Portable(ref key) => key.encrypt(block),
|
||||
#[cfg(all(any(target_arch="x86", target_arch="x86_64"),
|
||||
target_feature = "aes"))]
|
||||
AES256::Accelerated(ref key) => key.encrypt(block),
|
||||
}
|
||||
}
|
||||
|
||||
/// Decrypt the given block. This *must* be exactly 16 bytes long.
|
||||
pub fn decrypt(&self, block: &[u8]) -> Vec<u8> {
|
||||
match self {
|
||||
AES256::Portable(ref key) => key.decrypt(block),
|
||||
#[cfg(all(any(target_arch="x86", target_arch="x86_64"),
|
||||
target_feature = "aes"))]
|
||||
AES256::Accelerated(ref key) => key.decrypt(block),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(any(target_arch="x86", target_arch="x86_64"),
|
||||
target_feature = "aes",
|
||||
test))]
|
||||
mod flexible {
|
||||
use super::{AES128,AES256};
|
||||
use super::aesni;
|
||||
use super::portable;
|
||||
use super::portable::aes256::{RandomBlock,RandomKey};
|
||||
use testing::run_test;
|
||||
|
||||
quickcheck! {
|
||||
fn aes128_implementations_match(key: RandomBlock, block: RandomBlock) -> bool {
|
||||
let aesni_key = aesni::AES128::new(&key.block);
|
||||
let portable_key = portable::AES128::new(&key.block);
|
||||
let aesni_cipher = aesni_key.encrypt(&block.block);
|
||||
let portable_cipher = portable_key.encrypt(&block.block);
|
||||
aesni_cipher == portable_cipher
|
||||
}
|
||||
|
||||
fn aes256_implementations_match(key: RandomKey, block: RandomBlock) -> bool {
|
||||
let aesni_key = aesni::AES256::new(&key.key);
|
||||
let portable_key = portable::AES256::new(&key.key);
|
||||
let aesni_cipher = aesni_key.encrypt(&block.block);
|
||||
let portable_cipher = portable_key.encrypt(&block.block);
|
||||
aesni_cipher == portable_cipher
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn aes128_nist_test_vectors() {
|
||||
let fname = "testdata/aes/aes128.test";
|
||||
run_test(fname.to_string(), 3, |case| {
|
||||
let (negk, kbytes) = case.get("k").unwrap();
|
||||
let (negp, pbytes) = case.get("p").unwrap();
|
||||
let (negc, cbytes) = case.get("c").unwrap();
|
||||
|
||||
assert!(!negk && !negp && !negc);
|
||||
let keyval = [kbytes[00], kbytes[01], kbytes[02], kbytes[03],
|
||||
kbytes[04], kbytes[05], kbytes[06], kbytes[07],
|
||||
kbytes[08], kbytes[09], kbytes[10], kbytes[11],
|
||||
kbytes[12], kbytes[13], kbytes[14], kbytes[15]];
|
||||
let key = AES128::new(keyval);
|
||||
let cipher = key.encrypt(&pbytes);
|
||||
let plain = key.decrypt(&cipher);
|
||||
assert_eq!(&cipher, cbytes);
|
||||
assert_eq!(&plain, pbytes);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn aes256_nist_test_vectors() {
|
||||
let fname = "testdata/aes/aes256.test";
|
||||
run_test(fname.to_string(), 3, |case| {
|
||||
let (negk, kbytes) = case.get("k").unwrap();
|
||||
let (negp, pbytes) = case.get("p").unwrap();
|
||||
let (negc, cbytes) = case.get("c").unwrap();
|
||||
|
||||
assert!(!negk && !negp && !negc);
|
||||
let keyval = [kbytes[00], kbytes[01], kbytes[02], kbytes[03],
|
||||
kbytes[04], kbytes[05], kbytes[06], kbytes[07],
|
||||
kbytes[08], kbytes[09], kbytes[10], kbytes[11],
|
||||
kbytes[12], kbytes[13], kbytes[14], kbytes[15],
|
||||
kbytes[16], kbytes[17], kbytes[18], kbytes[19],
|
||||
kbytes[20], kbytes[21], kbytes[22], kbytes[23],
|
||||
kbytes[24], kbytes[25], kbytes[26], kbytes[27],
|
||||
kbytes[28], kbytes[29], kbytes[30], kbytes[31]];
|
||||
let key = AES256::new(keyval);
|
||||
let cipher = key.encrypt(&pbytes);
|
||||
let plain = key.decrypt(&cipher);
|
||||
assert_eq!(&cipher, cbytes);
|
||||
assert_eq!(&plain, pbytes);
|
||||
});
|
||||
}
|
||||
}
|
||||
835
src/aes/portable.rs
Normal file
835
src/aes/portable.rs
Normal file
@@ -0,0 +1,835 @@
|
||||
const RIJNDAEL_KEY_SCHEDULE: [u32; 11] = [
|
||||
0x00000000, 0x01000000, 0x02000000, 0x04000000,
|
||||
0x08000000, 0x10000000, 0x20000000, 0x40000000,
|
||||
0x80000000, 0x1b000000, 0x36000000,
|
||||
];
|
||||
|
||||
const SUB_BYTES_SBOX: [u8; 256] = [
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||||
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||||
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||||
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||||
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
|
||||
];
|
||||
|
||||
const INVSUB_BYTES_SBOX: [u8; 256] = [
|
||||
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
||||
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
||||
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
|
||||
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
|
||||
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
|
||||
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
|
||||
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
|
||||
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
|
||||
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
|
||||
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
|
||||
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
|
||||
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
|
||||
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
|
||||
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
|
||||
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
|
||||
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d,
|
||||
];
|
||||
|
||||
fn word(a: u8, b: u8, c: u8, d: u8) -> u32 {
|
||||
((a as u32) << 24) | ((b as u32) << 16) |
|
||||
((c as u32) << 08) | ((d as u32) << 00)
|
||||
}
|
||||
|
||||
fn rot_word(x: u32) -> u32 {
|
||||
x.rotate_left(8)
|
||||
}
|
||||
|
||||
fn sub_word(x: u32) -> u32 {
|
||||
(((SUB_BYTES_SBOX[((x >> 24) & 0xff) as usize]) as u32) << 24) |
|
||||
(((SUB_BYTES_SBOX[((x >> 16) & 0xff) as usize]) as u32) << 16) |
|
||||
(((SUB_BYTES_SBOX[((x >> 08) & 0xff) as usize]) as u32) << 08) |
|
||||
(((SUB_BYTES_SBOX[((x >> 00) & 0xff) as usize]) as u32) << 00)
|
||||
}
|
||||
|
||||
/**************************************************************************************************/
|
||||
/* */
|
||||
/* AES State */
|
||||
/* */
|
||||
/**************************************************************************************************/
|
||||
|
||||
struct AESState {
|
||||
state: [[u8; 4]; 4]
|
||||
}
|
||||
|
||||
macro_rules! xtime {
|
||||
($e: expr) => {{
|
||||
let base: u8 = $e;
|
||||
let dbl = base << 1;
|
||||
let high = base & 0x80;
|
||||
let xorval = if high == 0x80 { 0x1b } else { 0x00 };
|
||||
dbl ^ xorval
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! field_09 {
|
||||
($e: expr) => {{
|
||||
let base = $e;
|
||||
base ^ xtime!(xtime!(xtime!(base)))
|
||||
}}
|
||||
}
|
||||
|
||||
macro_rules! field_0b {
|
||||
($e: expr) => {{
|
||||
let base = $e;
|
||||
// 1 + 8 + 2 = 11 = 0xb
|
||||
base ^ xtime!(xtime!(xtime!(base))) ^ xtime!(base)
|
||||
}}
|
||||
}
|
||||
|
||||
macro_rules! field_0d {
|
||||
($e: expr) => {{
|
||||
let base = $e;
|
||||
// 1 + 8 + 4 = 13 = 0xd
|
||||
base ^ xtime!(xtime!(xtime!(base))) ^ xtime!(xtime!(base))
|
||||
}}
|
||||
}
|
||||
|
||||
macro_rules! field_0e {
|
||||
($e: expr) => {{
|
||||
let base = $e;
|
||||
// 2 + 8 + 4 = 14 = 0xe
|
||||
xtime!(base) ^ xtime!(xtime!(xtime!(base))) ^ xtime!(xtime!(base))
|
||||
}}
|
||||
}
|
||||
|
||||
impl AESState {
|
||||
fn new(inkey: &[u8]) -> AESState {
|
||||
assert_eq!(inkey.len(), 16);
|
||||
AESState {
|
||||
state: [[inkey[00], inkey[04], inkey[08], inkey[12]],
|
||||
[inkey[01], inkey[05], inkey[09], inkey[13]],
|
||||
[inkey[02], inkey[06], inkey[10], inkey[14]],
|
||||
[inkey[03], inkey[07], inkey[11], inkey[15]]]
|
||||
}
|
||||
}
|
||||
|
||||
// fn print_state(&self) {
|
||||
// println!("{:02x} {:02x} {:02x} {:02x}", self.state[0][0], self.state[0][1], self.state[0][2], self.state[0][3]);
|
||||
// println!("{:02x} {:02x} {:02x} {:02x}", self.state[1][0], self.state[1][1], self.state[1][2], self.state[1][3]);
|
||||
// println!("{:02x} {:02x} {:02x} {:02x}", self.state[2][0], self.state[2][1], self.state[2][2], self.state[2][3]);
|
||||
// println!("{:02x} {:02x} {:02x} {:02x}", self.state[3][0], self.state[3][1], self.state[3][2], self.state[3][3]);
|
||||
// println!("-----------");
|
||||
// }
|
||||
|
||||
fn add_round_key(&mut self, w: &[u32]) {
|
||||
assert_eq!(w.len(), 4);
|
||||
for i in 0..4 {
|
||||
self.state[0][i] ^= (w[i] >> 24) as u8;
|
||||
self.state[1][i] ^= (w[i] >> 16) as u8;
|
||||
self.state[2][i] ^= (w[i] >> 08) as u8;
|
||||
self.state[3][i] ^= (w[i] >> 00) as u8;
|
||||
}
|
||||
}
|
||||
|
||||
fn sub_bytes(&mut self) {
|
||||
for i in 0..4 {
|
||||
for j in 0..4 {
|
||||
self.state[i][j] = SUB_BYTES_SBOX[self.state[i][j] as usize];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn inv_sub_bytes(&mut self) {
|
||||
for i in 0..4 {
|
||||
for j in 0..4 {
|
||||
self.state[i][j] = INVSUB_BYTES_SBOX[self.state[i][j] as usize];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn shift_rows(&mut self) {
|
||||
let temp1 = self.state[1][0];
|
||||
self.state[1][0] = self.state[1][1];
|
||||
self.state[1][1] = self.state[1][2];
|
||||
self.state[1][2] = self.state[1][3];
|
||||
self.state[1][3] = temp1;
|
||||
let temp2a = self.state[2][0];
|
||||
let temp2b = self.state[2][1];
|
||||
self.state[2][0] = self.state[2][2];
|
||||
self.state[2][1] = self.state[2][3];
|
||||
self.state[2][2] = temp2a;
|
||||
self.state[2][3] = temp2b;
|
||||
let temp3 = self.state[3][3];
|
||||
self.state[3][3] = self.state[3][2];
|
||||
self.state[3][2] = self.state[3][1];
|
||||
self.state[3][1] = self.state[3][0];
|
||||
self.state[3][0] = temp3;
|
||||
}
|
||||
|
||||
fn inv_shift_rows(&mut self) {
|
||||
let temp1 = self.state[1][3];
|
||||
self.state[1][3] = self.state[1][2];
|
||||
self.state[1][2] = self.state[1][1];
|
||||
self.state[1][1] = self.state[1][0];
|
||||
self.state[1][0] = temp1;
|
||||
let temp2a = self.state[2][0];
|
||||
let temp2b = self.state[2][1];
|
||||
self.state[2][0] = self.state[2][2];
|
||||
self.state[2][1] = self.state[2][3];
|
||||
self.state[2][2] = temp2a;
|
||||
self.state[2][3] = temp2b;
|
||||
let temp3 = self.state[3][0];
|
||||
self.state[3][0] = self.state[3][1];
|
||||
self.state[3][1] = self.state[3][2];
|
||||
self.state[3][2] = self.state[3][3];
|
||||
self.state[3][3] = temp3;
|
||||
}
|
||||
|
||||
fn mix_columns(&mut self) {
|
||||
for c in 0..4 {
|
||||
// get the base values
|
||||
let s0c = self.state[0][c];
|
||||
let s1c = self.state[1][c];
|
||||
let s2c = self.state[2][c];
|
||||
let s3c = self.state[3][c];
|
||||
|
||||
// get the doubled values, forced to be within the field
|
||||
let d0c = xtime!(s0c);
|
||||
let d1c = xtime!(s1c);
|
||||
let d2c = xtime!(s2c);
|
||||
let d3c = xtime!(s3c);
|
||||
|
||||
self.state[0][c] = d0c ^ d1c ^ s2c ^ s3c ^ s1c;
|
||||
self.state[1][c] = s0c ^ d1c ^ d2c ^ s3c ^ s2c;
|
||||
self.state[2][c] = s0c ^ s1c ^ d2c ^ d3c ^ s3c;
|
||||
self.state[3][c] = d0c ^ s1c ^ s2c ^ d3c ^ s0c;
|
||||
}
|
||||
}
|
||||
|
||||
fn inv_mix_columns(&mut self) {
|
||||
for c in 0..4 {
|
||||
// get the base values
|
||||
let s0c = self.state[0][c];
|
||||
let s1c = self.state[1][c];
|
||||
let s2c = self.state[2][c];
|
||||
let s3c = self.state[3][c];
|
||||
|
||||
self.state[0][c] = field_0e!(s0c) ^ field_0b!(s1c) ^ field_0d!(s2c) ^ field_09!(s3c);
|
||||
self.state[1][c] = field_09!(s0c) ^ field_0e!(s1c) ^ field_0b!(s2c) ^ field_0d!(s3c);
|
||||
self.state[2][c] = field_0d!(s0c) ^ field_09!(s1c) ^ field_0e!(s2c) ^ field_0b!(s3c);
|
||||
self.state[3][c] = field_0b!(s0c) ^ field_0d!(s1c) ^ field_09!(s2c) ^ field_0e!(s3c);
|
||||
}
|
||||
}
|
||||
|
||||
fn decant(&self) -> Vec<u8> {
|
||||
vec![self.state[0][0], self.state[1][0], self.state[2][0], self.state[3][0],
|
||||
self.state[0][1], self.state[1][1], self.state[2][1], self.state[3][1],
|
||||
self.state[0][2], self.state[1][2], self.state[2][2], self.state[3][2],
|
||||
self.state[0][3], self.state[1][3], self.state[2][3], self.state[3][3],
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod state {
|
||||
use quickcheck::{Arbitrary,Gen};
|
||||
use std::fmt;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn xtime_works() {
|
||||
assert_eq!(xtime!(0x57), 0xae);
|
||||
assert_eq!(xtime!(0xae), 0x47);
|
||||
assert_eq!(xtime!(0x47), 0x8e);
|
||||
assert_eq!(xtime!(0x8e), 0x07);
|
||||
assert_eq!(xtime!(xtime!(0x57)), 0x47);
|
||||
}
|
||||
|
||||
impl PartialEq for AESState {
|
||||
fn eq(&self, other: &AESState) -> bool {
|
||||
for i in 0..4 {
|
||||
for j in 0..4 {
|
||||
if self.state[i][j] != other.state[i][j] {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for AESState {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "[{:02x} {:02x} {:02x} {:02x}", self.state[0][0], self.state[0][1], self.state[0][2], self.state[0][3])?;
|
||||
write!(f, " {:02x} {:02x} {:02x} {:02x}", self.state[1][0], self.state[1][1], self.state[1][2], self.state[1][3])?;
|
||||
write!(f, " {:02x} {:02x} {:02x} {:02x}", self.state[2][0], self.state[2][1], self.state[2][2], self.state[2][3])?;
|
||||
write!(f, " {:02x} {:02x} {:02x} {:02x}]", self.state[3][0], self.state[3][1], self.state[3][2], self.state[3][3])
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fips197_add_round_example() {
|
||||
let mut input = AESState{ state: [[0x32, 0x88, 0x31, 0xe0],
|
||||
[0x43, 0x5a, 0x31, 0x37],
|
||||
[0xf6, 0x30, 0x98, 0x07],
|
||||
[0xa8, 0x8d, 0xa2, 0x34]] };
|
||||
let key = [0x2b7e1516, 0x28aed2a6, 0xabf71588, 0x09cf4f3c];
|
||||
let output = AESState{ state: [[0x19, 0xa0, 0x9a, 0xe9],
|
||||
[0x3d, 0xf4, 0xc6, 0xf8],
|
||||
[0xe3, 0xe2, 0x8d, 0x48],
|
||||
[0xbe, 0x2b, 0x2a, 0x08]] };
|
||||
input.add_round_key(&key);
|
||||
assert_eq!(input, output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fips197_sub_bytes_example() {
|
||||
let mut input = AESState{ state: [[0x19, 0xa0, 0x9a, 0xe9],
|
||||
[0x3d, 0xf4, 0xc6, 0xf8],
|
||||
[0xe3, 0xe2, 0x8d, 0x48],
|
||||
[0xbe, 0x2b, 0x2a, 0x08]] };
|
||||
let output = AESState{ state: [[0xd4, 0xe0, 0xb8, 0x1e],
|
||||
[0x27, 0xbf, 0xb4, 0x41],
|
||||
[0x11, 0x98, 0x5d, 0x52],
|
||||
[0xae, 0xf1, 0xe5, 0x30]] };
|
||||
input.sub_bytes();
|
||||
assert_eq!(input, output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fips197_shift_rows_example() {
|
||||
let mut input = AESState{ state: [[0xd4, 0xe0, 0xb8, 0x1e],
|
||||
[0x27, 0xbf, 0xb4, 0x41],
|
||||
[0x11, 0x98, 0x5d, 0x52],
|
||||
[0xae, 0xf1, 0xe5, 0x30]] };
|
||||
let output = AESState{ state: [[0xd4, 0xe0, 0xb8, 0x1e],
|
||||
[0xbf, 0xb4, 0x41, 0x27],
|
||||
[0x5d, 0x52, 0x11, 0x98],
|
||||
[0x30, 0xae, 0xf1, 0xe5]] };
|
||||
input.shift_rows();
|
||||
assert_eq!(input, output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fips197_mix_columns_example() {
|
||||
let mut input = AESState{ state: [[0xd4, 0xe0, 0xb8, 0x1e],
|
||||
[0xbf, 0xb4, 0x41, 0x27],
|
||||
[0x5d, 0x52, 0x11, 0x98],
|
||||
[0x30, 0xae, 0xf1, 0xe5]] };
|
||||
let output = AESState{ state: [[0x04, 0xe0, 0x48, 0x28],
|
||||
[0x66, 0xcb, 0xf8, 0x06],
|
||||
[0x81, 0x19, 0xd3, 0x26],
|
||||
[0xe5, 0x9a, 0x7a, 0x4c]] };
|
||||
input.mix_columns();
|
||||
assert_eq!(input, output);
|
||||
}
|
||||
|
||||
impl Clone for AESState {
|
||||
fn clone(&self) -> AESState {
|
||||
AESState{ state: self.state.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Arbitrary for AESState {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> AESState {
|
||||
let mut base = [0; 16];
|
||||
g.fill_bytes(&mut base);
|
||||
AESState::new(&base)
|
||||
}
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn check_sub_bytes_inverse(input: AESState) -> bool {
|
||||
let mut output = input.clone();
|
||||
output.sub_bytes();
|
||||
output.inv_sub_bytes();
|
||||
input == output
|
||||
}
|
||||
|
||||
fn check_shift_rows_inverse(input: AESState) -> bool {
|
||||
let mut output = input.clone();
|
||||
output.shift_rows();
|
||||
output.inv_shift_rows();
|
||||
input == output
|
||||
}
|
||||
|
||||
fn check_mix_columns_inverse(input: AESState) -> bool {
|
||||
let mut output = input.clone();
|
||||
output.mix_columns();
|
||||
output.inv_mix_columns();
|
||||
input == output
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************************************/
|
||||
/* */
|
||||
/* AES128 Implementation */
|
||||
/* */
|
||||
/**************************************************************************************************/
|
||||
|
||||
const AES128_KEY_LENGTH: usize = 4; // Nk
|
||||
const AES128_BLOCK_SIZE: usize = 4; // Nb
|
||||
const AES128_NUM_ROUNDS: usize = 10; // Nr
|
||||
const AES128_STATE_WORDS: usize = AES128_BLOCK_SIZE * (AES128_NUM_ROUNDS + 1);
|
||||
|
||||
pub struct AES128 {
|
||||
expanded: [u32; AES128_STATE_WORDS]
|
||||
}
|
||||
|
||||
impl AES128 {
|
||||
pub fn new(base_key: &[u8]) -> AES128 {
|
||||
let mut expanded = [0; AES128_STATE_WORDS];
|
||||
let mut i = 0;
|
||||
|
||||
assert_eq!(base_key.len(), 16);
|
||||
// while (i < Nk)
|
||||
// w[i] = word(key[4*i],key[4*i+1],key[4*i+2],key[4*i+3])
|
||||
// i = i+1
|
||||
// end while
|
||||
while i < AES128_KEY_LENGTH {
|
||||
expanded[i] = word(base_key[(4*i)+0], base_key[(4*i)+1],
|
||||
base_key[(4*i)+2], base_key[(4*i)+3]);
|
||||
//println!("{:02}: expanded[{}] = {:08x}", i, i, expanded[i]);
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
// i = Nk
|
||||
assert_eq!(i, AES128_KEY_LENGTH);
|
||||
|
||||
// while (i < Nb * (Nr + 1))
|
||||
while i < AES128_BLOCK_SIZE * (AES128_NUM_ROUNDS+1) {
|
||||
// temp = w[i-1]
|
||||
let mut temp = expanded[i-1];
|
||||
//println!("{:02}: temp = {:08x}", i, temp);
|
||||
// if (i mod Nk = 0)
|
||||
// temp = sub_word(rot_word(temp)) xor Rcon[i/Nk]
|
||||
// else
|
||||
// temp = sub_word(temp)
|
||||
// end if
|
||||
if i % AES128_KEY_LENGTH == 0 {
|
||||
temp = rot_word(temp);
|
||||
//println!("{:02}: after rotword = {:08x}", i, temp);
|
||||
temp = sub_word(temp);
|
||||
//println!("{:02}: after subword = {:08x}", i, temp);
|
||||
temp ^= RIJNDAEL_KEY_SCHEDULE[i/AES128_KEY_LENGTH];
|
||||
//println!("{:02}: after rcon xor = {:08x}", i, temp);
|
||||
}
|
||||
// w[i] = w[i-Nk] ^ temp;
|
||||
//println!("{:02}: w[{}-{}] = {:08x}", i, i, AES128_KEY_LENGTH, expanded[i-AES128_KEY_LENGTH]);
|
||||
expanded[i] = expanded[i-AES128_KEY_LENGTH] ^ temp;
|
||||
//println!("{:02}: expanded[{:02}] = {:08x}", i, i, expanded[i]);
|
||||
// i = i + 1
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
AES128{ expanded }
|
||||
}
|
||||
|
||||
pub fn encrypt(&self, block: &[u8]) -> Vec<u8> {
|
||||
let mut state = AESState::new(block);
|
||||
|
||||
state.add_round_key(&self.expanded[0..4]);
|
||||
for round in 1..AES128_NUM_ROUNDS {
|
||||
state.sub_bytes();
|
||||
state.shift_rows();
|
||||
state.mix_columns();
|
||||
let start = round * AES128_BLOCK_SIZE;
|
||||
let end = (round + 1) * AES128_BLOCK_SIZE;
|
||||
state.add_round_key(&self.expanded[start..end]);
|
||||
}
|
||||
|
||||
state.sub_bytes();
|
||||
state.shift_rows();
|
||||
let start = AES128_NUM_ROUNDS * AES128_BLOCK_SIZE;
|
||||
state.add_round_key(&self.expanded[start..]);
|
||||
|
||||
state.decant()
|
||||
}
|
||||
|
||||
pub fn decrypt(&self, block: &[u8]) -> Vec<u8> {
|
||||
let mut state = AESState::new(block);
|
||||
|
||||
let last_chunk_start = AES128_NUM_ROUNDS * AES128_BLOCK_SIZE;
|
||||
state.add_round_key(&self.expanded[last_chunk_start..]);
|
||||
|
||||
let mut round = AES128_NUM_ROUNDS - 1;
|
||||
while round > 0 {
|
||||
state.inv_shift_rows();
|
||||
state.inv_sub_bytes();
|
||||
let start = round * AES128_BLOCK_SIZE;
|
||||
let end = start + AES128_BLOCK_SIZE;
|
||||
state.add_round_key(&self.expanded[start..end]);
|
||||
state.inv_mix_columns();
|
||||
round -= 1;
|
||||
}
|
||||
state.inv_shift_rows();
|
||||
state.inv_sub_bytes();
|
||||
state.add_round_key(&self.expanded[0..4]);
|
||||
|
||||
state.decant()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod aes128 {
|
||||
use super::*;
|
||||
use super::aes256::RandomBlock;
|
||||
use testing::run_test;
|
||||
|
||||
#[test]
|
||||
fn fips197_key_expansion_example() {
|
||||
let cipher_key = [0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6,0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c];
|
||||
let expanded = AES128::new(&cipher_key);
|
||||
assert_eq!(expanded.expanded[00], 0x2b7e1516);
|
||||
assert_eq!(expanded.expanded[01], 0x28aed2a6);
|
||||
assert_eq!(expanded.expanded[02], 0xabf71588);
|
||||
assert_eq!(expanded.expanded[03], 0x09cf4f3c);
|
||||
assert_eq!(expanded.expanded[04], 0xa0fafe17);
|
||||
assert_eq!(expanded.expanded[05], 0x88542cb1);
|
||||
assert_eq!(expanded.expanded[06], 0x23a33939);
|
||||
assert_eq!(expanded.expanded[07], 0x2a6c7605);
|
||||
assert_eq!(expanded.expanded[08], 0xf2c295f2);
|
||||
assert_eq!(expanded.expanded[09], 0x7a96b943);
|
||||
assert_eq!(expanded.expanded[10], 0x5935807a);
|
||||
assert_eq!(expanded.expanded[11], 0x7359f67f);
|
||||
assert_eq!(expanded.expanded[12], 0x3d80477d);
|
||||
assert_eq!(expanded.expanded[13], 0x4716fe3e);
|
||||
assert_eq!(expanded.expanded[14], 0x1e237e44);
|
||||
assert_eq!(expanded.expanded[15], 0x6d7a883b);
|
||||
assert_eq!(expanded.expanded[16], 0xef44a541);
|
||||
assert_eq!(expanded.expanded[17], 0xa8525b7f);
|
||||
assert_eq!(expanded.expanded[18], 0xb671253b);
|
||||
assert_eq!(expanded.expanded[19], 0xdb0bad00);
|
||||
assert_eq!(expanded.expanded[20], 0xd4d1c6f8);
|
||||
assert_eq!(expanded.expanded[21], 0x7c839d87);
|
||||
assert_eq!(expanded.expanded[22], 0xcaf2b8bc);
|
||||
assert_eq!(expanded.expanded[23], 0x11f915bc);
|
||||
assert_eq!(expanded.expanded[24], 0x6d88a37a);
|
||||
assert_eq!(expanded.expanded[25], 0x110b3efd);
|
||||
assert_eq!(expanded.expanded[26], 0xdbf98641);
|
||||
assert_eq!(expanded.expanded[27], 0xca0093fd);
|
||||
assert_eq!(expanded.expanded[28], 0x4e54f70e);
|
||||
assert_eq!(expanded.expanded[29], 0x5f5fc9f3);
|
||||
assert_eq!(expanded.expanded[30], 0x84a64fb2);
|
||||
assert_eq!(expanded.expanded[31], 0x4ea6dc4f);
|
||||
assert_eq!(expanded.expanded[32], 0xead27321);
|
||||
assert_eq!(expanded.expanded[33], 0xb58dbad2);
|
||||
assert_eq!(expanded.expanded[34], 0x312bf560);
|
||||
assert_eq!(expanded.expanded[35], 0x7f8d292f);
|
||||
assert_eq!(expanded.expanded[36], 0xac7766f3);
|
||||
assert_eq!(expanded.expanded[37], 0x19fadc21);
|
||||
assert_eq!(expanded.expanded[38], 0x28d12941);
|
||||
assert_eq!(expanded.expanded[39], 0x575c006e);
|
||||
assert_eq!(expanded.expanded[40], 0xd014f9a8);
|
||||
assert_eq!(expanded.expanded[41], 0xc9ee2589);
|
||||
assert_eq!(expanded.expanded[42], 0xe13f0cc8);
|
||||
assert_eq!(expanded.expanded[43], 0xb6630ca6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fips197_encrypt_examples() {
|
||||
let input1 = [0x32,0x43,0xf6,0xa8,0x88,0x5a,0x30,0x8d,0x31,0x31,0x98,0xa2,0xe0,0x37,0x07,0x34];
|
||||
let cipher_key1 = [0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6,0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c];
|
||||
let expanded1 = AES128::new(&cipher_key1);
|
||||
let ciphertext1 = expanded1.encrypt(&input1);
|
||||
assert_eq!(ciphertext1, vec![0x39,0x25,0x84,0x1d,0x02,0xdc,0x09,0xfb,
|
||||
0xdc,0x11,0x85,0x97,0x19,0x6a,0x0b,0x32]);
|
||||
assert_eq!(input1.to_vec(), expanded1.decrypt(&ciphertext1));
|
||||
//
|
||||
let input2 = [0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff];
|
||||
let cipher_key2 = [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f];
|
||||
let expanded2 = AES128::new(&cipher_key2);
|
||||
let ciphertext2 = expanded2.encrypt(&input2);
|
||||
assert_eq!(ciphertext2, vec![0x69,0xc4,0xe0,0xd8,0x6a,0x7b,0x04,0x30,
|
||||
0xd8,0xcd,0xb7,0x80,0x70,0xb4,0xc5,0x5a]);
|
||||
assert_eq!(input2.to_vec(), expanded2.decrypt(&ciphertext2));
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn encrypt_decrypt_is_identity(key: RandomBlock, block: RandomBlock) -> bool {
|
||||
let key = AES128::new(&key.block);
|
||||
let cipher = key.encrypt(&block.block);
|
||||
let block2 = key.decrypt(&cipher);
|
||||
block2 == block.block.to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nist_test_vectors() {
|
||||
let fname = "testdata/aes/aes128.test";
|
||||
run_test(fname.to_string(), 3, |case| {
|
||||
let (negk, kbytes) = case.get("k").unwrap();
|
||||
let (negp, pbytes) = case.get("p").unwrap();
|
||||
let (negc, cbytes) = case.get("c").unwrap();
|
||||
|
||||
assert!(!negk && !negp && !negc);
|
||||
let key = AES128::new(&kbytes);
|
||||
let cipher = key.encrypt(&pbytes);
|
||||
let plain = key.decrypt(&cipher);
|
||||
assert_eq!(&cipher, cbytes);
|
||||
assert_eq!(&plain, pbytes);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************************************/
|
||||
/* */
|
||||
/* AES256 Implementation */
|
||||
/* */
|
||||
/**************************************************************************************************/
|
||||
|
||||
const AES256_KEY_LENGTH: usize = 8; // Nk
|
||||
const AES256_BLOCK_SIZE: usize = 4; // Nb
|
||||
const AES256_NUM_ROUNDS: usize = 14; // Nr
|
||||
const AES256_STATE_WORDS: usize = AES256_BLOCK_SIZE * (AES256_NUM_ROUNDS + 1);
|
||||
|
||||
pub struct AES256 {
|
||||
expanded: [u32; AES256_STATE_WORDS]
|
||||
}
|
||||
|
||||
impl AES256 {
|
||||
pub fn new(base_key: &[u8]) -> AES256 {
|
||||
let mut expanded = [0; AES256_STATE_WORDS];
|
||||
let mut i = 0;
|
||||
|
||||
assert_eq!(base_key.len(), 32);
|
||||
// while (i < Nk)
|
||||
// w[i] = word(key[4*i],key[4*i+1],key[4*i+2],key[4*i+3])
|
||||
// i = i+1
|
||||
// end while
|
||||
while i < AES256_KEY_LENGTH {
|
||||
expanded[i] = word(base_key[(4*i)+0], base_key[(4*i)+1],
|
||||
base_key[(4*i)+2], base_key[(4*i)+3]);
|
||||
//println!("{:02}: expanded[{}] = {:08x}", i, i, expanded[i]);
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
// i = Nk
|
||||
assert_eq!(i, AES256_KEY_LENGTH);
|
||||
|
||||
// while (i < Nb * (Nr + 1))
|
||||
while i < AES256_BLOCK_SIZE * (AES256_NUM_ROUNDS+1) {
|
||||
// temp = w[i-1]
|
||||
let mut temp = expanded[i-1];
|
||||
//println!("{:02}: temp = {:08x}", i, temp);
|
||||
// if (i mod Nk = 0)
|
||||
// temp = sub_word(rot_word(temp)) xor Rcon[i/Nk]
|
||||
// else
|
||||
// temp = sub_word(temp)
|
||||
// end if
|
||||
if i % AES256_KEY_LENGTH == 0 {
|
||||
temp = rot_word(temp);
|
||||
//println!("{:02}: after rotword = {:08x}", i, temp);
|
||||
temp = sub_word(temp);
|
||||
//println!("{:02}: after subword = {:08x}", i, temp);
|
||||
temp ^= RIJNDAEL_KEY_SCHEDULE[i/AES256_KEY_LENGTH];
|
||||
//println!("{:02}: after rcon xor = {:08x}", i, temp);
|
||||
} else if i % 4 == 0 {
|
||||
temp = sub_word(temp);
|
||||
//println!("{:02}: after subword' = {:08x}", i, temp);
|
||||
}
|
||||
// w[i] = w[i-Nk] ^ temp;
|
||||
//println!("{:02}: w[{}-{}] = {:08x}", i, i, AES256_KEY_LENGTH, expanded[i-AES256_KEY_LENGTH]);
|
||||
expanded[i] = expanded[i-AES256_KEY_LENGTH] ^ temp;
|
||||
//println!("{:02}: expanded[{:02}] = {:08x}", i, i, expanded[i]);
|
||||
// i = i + 1
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
AES256{ expanded }
|
||||
}
|
||||
|
||||
pub fn encrypt(&self, block: &[u8]) -> Vec<u8> {
|
||||
let mut state = AESState::new(block);
|
||||
|
||||
assert_eq!(block.len(), 16);
|
||||
state.add_round_key(&self.expanded[0..4]);
|
||||
for round in 1..AES256_NUM_ROUNDS {
|
||||
state.sub_bytes();
|
||||
state.shift_rows();
|
||||
state.mix_columns();
|
||||
let start = round * AES256_BLOCK_SIZE;
|
||||
let end = (round + 1) * AES256_BLOCK_SIZE;
|
||||
state.add_round_key(&self.expanded[start..end]);
|
||||
}
|
||||
|
||||
state.sub_bytes();
|
||||
state.shift_rows();
|
||||
let start = AES256_NUM_ROUNDS * AES256_BLOCK_SIZE;
|
||||
state.add_round_key(&self.expanded[start..]);
|
||||
|
||||
state.decant()
|
||||
}
|
||||
|
||||
pub fn decrypt(&self, block: &[u8]) -> Vec<u8> {
|
||||
let mut state = AESState::new(block);
|
||||
|
||||
let last_chunk_start = AES256_NUM_ROUNDS * AES256_BLOCK_SIZE;
|
||||
state.add_round_key(&self.expanded[last_chunk_start..]);
|
||||
|
||||
let mut round = AES256_NUM_ROUNDS - 1;
|
||||
while round > 0 {
|
||||
state.inv_shift_rows();
|
||||
state.inv_sub_bytes();
|
||||
let start = round * AES256_BLOCK_SIZE;
|
||||
let end = start + AES256_BLOCK_SIZE;
|
||||
state.add_round_key(&self.expanded[start..end]);
|
||||
state.inv_mix_columns();
|
||||
round -= 1;
|
||||
}
|
||||
state.inv_shift_rows();
|
||||
state.inv_sub_bytes();
|
||||
state.add_round_key(&self.expanded[0..4]);
|
||||
|
||||
state.decant()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod aes256 {
|
||||
use quickcheck::{Arbitrary,Gen};
|
||||
use super::*;
|
||||
use testing::run_test;
|
||||
|
||||
#[test]
|
||||
fn fips197_key_expansion_example() {
|
||||
let cipher_key = [0x60,0x3d,0xeb,0x10,0x15,0xca,0x71,0xbe,
|
||||
0x2b,0x73,0xae,0xf0,0x85,0x7d,0x77,0x81,
|
||||
0x1f,0x35,0x2c,0x07,0x3b,0x61,0x08,0xd7,
|
||||
0x2d,0x98,0x10,0xa3,0x09,0x14,0xdf,0xf4];
|
||||
let expanded = AES256::new(&cipher_key);
|
||||
assert_eq!(expanded.expanded[00], 0x603deb10);
|
||||
assert_eq!(expanded.expanded[01], 0x15ca71be);
|
||||
assert_eq!(expanded.expanded[02], 0x2b73aef0);
|
||||
assert_eq!(expanded.expanded[03], 0x857d7781);
|
||||
assert_eq!(expanded.expanded[04], 0x1f352c07);
|
||||
assert_eq!(expanded.expanded[05], 0x3b6108d7);
|
||||
assert_eq!(expanded.expanded[06], 0x2d9810a3);
|
||||
assert_eq!(expanded.expanded[07], 0x0914dff4);
|
||||
assert_eq!(expanded.expanded[08], 0x9ba35411);
|
||||
assert_eq!(expanded.expanded[09], 0x8e6925af);
|
||||
assert_eq!(expanded.expanded[10], 0xa51a8b5f);
|
||||
assert_eq!(expanded.expanded[11], 0x2067fcde);
|
||||
assert_eq!(expanded.expanded[12], 0xa8b09c1a);
|
||||
assert_eq!(expanded.expanded[13], 0x93d194cd);
|
||||
assert_eq!(expanded.expanded[14], 0xbe49846e);
|
||||
assert_eq!(expanded.expanded[15], 0xb75d5b9a);
|
||||
assert_eq!(expanded.expanded[16], 0xd59aecb8);
|
||||
assert_eq!(expanded.expanded[17], 0x5bf3c917);
|
||||
assert_eq!(expanded.expanded[18], 0xfee94248);
|
||||
assert_eq!(expanded.expanded[19], 0xde8ebe96);
|
||||
assert_eq!(expanded.expanded[20], 0xb5a9328a);
|
||||
assert_eq!(expanded.expanded[21], 0x2678a647);
|
||||
assert_eq!(expanded.expanded[22], 0x98312229);
|
||||
assert_eq!(expanded.expanded[23], 0x2f6c79b3);
|
||||
assert_eq!(expanded.expanded[24], 0x812c81ad);
|
||||
assert_eq!(expanded.expanded[25], 0xdadf48ba);
|
||||
assert_eq!(expanded.expanded[26], 0x24360af2);
|
||||
assert_eq!(expanded.expanded[27], 0xfab8b464);
|
||||
assert_eq!(expanded.expanded[28], 0x98c5bfc9);
|
||||
assert_eq!(expanded.expanded[29], 0xbebd198e);
|
||||
assert_eq!(expanded.expanded[30], 0x268c3ba7);
|
||||
assert_eq!(expanded.expanded[31], 0x09e04214);
|
||||
assert_eq!(expanded.expanded[32], 0x68007bac);
|
||||
assert_eq!(expanded.expanded[33], 0xb2df3316);
|
||||
assert_eq!(expanded.expanded[34], 0x96e939e4);
|
||||
assert_eq!(expanded.expanded[35], 0x6c518d80);
|
||||
assert_eq!(expanded.expanded[36], 0xc814e204);
|
||||
assert_eq!(expanded.expanded[37], 0x76a9fb8a);
|
||||
assert_eq!(expanded.expanded[38], 0x5025c02d);
|
||||
assert_eq!(expanded.expanded[39], 0x59c58239);
|
||||
assert_eq!(expanded.expanded[40], 0xde136967);
|
||||
assert_eq!(expanded.expanded[41], 0x6ccc5a71);
|
||||
assert_eq!(expanded.expanded[42], 0xfa256395);
|
||||
assert_eq!(expanded.expanded[43], 0x9674ee15);
|
||||
assert_eq!(expanded.expanded[44], 0x5886ca5d);
|
||||
assert_eq!(expanded.expanded[45], 0x2e2f31d7);
|
||||
assert_eq!(expanded.expanded[46], 0x7e0af1fa);
|
||||
assert_eq!(expanded.expanded[47], 0x27cf73c3);
|
||||
assert_eq!(expanded.expanded[48], 0x749c47ab);
|
||||
assert_eq!(expanded.expanded[49], 0x18501dda);
|
||||
assert_eq!(expanded.expanded[50], 0xe2757e4f);
|
||||
assert_eq!(expanded.expanded[51], 0x7401905a);
|
||||
assert_eq!(expanded.expanded[52], 0xcafaaae3);
|
||||
assert_eq!(expanded.expanded[53], 0xe4d59b34);
|
||||
assert_eq!(expanded.expanded[54], 0x9adf6ace);
|
||||
assert_eq!(expanded.expanded[55], 0xbd10190d);
|
||||
assert_eq!(expanded.expanded[56], 0xfe4890d1);
|
||||
assert_eq!(expanded.expanded[57], 0xe6188d0b);
|
||||
assert_eq!(expanded.expanded[58], 0x046df344);
|
||||
assert_eq!(expanded.expanded[59], 0x706c631e);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fips197_example() {
|
||||
let input = [0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff];
|
||||
let key = [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
|
||||
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f];
|
||||
let aeskey = AES256::new(&key);
|
||||
let cipher = aeskey.encrypt(&input);
|
||||
assert_eq!(cipher, vec![0x8e,0xa2,0xb7,0xca,0x51,0x67,0x45,0xbf,
|
||||
0xea,0xfc,0x49,0x90,0x4b,0x49,0x60,0x89]);
|
||||
assert_eq!(input.to_vec(), aeskey.decrypt(&cipher));
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug)]
|
||||
pub(crate) struct RandomKey {
|
||||
pub(crate) key: [u8; 32]
|
||||
}
|
||||
|
||||
impl Arbitrary for RandomKey {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> RandomKey {
|
||||
let mut res = RandomKey{ key: [0; 32] };
|
||||
g.fill_bytes(&mut res.key);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug)]
|
||||
pub(crate) struct RandomBlock {
|
||||
pub(crate) block: [u8; 16]
|
||||
}
|
||||
|
||||
impl Arbitrary for RandomBlock {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> RandomBlock {
|
||||
let mut res = RandomBlock{ block: [0; 16] };
|
||||
g.fill_bytes(&mut res.block);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn encrypt_decrypt_is_identity(key: RandomKey, block: RandomBlock) -> bool {
|
||||
let key = AES256::new(&key.key);
|
||||
let cipher = key.encrypt(&block.block);
|
||||
let block2 = key.decrypt(&cipher);
|
||||
block2 == block.block.to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nist_test_vectors() {
|
||||
let fname = "testdata/aes/aes256.test";
|
||||
run_test(fname.to_string(), 3, |case| {
|
||||
let (negk, kbytes) = case.get("k").unwrap();
|
||||
let (negp, pbytes) = case.get("p").unwrap();
|
||||
let (negc, cbytes) = case.get("c").unwrap();
|
||||
|
||||
assert!(!negk && !negp && !negc);
|
||||
let key = AES256::new(&kbytes);
|
||||
let cipher = key.encrypt(&pbytes);
|
||||
let plain = key.decrypt(&cipher);
|
||||
assert_eq!(&cipher, cbytes);
|
||||
assert_eq!(&plain, pbytes);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ extern crate rand;
|
||||
#[macro_use]
|
||||
extern crate simple_asn1;
|
||||
|
||||
/// The `aes` module provides bare-bones AES support.
|
||||
pub mod aes;
|
||||
/// The `rsa` module provides bare-bones support for RSA signing, verification,
|
||||
/// encryption, decryption, and key generation.
|
||||
pub mod rsa;
|
||||
|
||||
1704
testdata/aes/aes128.test
vendored
Normal file
1704
testdata/aes/aes128.test
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2430
testdata/aes/aes256.test
vendored
Normal file
2430
testdata/aes/aes256.test
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user