Skip to content

Commit 1e3b6bd

Browse files
committed
ucryptolib: Add support for AES when no SSL library is present.
1 parent cac4985 commit 1e3b6bd

File tree

5 files changed

+441
-2
lines changed

5 files changed

+441
-2
lines changed

extmod/crypto-algorithms/aes.c

Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
/*
2+
* A small, lightweight AES implmentation suitable for microcontrollers.
3+
*
4+
* SPDX-License-Identifier: MIT
5+
* The MIT License (MIT)
6+
*
7+
* Copyright (c) 2021 Nicko van Someren
8+
*
9+
* Permission is hereby granted, free of charge, to any person obtaining a copy
10+
* of this software and associated documentation files (the "Software"), to deal
11+
* in the Software without restriction, including without limitation the rights
12+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
* copies of the Software, and to permit persons to whom the Software is
14+
* furnished to do so, subject to the following conditions:
15+
*
16+
* The above copyright notice and this permission notice shall be included in
17+
* all copies or substantial portions of the Software.
18+
*
19+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
* THE SOFTWARE.
26+
*/
27+
28+
#include <stdlib.h>
29+
#include <stddef.h>
30+
#include <string.h>
31+
32+
#include "aes.h"
33+
34+
#define ROUNDS_FOR_KEYLEN(l) \
35+
((l == 16) ? AES_128_ROUNDS : \
36+
((l == 24) ? AES_192_ROUNDS : \
37+
((l == 32) ? AES_256_ROUNDS : \
38+
0)))
39+
40+
static const uint8_t sbox[256] = {
41+
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
42+
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
43+
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
44+
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
45+
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
46+
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
47+
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
48+
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
49+
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
50+
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
51+
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
52+
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
53+
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
54+
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
55+
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
56+
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
57+
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
58+
};
59+
60+
static const uint8_t rsbox[256] = {
61+
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
62+
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
63+
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
64+
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
65+
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
66+
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
67+
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
68+
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
69+
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
70+
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
71+
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
72+
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
73+
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
74+
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
75+
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
76+
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
77+
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
78+
};
79+
80+
// For AES (as distinct from Rijndael), we only need the round constants 1 through 10
81+
static const uint8_t round_constants[11] = {
82+
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36
83+
};
84+
85+
// Perform s-box substitution and row shift on round state
86+
static void shift_sub_state(aes_state_word_t *state) {
87+
uint8_t temp;
88+
89+
// The first row only needs substitution, not rotation
90+
state[0].b[0] = sbox[state[0].b[0]];
91+
state[1].b[0] = sbox[state[1].b[0]];
92+
state[2].b[0] = sbox[state[2].b[0]];
93+
state[3].b[0] = sbox[state[3].b[0]];
94+
95+
// The second row is rotated one column left
96+
temp = sbox[state[0].b[1]];
97+
state[0].b[1] = sbox[state[1].b[1]];
98+
state[1].b[1] = sbox[state[2].b[1]];
99+
state[2].b[1] = sbox[state[3].b[1]];
100+
state[3].b[1] = temp;
101+
102+
// The third row is rotated two columns left
103+
temp = sbox[state[0].b[2]];
104+
state[0].b[2] = sbox[state[2].b[2]];
105+
state[2].b[2] = temp;
106+
temp = sbox[state[1].b[2]];
107+
state[1].b[2] = sbox[state[3].b[2]];
108+
state[3].b[2] = temp;
109+
110+
// The fourth row is rotated three columns left
111+
temp = sbox[state[3].b[3]];
112+
state[3].b[3] = sbox[state[2].b[3]];
113+
state[2].b[3] = sbox[state[1].b[3]];
114+
state[1].b[3] = sbox[state[0].b[3]];
115+
state[0].b[3] = temp;
116+
}
117+
118+
// Perform reverse row shift and s-box substitution on round state
119+
static void rsub_shift_state(aes_state_word_t *state) {
120+
uint8_t temp;
121+
122+
state[0].b[0] = rsbox[state[0].b[0]];
123+
state[1].b[0] = rsbox[state[1].b[0]];
124+
state[2].b[0] = rsbox[state[2].b[0]];
125+
state[3].b[0] = rsbox[state[3].b[0]];
126+
127+
temp = rsbox[state[3].b[1]];
128+
state[3].b[1] = rsbox[state[2].b[1]];
129+
state[2].b[1] = rsbox[state[1].b[1]];
130+
state[1].b[1] = rsbox[state[0].b[1]];
131+
state[0].b[1] = temp;
132+
133+
temp = rsbox[state[0].b[2]];
134+
state[0].b[2] = rsbox[state[2].b[2]];
135+
state[2].b[2] = temp;
136+
temp = rsbox[state[1].b[2]];
137+
state[1].b[2] = rsbox[state[3].b[2]];
138+
state[3].b[2] = temp;
139+
140+
temp = rsbox[state[0].b[3]];
141+
state[0].b[3] = rsbox[state[1].b[3]];
142+
state[1].b[3] = rsbox[state[2].b[3]];
143+
state[2].b[3] = rsbox[state[3].b[3]];
144+
state[3].b[3] = temp;
145+
}
146+
147+
// Add round key to state
148+
static void add_round_key(aes_state_word_t *state, aes_state_word_t *key) {
149+
for (int i = 0; i < 4; i++) {
150+
state[i].w ^= key[i].w;
151+
}
152+
}
153+
154+
static inline uint8_t gf_double(uint8_t x) {
155+
return (x << 1) ^ (((x >> 7) & 1) * 0x1b);
156+
}
157+
158+
static void mix_columns(aes_state_word_t *state) {
159+
uint8_t temp, all_sum;
160+
for (int i = 0; i < 4; i++) {
161+
temp = state[i].b[0];
162+
all_sum = state[i].b[0] ^ state[i].b[1] ^ state[i].b[2] ^ state[i].b[3];
163+
state[i].b[0] ^= (gf_double(state[i].b[0] ^ state[i].b[1]) ^ all_sum);
164+
state[i].b[1] ^= (gf_double(state[i].b[1] ^ state[i].b[2]) ^ all_sum);
165+
state[i].b[2] ^= (gf_double(state[i].b[2] ^ state[i].b[3]) ^ all_sum);
166+
state[i].b[3] ^= (gf_double(state[i].b[3] ^ temp) ^ all_sum);
167+
}
168+
}
169+
170+
// Compute the GF weighted sum 14a + 11b + 13c + 9d
171+
// 14 = 0b1110, 11 = 0b1011, 13 = 0b1101, 9 = 0b1001
172+
static const uint8_t poly_reduce_mask[8] = {0, 27, 54, 45, 108, 119, 90, 65};
173+
174+
static uint8_t gf_ploy_inv(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
175+
uint8_t ac = a ^ c;
176+
uint8_t bd = b ^ d;
177+
uint8_t ab = a ^ b;
178+
uint16_t sum = ((ac ^ bd) << 3) ^ (ac << 2) ^ (ab << 1) ^ (bd ^ c);
179+
return (uint8_t)(sum ^ poly_reduce_mask[sum >> 8]);
180+
}
181+
182+
static void inv_mix_columns(aes_state_word_t *state) {
183+
uint8_t a, b, c, d;
184+
185+
for (int i = 0; i < 4; i++) {
186+
a = state[i].b[0];
187+
b = state[i].b[1];
188+
c = state[i].b[2];
189+
d = state[i].b[3];
190+
191+
state[i].b[0] = gf_ploy_inv(a, b, c, d);
192+
state[i].b[1] = gf_ploy_inv(b, c, d, a);
193+
state[i].b[2] = gf_ploy_inv(c, d, a, b);
194+
state[i].b[3] = gf_ploy_inv(d, a, b, c);
195+
}
196+
}
197+
198+
// Key length is given in bytes, not bits
199+
void aes_expand_key(aes_key_info_t *dest, const uint8_t *key, int keylen) {
200+
int n_rounds = ROUNDS_FOR_KEYLEN(keylen);
201+
int key_words = keylen / 4;
202+
int subkey_words = (n_rounds + 1) * 4;
203+
aes_state_word_t *array = dest->expanded_key.array;
204+
205+
dest->key_length = keylen;
206+
dest->n_rounds = n_rounds;
207+
208+
memcpy(dest->expanded_key.flat, key, keylen);
209+
210+
aes_state_word_t prev_word = array[key_words - 1];
211+
212+
for (int i = key_words; i < subkey_words; i++) {
213+
aes_state_word_t this_word = array[i - key_words];
214+
215+
if ((i % key_words) == 0) {
216+
this_word.b[0] ^= round_constants[i / key_words];
217+
218+
uint8_t temp = sbox[prev_word.b[0]];
219+
prev_word.b[0] = sbox[prev_word.b[1]];
220+
prev_word.b[1] = sbox[prev_word.b[2]];
221+
prev_word.b[2] = sbox[prev_word.b[3]];
222+
prev_word.b[3] = temp;
223+
} else if (key_words > 6 && (i % key_words) == 4) {
224+
prev_word.b[0] = sbox[prev_word.b[0]];
225+
prev_word.b[1] = sbox[prev_word.b[1]];
226+
prev_word.b[2] = sbox[prev_word.b[2]];
227+
prev_word.b[3] = sbox[prev_word.b[3]];
228+
}
229+
this_word.w ^= prev_word.w;
230+
prev_word = array[i] = this_word;
231+
}
232+
}
233+
234+
void aes_encrypt_block(uint8_t *block, aes_key_info_t *key_info) {
235+
uint32_t n_rounds = key_info->n_rounds;
236+
aes_expanded_key_t *key = &key_info->expanded_key;
237+
aes_round_state_t *state = (aes_round_state_t *)block;
238+
239+
add_round_key(state->words, key->rounds[0]);
240+
241+
uint32_t i;
242+
for (i = 1; i < n_rounds; i++) {
243+
shift_sub_state(state->words);
244+
mix_columns(state->words);
245+
add_round_key(state->words, key->rounds[i]);
246+
}
247+
248+
shift_sub_state(state->words);
249+
add_round_key(state->words, key->rounds[i]);
250+
}
251+
252+
void aes_decrypt_block(uint8_t *block, aes_key_info_t *key_info) {
253+
uint32_t n_rounds = key_info->n_rounds;
254+
aes_expanded_key_t *key = &key_info->expanded_key;
255+
aes_round_state_t *state = (aes_round_state_t *)block;
256+
257+
add_round_key(state->words, key->rounds[n_rounds]);
258+
rsub_shift_state(state->words);
259+
260+
for (int i = n_rounds - 1; i > 0; i--) {
261+
add_round_key(state->words, key->rounds[i]);
262+
inv_mix_columns(state->words);
263+
rsub_shift_state(state->words);
264+
}
265+
266+
add_round_key(state->words, key->rounds[0]);
267+
}
268+
269+
// Requires input_length % 16 == 0
270+
void aes_crypt_cbc(aes_key_info_t *key_info, int encrypt, size_t input_length, uint8_t *iv, const uint8_t *in, uint8_t *out) {
271+
uint32_t *iv_words = (uint32_t *)iv;
272+
uint32_t *in_words = (uint32_t *)in;
273+
uint32_t *out_words = (uint32_t *)out;
274+
275+
if (encrypt) {
276+
while (input_length > 0) {
277+
for (int i = 0; i < 4; i++) {
278+
iv_words[i] ^= *(in_words++);
279+
}
280+
aes_encrypt_block((uint8_t *)iv_words, key_info);
281+
memcpy(out_words, iv_words, 16);
282+
out_words += 4;
283+
input_length -= 16;
284+
}
285+
} else {
286+
uint32_t block_words[4];
287+
while (input_length > 0) {
288+
memcpy(block_words, in_words, 16);
289+
aes_decrypt_block((uint8_t *)block_words, key_info);
290+
for (int i = 0; i < 4; i++) {
291+
*(out_words++) = iv_words[i] ^ block_words[i];
292+
iv_words[i] = *(in_words++);
293+
}
294+
input_length -= 16;
295+
}
296+
}
297+
}

