Branch data Line data Source code
1 : : /*
2 : : * This file is part of the MicroPython project, http://micropython.org/
3 : : *
4 : : * The MIT License (MIT)
5 : : *
6 : : * Copyright (c) 2017-2018 Paul Sokolovsky
7 : : * Copyright (c) 2018 Yonatan Goldschmidt
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 "py/mpconfig.h"
29 : :
30 : : #if MICROPY_PY_CRYPTOLIB
31 : :
32 : : #include <assert.h>
33 : : #include <string.h>
34 : :
35 : : #include "py/runtime.h"
36 : :
37 : : // This module implements crypto ciphers API, roughly following
38 : : // https://www.python.org/dev/peps/pep-0272/ . Exact implementation
39 : : // of PEP 272 can be made with a simple wrapper which adds all the
40 : : // needed boilerplate.
41 : :
42 : : // values follow PEP 272
43 : : enum {
44 : : UCRYPTOLIB_MODE_ECB = 1,
45 : : UCRYPTOLIB_MODE_CBC = 2,
46 : : UCRYPTOLIB_MODE_CTR = 6,
47 : : };
48 : :
49 : : struct ctr_params {
50 : : // counter is the IV of the AES context.
51 : :
52 : : size_t offset; // in encrypted_counter
53 : : // encrypted counter
54 : : uint8_t encrypted_counter[16];
55 : : };
56 : :
57 : : #if MICROPY_SSL_AXTLS
58 : : #include "lib/axtls/crypto/crypto.h"
59 : :
60 : : #define AES_CTX_IMPL AES_CTX
61 : : #endif
62 : :
63 : : #if MICROPY_SSL_MBEDTLS
64 : : #include <mbedtls/aes.h>
65 : :
66 : : // we can't run mbedtls AES key schedule until we know whether we're used for encrypt or decrypt.
67 : : // therefore, we store the key & keysize and on the first call to encrypt/decrypt we override them
68 : : // with the mbedtls_aes_context, as they are not longer required. (this is done to save space)
69 : : struct mbedtls_aes_ctx_with_key {
70 : : union {
71 : : mbedtls_aes_context mbedtls_ctx;
72 : : struct {
73 : : uint8_t key[32];
74 : : uint8_t keysize;
75 : : } init_data;
76 : : } u;
77 : : unsigned char iv[16];
78 : : };
79 : : #define AES_CTX_IMPL struct mbedtls_aes_ctx_with_key
80 : : #endif
81 : :
82 : : typedef struct _mp_obj_aes_t {
83 : : mp_obj_base_t base;
84 : : AES_CTX_IMPL ctx;
85 : : uint8_t block_mode : 6;
86 : : #define AES_KEYTYPE_NONE 0
87 : : #define AES_KEYTYPE_ENC 1
88 : : #define AES_KEYTYPE_DEC 2
89 : : uint8_t key_type : 2;
90 : : struct ctr_params ctr_params[]; // optional
91 : : } mp_obj_aes_t;
92 : :
93 : : static inline bool is_ctr_mode(int block_mode) {
94 : : #if MICROPY_PY_CRYPTOLIB_CTR
95 : : return block_mode == UCRYPTOLIB_MODE_CTR;
96 : : #else
97 : : return false;
98 : : #endif
99 : : }
100 : :
101 : 6 : static inline struct ctr_params *ctr_params_from_aes(mp_obj_aes_t *o) {
102 : 6 : return &o->ctr_params[0];
103 : : }
104 : :
105 : : #if MICROPY_SSL_AXTLS
106 : : static void aes_initial_set_key_impl(AES_CTX_IMPL *ctx, const uint8_t *key, size_t keysize, const uint8_t iv[16]) {
107 : : assert(16 == keysize || 32 == keysize);
108 : : AES_set_key(ctx, key, iv, (16 == keysize) ? AES_MODE_128 : AES_MODE_256);
109 : : }
110 : :
111 : : static void aes_final_set_key_impl(AES_CTX_IMPL *ctx, bool encrypt) {
112 : : if (!encrypt) {
113 : : AES_convert_key(ctx);
114 : : }
115 : : }
116 : :
117 : : static void aes_process_ecb_impl(AES_CTX_IMPL *ctx, const uint8_t in[16], uint8_t out[16], bool encrypt) {
118 : : memcpy(out, in, 16);
119 : : // We assume that out (vstr.buf or given output buffer) is uint32_t aligned
120 : : uint32_t *p = (uint32_t *)out;
121 : : // axTLS likes it weird and complicated with byteswaps
122 : : for (int i = 0; i < 4; i++) {
123 : : p[i] = MP_HTOBE32(p[i]);
124 : : }
125 : : if (encrypt) {
126 : : AES_encrypt(ctx, p);
127 : : } else {
128 : : AES_decrypt(ctx, p);
129 : : }
130 : : for (int i = 0; i < 4; i++) {
131 : : p[i] = MP_BE32TOH(p[i]);
132 : : }
133 : : }
134 : :
135 : : static void aes_process_cbc_impl(AES_CTX_IMPL *ctx, const uint8_t *in, uint8_t *out, size_t in_len, bool encrypt) {
136 : : if (encrypt) {
137 : : AES_cbc_encrypt(ctx, in, out, in_len);
138 : : } else {
139 : : AES_cbc_decrypt(ctx, in, out, in_len);
140 : : }
141 : : }
142 : :
143 : : #if MICROPY_PY_CRYPTOLIB_CTR
144 : : // axTLS doesn't have CTR support out of the box. This implements the counter part using the ECB primitive.
145 : : static void aes_process_ctr_impl(AES_CTX_IMPL *ctx, const uint8_t *in, uint8_t *out, size_t in_len, struct ctr_params *ctr_params) {
146 : : size_t n = ctr_params->offset;
147 : : uint8_t *const counter = ctx->iv;
148 : :
149 : : while (in_len--) {
150 : : if (n == 0) {
151 : : aes_process_ecb_impl(ctx, counter, ctr_params->encrypted_counter, true);
152 : :
153 : : // increment the 128-bit counter
154 : : for (int i = 15; i >= 0; --i) {
155 : : if (++counter[i] != 0) {
156 : : break;
157 : : }
158 : : }
159 : : }
160 : :
161 : : *out++ = *in++ ^ ctr_params->encrypted_counter[n];
162 : : n = (n + 1) & 0xf;
163 : : }
164 : :
165 : : ctr_params->offset = n;
166 : : }
167 : : #endif
168 : :
169 : : #endif
170 : :
171 : : #if MICROPY_SSL_MBEDTLS
172 : 32 : static void aes_initial_set_key_impl(AES_CTX_IMPL *ctx, const uint8_t *key, size_t keysize, const uint8_t iv[16]) {
173 : 32 : ctx->u.init_data.keysize = keysize;
174 : 32 : memcpy(ctx->u.init_data.key, key, keysize);
175 : :
176 [ + + ]: 32 : if (NULL != iv) {
177 : 14 : memcpy(ctx->iv, iv, sizeof(ctx->iv));
178 : : }
179 : 32 : }
180 : :
181 : 30 : static void aes_final_set_key_impl(AES_CTX_IMPL *ctx, bool encrypt) {
182 : : // first, copy key aside
183 : 30 : uint8_t key[32];
184 : 30 : uint8_t keysize = ctx->u.init_data.keysize;
185 : 30 : memcpy(key, ctx->u.init_data.key, keysize);
186 : : // now, override key with the mbedtls context object
187 : 30 : mbedtls_aes_init(&ctx->u.mbedtls_ctx);
188 : :
189 : : // setkey call will succeed, we've already checked the keysize earlier.
190 [ - + ]: 30 : assert(16 == keysize || 32 == keysize);
191 [ + + ]: 30 : if (encrypt) {
192 : 18 : mbedtls_aes_setkey_enc(&ctx->u.mbedtls_ctx, key, keysize * 8);
193 : : } else {
194 : 12 : mbedtls_aes_setkey_dec(&ctx->u.mbedtls_ctx, key, keysize * 8);
195 : : }
196 : 30 : }
197 : :
198 : 36 : static void aes_process_ecb_impl(AES_CTX_IMPL *ctx, const uint8_t in[16], uint8_t out[16], bool encrypt) {
199 : 36 : mbedtls_aes_crypt_ecb(&ctx->u.mbedtls_ctx, encrypt ? MBEDTLS_AES_ENCRYPT : MBEDTLS_AES_DECRYPT, in, out);
200 : 36 : }
201 : :
202 : 8 : static void aes_process_cbc_impl(AES_CTX_IMPL *ctx, const uint8_t *in, uint8_t *out, size_t in_len, bool encrypt) {
203 : 8 : mbedtls_aes_crypt_cbc(&ctx->u.mbedtls_ctx, encrypt ? MBEDTLS_AES_ENCRYPT : MBEDTLS_AES_DECRYPT, in_len, ctx->iv, in, out);
204 : 8 : }
205 : :
206 : : #if MICROPY_PY_CRYPTOLIB_CTR
207 : 6 : static void aes_process_ctr_impl(AES_CTX_IMPL *ctx, const uint8_t *in, uint8_t *out, size_t in_len, struct ctr_params *ctr_params) {
208 : 6 : mbedtls_aes_crypt_ctr(&ctx->u.mbedtls_ctx, in_len, &ctr_params->offset, ctx->iv, ctr_params->encrypted_counter, in, out);
209 : 6 : }
210 : : #endif
211 : :
212 : : #endif
213 : :
214 : 32 : static mp_obj_t cryptolib_aes_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
215 : 32 : mp_arg_check_num(n_args, n_kw, 2, 3, false);
216 : :
217 : 32 : const mp_int_t block_mode = mp_obj_get_int(args[1]);
218 : :
219 [ - + ]: 32 : switch (block_mode) {
220 : : case UCRYPTOLIB_MODE_ECB:
221 : : case UCRYPTOLIB_MODE_CBC:
222 : : #if MICROPY_PY_CRYPTOLIB_CTR
223 : : case UCRYPTOLIB_MODE_CTR:
224 : : #endif
225 : 32 : break;
226 : :
227 : : default:
228 : 0 : mp_raise_ValueError(MP_ERROR_TEXT("mode"));
229 : : }
230 : :
231 [ + + ]: 58 : mp_obj_aes_t *o = mp_obj_malloc_var(mp_obj_aes_t, ctr_params, struct ctr_params, !!is_ctr_mode(block_mode), type);
232 : :
233 : 32 : o->block_mode = block_mode;
234 : 32 : o->key_type = AES_KEYTYPE_NONE;
235 : :
236 : 32 : mp_buffer_info_t keyinfo;
237 : 32 : mp_get_buffer_raise(args[0], &keyinfo, MP_BUFFER_READ);
238 [ - + ]: 32 : if (32 != keyinfo.len && 16 != keyinfo.len) {
239 : 0 : mp_raise_ValueError(MP_ERROR_TEXT("key"));
240 : : }
241 : :
242 : 32 : mp_buffer_info_t ivinfo;
243 : 32 : ivinfo.buf = NULL;
244 [ + + + - ]: 32 : if (n_args > 2 && args[2] != mp_const_none) {
245 : 14 : mp_get_buffer_raise(args[2], &ivinfo, MP_BUFFER_READ);
246 : :
247 [ - + ]: 14 : if (16 != ivinfo.len) {
248 : 0 : mp_raise_ValueError(MP_ERROR_TEXT("IV"));
249 : : }
250 [ + - - + ]: 18 : } else if (o->block_mode == UCRYPTOLIB_MODE_CBC || is_ctr_mode(o->block_mode)) {
251 : 0 : mp_raise_ValueError(MP_ERROR_TEXT("IV"));
252 : : }
253 : :
254 [ + + ]: 32 : if (is_ctr_mode(block_mode)) {
255 : 6 : ctr_params_from_aes(o)->offset = 0;
256 : : }
257 : :
258 : 32 : aes_initial_set_key_impl(&o->ctx, keyinfo.buf, keyinfo.len, ivinfo.buf);
259 : :
260 : 32 : return MP_OBJ_FROM_PTR(o);
261 : : }
262 : :
263 : 32 : static mp_obj_t aes_process(size_t n_args, const mp_obj_t *args, bool encrypt) {
264 : 32 : mp_obj_aes_t *self = MP_OBJ_TO_PTR(args[0]);
265 : :
266 : 32 : mp_obj_t in_buf = args[1];
267 : 32 : mp_obj_t out_buf = MP_OBJ_NULL;
268 [ + + ]: 32 : if (n_args > 2) {
269 : 8 : out_buf = args[2];
270 : : }
271 : :
272 : 32 : mp_buffer_info_t in_bufinfo;
273 : 32 : mp_get_buffer_raise(in_buf, &in_bufinfo, MP_BUFFER_READ);
274 : :
275 [ + + - + ]: 32 : if (!is_ctr_mode(self->block_mode) && in_bufinfo.len % 16 != 0) {
276 : 0 : mp_raise_ValueError(MP_ERROR_TEXT("blksize % 16"));
277 : : }
278 : :
279 : 32 : vstr_t vstr;
280 : 32 : mp_buffer_info_t out_bufinfo;
281 : 32 : uint8_t *out_buf_ptr;
282 : :
283 [ + + ]: 32 : if (out_buf != MP_OBJ_NULL) {
284 : 8 : mp_get_buffer_raise(out_buf, &out_bufinfo, MP_BUFFER_WRITE);
285 [ - + ]: 8 : if (out_bufinfo.len < in_bufinfo.len) {
286 : 0 : mp_raise_ValueError(MP_ERROR_TEXT("output too small"));
287 : : }
288 : 8 : out_buf_ptr = out_bufinfo.buf;
289 : : } else {
290 : 24 : vstr_init_len(&vstr, in_bufinfo.len);
291 : 24 : out_buf_ptr = (uint8_t *)vstr.buf;
292 : : }
293 : :
294 [ + + ]: 32 : if (AES_KEYTYPE_NONE == self->key_type) {
295 : : // always set key for encryption if CTR mode.
296 [ + + + + ]: 30 : const bool encrypt_mode = encrypt || is_ctr_mode(self->block_mode);
297 : 30 : aes_final_set_key_impl(&self->ctx, encrypt_mode);
298 [ + + ]: 44 : self->key_type = encrypt ? AES_KEYTYPE_ENC : AES_KEYTYPE_DEC;
299 : : } else {
300 [ - + - + ]: 2 : if ((encrypt && self->key_type == AES_KEYTYPE_DEC) ||
301 [ # # ]: 0 : (!encrypt && self->key_type == AES_KEYTYPE_ENC)) {
302 : :
303 : 0 : mp_raise_ValueError(MP_ERROR_TEXT("can't encrypt & decrypt"));
304 : : }
305 : : }
306 : :
307 [ + + + - ]: 32 : switch (self->block_mode) {
308 : 18 : case UCRYPTOLIB_MODE_ECB: {
309 : 18 : uint8_t *in = in_bufinfo.buf, *out = out_buf_ptr;
310 : 18 : uint8_t *top = in + in_bufinfo.len;
311 [ + + ]: 54 : for (; in < top; in += 16, out += 16) {
312 : 36 : aes_process_ecb_impl(&self->ctx, in, out, encrypt);
313 : : }
314 : : break;
315 : : }
316 : :
317 : 8 : case UCRYPTOLIB_MODE_CBC:
318 : 8 : aes_process_cbc_impl(&self->ctx, in_bufinfo.buf, out_buf_ptr, in_bufinfo.len, encrypt);
319 : 8 : break;
320 : :
321 : : #if MICROPY_PY_CRYPTOLIB_CTR
322 : : case UCRYPTOLIB_MODE_CTR:
323 : 6 : aes_process_ctr_impl(&self->ctx, in_bufinfo.buf, out_buf_ptr, in_bufinfo.len,
324 : : ctr_params_from_aes(self));
325 : 6 : break;
326 : : #endif
327 : : }
328 : :
329 [ + + ]: 32 : if (out_buf != MP_OBJ_NULL) {
330 : : return out_buf;
331 : : }
332 : 24 : return mp_obj_new_bytes_from_vstr(&vstr);
333 : : }
334 : :
335 : 18 : static mp_obj_t cryptolib_aes_encrypt(size_t n_args, const mp_obj_t *args) {
336 : 18 : return aes_process(n_args, args, true);
337 : : }
338 : : static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(cryptolib_aes_encrypt_obj, 2, 3, cryptolib_aes_encrypt);
339 : :
340 : 14 : static mp_obj_t cryptolib_aes_decrypt(size_t n_args, const mp_obj_t *args) {
341 : 14 : return aes_process(n_args, args, false);
342 : : }
343 : : static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(cryptolib_aes_decrypt_obj, 2, 3, cryptolib_aes_decrypt);
344 : :
345 : : static const mp_rom_map_elem_t cryptolib_aes_locals_dict_table[] = {
346 : : { MP_ROM_QSTR(MP_QSTR_encrypt), MP_ROM_PTR(&cryptolib_aes_encrypt_obj) },
347 : : { MP_ROM_QSTR(MP_QSTR_decrypt), MP_ROM_PTR(&cryptolib_aes_decrypt_obj) },
348 : : };
349 : : static MP_DEFINE_CONST_DICT(cryptolib_aes_locals_dict, cryptolib_aes_locals_dict_table);
350 : :
351 : : static MP_DEFINE_CONST_OBJ_TYPE(
352 : : cryptolib_aes_type,
353 : : MP_QSTR_aes,
354 : : MP_TYPE_FLAG_NONE,
355 : : make_new, cryptolib_aes_make_new,
356 : : locals_dict, &cryptolib_aes_locals_dict
357 : : );
358 : :
359 : : static const mp_rom_map_elem_t mp_module_cryptolib_globals_table[] = {
360 : : { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_cryptolib) },
361 : : { MP_ROM_QSTR(MP_QSTR_aes), MP_ROM_PTR(&cryptolib_aes_type) },
362 : : #if MICROPY_PY_CRYPTOLIB_CONSTS
363 : : { MP_ROM_QSTR(MP_QSTR_MODE_ECB), MP_ROM_INT(UCRYPTOLIB_MODE_ECB) },
364 : : { MP_ROM_QSTR(MP_QSTR_MODE_CBC), MP_ROM_INT(UCRYPTOLIB_MODE_CBC) },
365 : : #if MICROPY_PY_CRYPTOLIB_CTR
366 : : { MP_ROM_QSTR(MP_QSTR_MODE_CTR), MP_ROM_INT(UCRYPTOLIB_MODE_CTR) },
367 : : #endif
368 : : #endif
369 : : };
370 : :
371 : : static MP_DEFINE_CONST_DICT(mp_module_cryptolib_globals, mp_module_cryptolib_globals_table);
372 : :
373 : : const mp_obj_module_t mp_module_cryptolib = {
374 : : .base = { &mp_type_module },
375 : : .globals = (mp_obj_dict_t *)&mp_module_cryptolib_globals,
376 : : };
377 : :
378 : : // This module should not be extensible (as it is not a CPython standard
379 : : // library nor is it necessary to override from the filesystem), however it
380 : : // has previously been known as `ucryptolib`, so by making it extensible the
381 : : // `ucryptolib` alias will continue to work.
382 : : MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_cryptolib, mp_module_cryptolib);
383 : :
384 : : #endif // MICROPY_PY_CRYPTOLIB
|