LCOV - code coverage report
Current view: top level - extmod - modcryptolib.c (source / functions) Hit Total Coverage
Test: unix_coverage_v1.24.0-7-g548babf8a.info Lines: 88 96 91.7 %
Date: 2024-10-30 09:06:48 Functions: 9 9 100.0 %
Branches: 42 56 75.0 %

           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

Generated by: LCOV version 1.15-5-g462f71d