extmod/crypto-algorithms/aes.h

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* A small, lightweight AES implmentation suitable for microcontrollers.
3+
*
4+
* SPDX-License-Identifier: MIT
5+
* The MIT License (MIT)
6+
*
7+
* Copyright (c) 2021 Nicko van Someren
8+
*
9+
* Permission is hereby granted, free of charge, to any person obtaining a copy
10+
* of this software and associated documentation files (the "Software"), to deal
11+
* in the Software without restriction, including without limitation the rights
12+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
* copies of the Software, and to permit persons to whom the Software is
14+
* furnished to do so, subject to the following conditions:
15+
*
16+
* The above copyright notice and this permission notice shall be included in
17+
* all copies or substantial portions of the Software.
18+
*
19+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
* THE SOFTWARE.
26+
*/
27+
28+
#ifndef SMALL_AES_INCLUDE_AES_H
29+
#define SMALL_AES_INCLUDE_AES_H
30+
31+
#define AES_128_ROUNDS 10
32+
#define AES_192_ROUNDS 12
33+
#define AES_256_ROUNDS 14
34+
35+
#define AES_MAX_SUBKEYS 15
36+
37+
typedef union aes_state_word {
38+
uint8_t b[4];
39+
uint32_t w;
40+
} aes_state_word_t;
41+
42+
typedef union aes_round_state {
43+
aes_state_word_t words[4];
44+
uint8_t flat[16];
45+
} aes_round_state_t;
46+
47+
typedef union aes_expanded_key {
48+
aes_state_word_t rounds[AES_MAX_SUBKEYS][4];
49+
aes_state_word_t array[AES_MAX_SUBKEYS * 4];
50+
uint8_t flat[AES_MAX_SUBKEYS * 16];
51+
} aes_expanded_key_t;
52+
53+
typedef struct aes_key_info {
54+
uint16_t key_length;
55+
uint16_t n_rounds;
56+
aes_expanded_key_t expanded_key;
57+
} aes_key_info_t;
58+
59+
void aes_expand_key(aes_key_info_t *dest, const uint8_t *key, int keylen);
60+
void aes_encrypt_block(uint8_t *block, aes_key_info_t *key_info);
61+
void aes_decrypt_block(uint8_t *block, aes_key_info_t *key_info);
62+
63+
// Requires input_length % 16 == 0
64+
void aes_crypt_cbc(aes_key_info_t *key_info, int encrypt, size_t input_length, uint8_t *iv, const uint8_t *in, uint8_t *out);
65+
66+
#endif

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy