From d670f476ba977990d1f09ec0ebd989ea7a3845cd Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Mon, 19 Dec 2022 22:30:54 +0100 Subject: [PATCH] Berry add crypto AES_CTR, HDMAC_SHA256, MD5 (#17451) --- CHANGELOG.md | 1 + .../berry_tasmota/src/be_crypto_lib.c | 31 ++++ lib/libesp32/berry_tasmota/src/be_md5_lib.c | 16 +- tasmota/my_user_config.h | 2 + .../xdrv_52_3_berry_crypto.ino | 168 +++++++++++++++++- 5 files changed, 208 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a3f61efd..a17731b8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file. - Support for IPv6 DNS records (AAAA) and IPv6 ``Ping`` for ESP32 and ESP8266 (#17417) - Berry support for ``crypto.SHA256`` (#17430) - Support for RGB displays (#17414) +- Berry add crypto AES_CTR, HDMAC_SHA256, MD5 ### Breaking Changed diff --git a/lib/libesp32/berry_tasmota/src/be_crypto_lib.c b/lib/libesp32/berry_tasmota/src/be_crypto_lib.c index 3889e750c..083a846c9 100644 --- a/lib/libesp32/berry_tasmota/src/be_crypto_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_crypto_lib.c @@ -12,6 +12,10 @@ extern int m_aes_gcm_encryt(bvm *vm); extern int m_aes_gcm_decryt(bvm *vm); extern int m_aes_gcm_tag(bvm *vm); +extern int m_aes_ctr_init(bvm *vm); +extern int m_aes_ctr_run(bvm *vm); +extern int m_aes_ctr_tag(bvm *vm); + extern int m_ec_c25519_pubkey(bvm *vm); extern int m_ec_c25519_sharedkey(bvm *vm); @@ -19,9 +23,17 @@ extern int m_hash_sha256_init(bvm *vm); extern int m_hash_sha256_update(bvm *vm); extern int m_hash_sha256_out(bvm *vm); +extern int m_hmac_sha256_init(bvm *vm); +extern int m_hmac_sha256_update(bvm *vm); +extern int m_hmac_sha256_out(bvm *vm); + +extern const bclass be_class_md5; + #include "be_fixed_be_class_aes_gcm.h" +#include "be_fixed_be_class_aes_ctr.h" #include "be_fixed_be_class_ec_c25519.h" #include "be_fixed_be_class_sha256.h" +#include "be_fixed_be_class_hmac_sha256.h" #include "be_fixed_crypto.h" /* @const_object_info_begin @@ -36,6 +48,14 @@ class be_class_aes_gcm (scope: global, name: AES_GCM) { tag, func(m_aes_gcm_tag) } +class be_class_aes_ctr (scope: global, name: AES_CTR) { + .p1, var + + init, func(m_aes_ctr_init) + encrypt, func(m_aes_ctr_run) + decrypt, func(m_aes_ctr_run) +} + class be_class_ec_c25519 (scope: global, name: EC_C25519) { public_key, func(m_ec_c25519_pubkey) shared_key, func(m_ec_c25519_sharedkey) @@ -49,10 +69,21 @@ class be_class_sha256 (scope: global, name: SHA256) { out, func(m_hash_sha256_out) } +class be_class_hmac_sha256 (scope: global, name: HMAC_SHA256) { + .p, var + + init, func(m_hmac_sha256_init) + update, func(m_hmac_sha256_update) + out, func(m_hmac_sha256_out) +} + module crypto (scope: global) { AES_GCM, class(be_class_aes_gcm) + AES_CTR, class(be_class_aes_ctr) EC_C25519, class(be_class_ec_c25519) SHA256, class(be_class_sha256) + HMAC_SHA256, class(be_class_hmac_sha256) + MD5, class(be_class_md5) } @const_object_info_end */ diff --git a/lib/libesp32/berry_tasmota/src/be_md5_lib.c b/lib/libesp32/berry_tasmota/src/be_md5_lib.c index 3b73940ce..109003422 100644 --- a/lib/libesp32/berry_tasmota/src/be_md5_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_md5_lib.c @@ -11,8 +11,8 @@ #include "esp_rom_md5.h" // `Md5.init() -> ` -int32_t m_md5_init(struct bvm *vm); -int32_t m_md5_init(struct bvm *vm) { +int m_md5_init(bvm *vm); +int m_md5_init(bvm *vm) { md5_context_t * ctx = (md5_context_t *) be_os_malloc(sizeof(md5_context_t)); if (!ctx) { @@ -28,13 +28,11 @@ int32_t m_md5_init(struct bvm *vm) { // `Md5.update(content:bytes()) -> nil` // // Add raw bytes to the MD5 calculation -int32_t m_md5_update(struct bvm *vm); -int32_t m_md5_update(struct bvm *vm) { +int m_md5_update(bvm *vm); +int m_md5_update(bvm *vm) { int32_t argc = be_top(vm); // Get the number of arguments - if (argc >= 2 && be_isinstance(vm, 2)) { + if (argc >= 2 && be_isbytes(vm, 2)) { do { - be_getglobal(vm, "bytes"); /* get the bytes class */ /* TODO eventually replace with be_getbuiltin */ - if (!be_isderived(vm, 2)) break; size_t length = 0; const void * bytes = be_tobytes(vm, 2, &length); if (!bytes) break; @@ -57,8 +55,8 @@ int32_t m_md5_update(struct bvm *vm) { // `Md5.update(content:bytes()) -> nil` // // Add raw bytes to the MD5 calculation -int32_t m_md5_finish(struct bvm *vm); -int32_t m_md5_finish(struct bvm *vm) { +int m_md5_finish(bvm *vm); +int m_md5_finish(bvm *vm) { be_getmember(vm, 1, ".p"); md5_context_t * ctx; ctx = (md5_context_t *) be_tocomptr(vm, -1); diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index f00cc476a..3b147cce7 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -1106,8 +1106,10 @@ // #define USE_BERRY_ULP // Enable ULP (Ultra Low Power) support (+4.9k) // Berry crypto extensions below: #define USE_BERRY_CRYPTO_AES_GCM // enable AES GCM 256 bits + #define USE_BERRY_CRYPTO_AES_CTR // enable AEC CTR 256 bits // #define USE_BERRY_CRYPTO_EC_C25519 // enable Elliptic Curve C C25519 #define USE_BERRY_CRYPTO_SHA256 // enable SHA256 hash function + #define USE_BERRY_CRYPTO_HMAC_SHA256 // enable HMAC SHA256 hash function #define USE_CSE7761 // Add support for CSE7761 Energy monitor as used in Sonoff Dual R3 // -- LVGL Graphics Library --------------------------------- diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino index 83094ff5d..8f5e3613e 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino @@ -25,7 +25,7 @@ #include "be_object.h" /*********************************************************************************************\ - * AES class + * AES_GCM class * \*********************************************************************************************/ extern "C" { @@ -158,6 +158,87 @@ extern "C" { #endif // USE_BERRY_CRYPTO_AES_GCM } } + +/*********************************************************************************************\ + * AES_CTR class + * +\*********************************************************************************************/ +extern "C" { + + // `AES_CTR.init(secret_key:bytes(32)) -> instance` + int32_t m_aes_ctr_init(struct bvm *vm); + int32_t m_aes_ctr_init(struct bvm *vm) { +#ifdef USE_BERRY_CRYPTO_AES_CTR + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 2 && be_isbytes(vm, 2)) { + do { + size_t length = 0; + const void * bytes = be_tobytes(vm, 2, &length); + if (!bytes) break; + if (length != 32) { + be_raise(vm, "value_error", "Key size must be 32 bytes"); + } + + // Initialize an AES CTR structure with the secret key + br_aes_small_ctr_keys * ctr_ctx = (br_aes_small_ctr_keys *) be_os_malloc(sizeof(br_aes_small_ctr_keys)); + if (!ctr_ctx) { be_throw(vm, BE_MALLOC_FAIL); } + br_aes_small_ctr_init(ctr_ctx, bytes, length); + be_newcomobj(vm, ctr_ctx, &be_commonobj_destroy_generic); + be_setmember(vm, 1, ".p1"); + + be_return_nil(vm); + // success + } while (0); + } + be_raise(vm, kTypeError, nullptr); +#else // USE_BERRY_CRYPTO_AES_CTR + be_raise(vm, "Not implemented", nullptr); +#endif // USE_BERRY_CRYPTO_AES_CTR + } + + // `.encrypt(content:bytes(), in:bytes(12), counter:int) -> nil` + // `.decrypt(content:bytes(), in:bytes(12), counter:int) -> nil` + int32_t m_aes_ctr_run(bvm *vm); + int32_t m_aes_ctr_run(bvm *vm) { +#ifdef USE_BERRY_CRYPTO_AES_CTR + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 4 && be_isbytes(vm, 2) && be_isbytes(vm, 3) && be_isint(vm, 4)) { + do { + // get GCM context + be_getmember(vm, 1, ".p1"); + br_aes_small_ctr_keys * ctx = (br_aes_small_ctr_keys *) be_tocomptr(vm, -1); + be_pop(vm, 1); + + size_t iv_len; + const void * iv = be_tobytes(vm, 3, &iv_len); + if (iv_len != 12) { be_raise(vm, "value_error", "IV size must be 12 bytes"); } + + uint32_t counter = be_toint(vm, 4); + + // copy the input buffer + be_getmember(vm, 2, "copy"); // stack: bytes.copy() + be_pushvalue(vm, 2); // stack: bytes.copy(), bytes instance + be_call(vm, 1); // call copy with self parameter + be_pop(vm, 1); // stack: clone of input bytes + + size_t length = 0; + // we are changing bytes in place + void * bytes = (void*) be_tobytes(vm, -1, &length); + if (!bytes) break; + + uint32_t next_counter = br_aes_small_ctr_run(ctx, iv, counter, bytes, length); + + be_return(vm); + // success + } while (0); + } + be_raise(vm, kTypeError, nullptr); +#else // USE_BERRY_CRYPTO_AES_CTR + be_raise(vm, "Not implemented", nullptr); +#endif // USE_BERRY_CRYPTO_AES_CTR + } +} + /*********************************************************************************************\ * SHA256 class * @@ -236,6 +317,91 @@ extern "C" { } } +/*********************************************************************************************\ + * HMAC_SHA256 class + * +\*********************************************************************************************/ +extern "C" { + + // `HMAC_SHA256.init(key:bytes) -> nil` + int32_t m_hmac_sha256_init(struct bvm *vm); + int32_t m_hmac_sha256_init(struct bvm *vm) { +#ifdef USE_BERRY_CRYPTO_HMAC_SHA256 + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 2 && be_isbytes(vm, 2)) { + // Initialize a HMAC context + br_hmac_context * ctx = (br_hmac_context *) be_os_malloc(sizeof(br_hmac_context)); + if (!ctx) { + be_throw(vm, BE_MALLOC_FAIL); + } + br_hmac_key_context keyCtx; // keyCtx can be allocated on stack, it is not needed after `br_hmac_init` + size_t key_len; + const void *key = be_tobytes(vm, 2, &key_len); + br_hmac_key_init(&keyCtx, &br_sha256_vtable, key, key_len); + br_hmac_init(ctx, &keyCtx, 0); // 0 is "natural output length" + + be_newcomobj(vm, ctx, &be_commonobj_destroy_generic); + be_setmember(vm, 1, ".p"); + be_return_nil(vm); + } + be_raise(vm, kTypeError, nullptr); +#else // USE_BERRY_CRYPTO_HMAC_SHA256 + be_raise(vm, "Not implemented", nullptr); +#endif // USE_BERRY_CRYPTO_HMAC_SHA256 + } + + // `.update(content:bytes()) -> nil` + // + // Add raw bytes to the hash calculation + int32_t m_hmac_sha256_update(struct bvm *vm); + int32_t m_hmac_sha256_update(struct bvm *vm) { +#ifdef USE_BERRY_CRYPTO_HMAC_SHA256 + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 2 && be_isinstance(vm, 2)) { + do { + if (!be_isbytes(vm, 2)) break; + size_t length = 0; + const void * bytes = be_tobytes(vm, 2, &length); + if (!bytes) break; + + be_getmember(vm, 1, ".p"); + br_hmac_context * ctx; + ctx = (br_hmac_context *) be_tocomptr(vm, -1); + if (!ctx) break; + + if (length > 0) { + br_hmac_update(ctx, bytes, length); + } + be_return_nil(vm); + // success + } while (0); + } + be_raise(vm, "value_error", NULL); +#else // USE_BERRY_CRYPTO_HMAC_SHA256 + be_raise(vm, "Not implemented", nullptr); +#endif // USE_BERRY_CRYPTO_HMAC_SHA256 + } + + // `.finish() -> bytes()` + // + // Add raw bytes to the MD5 calculation + int32_t m_hmac_sha256_out(struct bvm *vm); + int32_t m_hmac_sha256_out(struct bvm *vm) { +#ifdef USE_BERRY_CRYPTO_HMAC_SHA256 + be_getmember(vm, 1, ".p"); + br_hmac_context * ctx; + ctx = (br_hmac_context *) be_tocomptr(vm, -1); + + uint8_t output[32]; + br_hmac_out(ctx, output); + be_pushbytes(vm, output, sizeof(output)); + be_return(vm); +#else // USE_BERRY_CRYPTO_HMAC_SHA256 + be_raise(vm, "Not implemented", nullptr); +#endif // USE_BERRY_CRYPTO_HMAC_SHA256 + } +} + /*********************************************************************************************\ * EC C25519 class *