1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
use block_cipher_trait::generic_array::GenericArray;
use block_cipher_trait::BlockCipher;
use once_cell::sync::Lazy;
static USE_AES_NI: Lazy<bool> =
Lazy::new(|| is_x86_feature_detected!("aes") && is_x86_feature_detected!("sse2"));
macro_rules! do_encrypt {
( $root:ident($plaintext:expr, $key:expr, $iv:expr) ) => {{
assert!($plaintext.len() % 16 == 0);
let mut ciphertext = Vec::with_capacity($plaintext.len());
let key = GenericArray::from_slice($key);
let cipher = $root::Aes256::new(&key);
let mut iv = $iv.clone();
let (iv1, iv2) = iv.split_at_mut(16);
for plaintext_block in $plaintext.chunks(16) {
let mut xored_block = [0; 16];
xored_block
.iter_mut()
.zip(plaintext_block.iter().zip(iv1.iter()))
.for_each(|(x, (a, b))| *x = a ^ b);
let mut ciphertext_block = GenericArray::clone_from_slice(&xored_block);
cipher.encrypt_block(&mut ciphertext_block);
ciphertext_block
.iter_mut()
.zip(iv2.iter())
.for_each(|(x, a)| *x ^= a);
ciphertext.extend(ciphertext_block.iter());
iv1.clone_from_slice(&ciphertext_block);
iv2.clone_from_slice(plaintext_block);
}
ciphertext
}};
}
macro_rules! do_decrypt {
( $root:ident($ciphertext:expr, $key:expr, $iv:expr) ) => {{
assert!($ciphertext.len() % 16 == 0);
let mut plaintext = Vec::with_capacity($ciphertext.len());
let key = GenericArray::from_slice($key);
let cipher = $root::Aes256::new(&key);
let mut iv = $iv.clone();
let (iv1, iv2) = iv.split_at_mut(16);
for ciphertext_block in $ciphertext.chunks(16) {
let mut xored_block = [0; 16];
xored_block
.iter_mut()
.zip(ciphertext_block.iter().zip(iv2.iter()))
.for_each(|(x, (a, b))| *x = a ^ b);
let mut plaintext_block = GenericArray::clone_from_slice(&xored_block);
cipher.decrypt_block(&mut plaintext_block);
plaintext_block
.iter_mut()
.zip(iv1.iter())
.for_each(|(x, a)| *x ^= a);
plaintext.extend(plaintext_block.iter());
iv1.clone_from_slice(ciphertext_block);
iv2.clone_from_slice(&plaintext_block);
}
plaintext
}};
}
pub fn ige_encrypt(plaintext: &[u8], key: &[u8; 32], iv: &[u8; 32]) -> Vec<u8> {
if *USE_AES_NI {
do_encrypt!(aesni(plaintext, key, iv))
} else {
do_encrypt!(aes_soft(plaintext, key, iv))
}
}
pub fn ige_decrypt(ciphertext: &[u8], key: &[u8; 32], iv: &[u8; 32]) -> Vec<u8> {
if *USE_AES_NI {
do_decrypt!(aesni(ciphertext, key, iv))
} else {
do_decrypt!(aes_soft(ciphertext, key, iv))
}
}