1use aes::KeySize;
8use aes::KeySize::{KeySize128, KeySize192, KeySize256};
9use symmetriccipher::{BlockEncryptor, BlockDecryptor};
10use util::supports_aesni;
11
12#[derive(Copy)]
13pub struct AesNiEncryptor {
14 rounds: u8,
15 round_keys: [u8; 240]
16}
17
18impl Clone for AesNiEncryptor { fn clone(&self) -> AesNiEncryptor { *self } }
19
20#[derive(Copy)]
21pub struct AesNiDecryptor {
22 rounds: u8,
23 round_keys: [u8; 240]
24}
25
26impl Clone for AesNiDecryptor { fn clone(&self) -> AesNiDecryptor { *self } }
27
28type RoundSetupInfo = (u8, fn(&[u8], KeyType, &mut [u8]));
30
31impl AesNiEncryptor {
32 pub fn new(key_size: KeySize, key: &[u8]) -> AesNiEncryptor {
33 if !supports_aesni() {
34 panic!("AES-NI not supported on this architecture. If you are \
35 using the MSVC toolchain, this is because the AES-NI method's \
36 have not been ported, yet");
37 }
38 let (rounds, setup_function): RoundSetupInfo = match key_size {
39 KeySize128 => (10, setup_working_key_aesni_128),
40 KeySize192 => (12, setup_working_key_aesni_192),
41 KeySize256 => (14, setup_working_key_aesni_256)
42 };
43 let mut e = AesNiEncryptor {
44 rounds: rounds,
45 round_keys: [0u8; 240]
46 };
47 setup_function(key, KeyType::Encryption, &mut e.round_keys[0..size(e.rounds)]);
48 e
49 }
50}
51
52impl AesNiDecryptor {
53 pub fn new(key_size: KeySize, key: &[u8]) -> AesNiDecryptor {
54 if !supports_aesni() {
55 panic!("AES-NI not supported on this architecture. If you are \
56 using the MSVC toolchain, this is because the AES-NI method's \
57 have not been ported, yet");
58 }
59 let (rounds, setup_function): RoundSetupInfo = match key_size {
60 KeySize128 => (10, setup_working_key_aesni_128),
61 KeySize192 => (12, setup_working_key_aesni_192),
62 KeySize256 => (14, setup_working_key_aesni_256)
63 };
64 let mut d = AesNiDecryptor {
65 rounds: rounds,
66 round_keys: [0u8; 240]
67 };
68 setup_function(key, KeyType::Decryption, &mut d.round_keys[0..size(d.rounds)]);
69 d
70 }
71
72}
73
74impl BlockEncryptor for AesNiEncryptor {
75 fn block_size(&self) -> usize { 16 }
76 fn encrypt_block(&self, input: &[u8], output: &mut [u8]) {
77 encrypt_block_aesni(self.rounds, input, &self.round_keys[0..size(self.rounds)], output);
78 }
79}
80
81impl BlockDecryptor for AesNiDecryptor {
82 fn block_size(&self) -> usize { 16 }
83 fn decrypt_block(&self, input: &[u8], output: &mut [u8]) {
84 decrypt_block_aesni(self.rounds, input, &self.round_keys[0..size(self.rounds)], output);
85 }
86}
87
88enum KeyType {
89 Encryption,
90 Decryption
91}
92
93#[inline(always)]
94fn size(rounds: u8) -> usize { 16 * ((rounds as usize) + 1) }
95
96extern {
97 fn rust_crypto_aesni_aesimc(round_keys: *mut u8);
98 fn rust_crypto_aesni_setup_working_key_128(key: *const u8, round_key: *mut u8);
99 fn rust_crypto_aesni_setup_working_key_192(key: *const u8, round_key: *mut u8);
100 fn rust_crypto_aesni_setup_working_key_256(key: *const u8, round_key: *mut u8);
101 fn rust_crypto_aesni_encrypt_block(
102 rounds: u8,
103 input: *const u8,
104 round_keys: *const u8,
105 output: *mut u8);
106 fn rust_crypto_aesni_decrypt_block(
107 rounds: u8,
108 input: *const u8,
109 round_keys: *const u8,
110 output: *mut u8);
111}
112
113fn setup_working_key_aesni_128(key: &[u8], key_type: KeyType, round_key: &mut [u8]) {
114 unsafe {
115 rust_crypto_aesni_setup_working_key_128(key.as_ptr(), round_key.as_mut_ptr());
116
117 match key_type {
118 KeyType::Decryption => {
119 for i in 1..10 {
121 rust_crypto_aesni_aesimc(round_key.get_unchecked_mut(16 * i));
122 }
123 }
124 KeyType::Encryption => { }
125 }
126 }
127}
128
129fn setup_working_key_aesni_192(key: &[u8], key_type: KeyType, round_key: &mut [u8]) {
130 unsafe {
131 rust_crypto_aesni_setup_working_key_192(key.as_ptr(), round_key.as_mut_ptr());
132
133 match key_type {
134 KeyType::Decryption => {
135 for i in 1..12 {
137 rust_crypto_aesni_aesimc(round_key.get_unchecked_mut(16 * i));
138 }
139 }
140 KeyType::Encryption => { }
141 }
142 }
143}
144
145fn setup_working_key_aesni_256(key: &[u8], key_type: KeyType, round_key: &mut [u8]) {
146 unsafe {
147 rust_crypto_aesni_setup_working_key_256(key.as_ptr(), round_key.as_mut_ptr());
148
149 match key_type {
150 KeyType::Decryption => {
151 for i in 1..14 {
153 rust_crypto_aesni_aesimc(round_key.get_unchecked_mut(16 * i));
154 }
155 }
156 KeyType::Encryption => { }
157 }
158 }
159}
160
161fn encrypt_block_aesni(rounds: u8, input: &[u8], round_keys: &[u8], output: &mut [u8]) {
162 unsafe {
163 rust_crypto_aesni_encrypt_block(
164 rounds,
165 input.as_ptr(),
166 round_keys.as_ptr(),
167 output.as_mut_ptr());
168 }
169}
170
171fn decrypt_block_aesni(rounds: u8, input: &[u8], round_keys: &[u8], output: &mut [u8]) {
172 unsafe {
173 rust_crypto_aesni_decrypt_block(
174 rounds as u8,
175 input.as_ptr(),
176 round_keys.get_unchecked(round_keys.len() - 16),
177 output.as_mut_ptr());
178 }
179}