From 457f706d1726c9dfa2ab1b566ae546ad4e0d2c6c Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Mon, 16 Jan 2023 21:48:28 +0100 Subject: [PATCH] Berry ``crypto.EC_P256`` ECDSA signature (required by Matter protocol) (#17723) --- CHANGELOG.md | 1 + .../berry_tasmota/src/be_crypto_lib.c | 4 + .../xdrv_52_3_berry_crypto.ino | 76 +++++++++++++++++++ 3 files changed, 81 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 70dd1dee9..d30ad9a6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file. ## [12.3.1.4] ### Added +- Berry ``crypto.EC_P256`` ECDSA signature (required by Matter protocol) ### 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 59518e120..079a9249a 100644 --- a/lib/libesp32/berry_tasmota/src/be_crypto_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_crypto_lib.c @@ -27,6 +27,8 @@ extern int m_aes_ctr_tag(bvm *vm); extern int m_ec_p256_pubkey(bvm *vm); extern int m_ec_p256_sharedkey(bvm *vm); +extern int m_ec_p256_ecdsa_sign_sha256(bvm *vm); +extern int m_ec_p256_ecdsa_verify_sha256(bvm *vm); extern int m_ec_p256_mod(bvm *vm); extern int m_ec_p256_neg(bvm *vm); extern int m_ec_p256_muladd(bvm *vm); @@ -157,6 +159,8 @@ class be_class_aes_ctr (scope: global, name: AES_CTR) { class be_class_ec_p256 (scope: global, name: EC_P256) { public_key, static_func(m_ec_p256_pubkey) shared_key, static_func(m_ec_p256_sharedkey) + ecdsa_sign_sha256, static_func(m_ec_p256_ecdsa_sign_sha256) + ecdsa_verify_sha256, static_func(m_ec_p256_ecdsa_verify_sha256) mod, static_func(m_ec_p256_mod) neg, static_func(m_ec_p256_neg) muladd, static_func(m_ec_p256_muladd) 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 40261e22b..f739b090c 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino @@ -566,6 +566,82 @@ extern "C" { be_raise(vm, kTypeError, nullptr); } + // crypto.EC_P256().ecdsa_sign_sha256(my_private_key:bytes(32), message:bytes()) -> bytes(64) + // Sign with ECDSA SHA256 + int32_t m_ec_p256_ecdsa_sign_sha256(bvm *vm); + int32_t m_ec_p256_ecdsa_sign_sha256(bvm *vm) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 2 && be_isbytes(vm, 1) && be_isbytes(vm, 2)) { + size_t sk_len = 0; + uint8_t * sk = (uint8_t*) be_tobytes(vm, 1, &sk_len); + size_t msg_len = 0; + const uint8_t * msg = (const uint8_t*) be_tobytes(vm, 2, &msg_len); + if (sk_len != 32) { + be_raise(vm, "value_error", "Key size invalid"); + } + + // first compute SHA-256 hash on the message + uint8_t hash[32]; + br_sha256_context ctx; + br_sha256_init(&ctx); + br_sha256_update(&ctx, msg, msg_len); + br_sha256_out(&ctx, hash); + + // run ECDSA on hash + uint8_t sign[64]; // hard limit for ECDSA SHA256 + br_ec_private_key br_sk = { BR_EC_secp256r1, sk, 32 }; + size_t sign_len = br_ecdsa_i15_sign_raw(&BR_EC_P256_IMPL, &br_sha256_vtable, hash, &br_sk, sign); + + be_pushbytes(vm, sign, sign_len); + be_return(vm); + } + be_raise(vm, kTypeError, nullptr); + } + + // `crypto.EC_P256().ecdsa_verify_sha256(public_key:bytes(65), message:bytes(), hash:bytes()) -> bool` + // Verify signature with ECDSA SHA256 + int32_t m_ec_p256_ecdsa_verify_sha256(bvm *vm); + int32_t m_ec_p256_ecdsa_verify_sha256(bvm *vm) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 3 && be_isbytes(vm, 1) && be_isbytes(vm, 2) && be_isbytes(vm, 3)) { + size_t pk_len = 0; + uint8_t * pk = (uint8_t*) be_tobytes(vm, 1, &pk_len); + size_t msg_len = 0; + const uint8_t * msg = (const uint8_t*) be_tobytes(vm, 2, &msg_len); + if (pk_len != 65) { + be_raise(vm, "value_error", "Key size invalid"); + } + size_t sig_len = 0; + const uint8_t * sig = (const uint8_t*) be_tobytes(vm, 3, &sig_len); + + // first compute SHA-256 hash on the message + uint8_t hash[32]; + br_sha256_context ctx; + br_sha256_init(&ctx); + br_sha256_update(&ctx, msg, msg_len); + br_sha256_out(&ctx, hash); + + // run ECDSA on hash + br_ec_public_key br_pk = { BR_EC_secp256r1, pk, pk_len }; + uint32_t ret = br_ecdsa_i15_vrfy_raw(&BR_EC_P256_IMPL, hash, sizeof(hash), &br_pk, sig, sig_len); + + be_pushbool(vm, ret); + be_return(vm); + } + be_raise(vm, kTypeError, nullptr); + } + /* Test values + import crypto + var priv = bytes('D42A43989B67211031FF194FBA791B5C3E03F9EC10ED561A4DEB2AA7BADB4772') + # var priv = crypto.random(32) + var pub = crypto.EC_P256().public_key(priv) + var msg = bytes().fromstring("Tasmota crypto ECDSA SECP256R1 SHA256 test message") + + var sig = crypto.EC_P256().ecdsa_sign_sha256(priv, msg) + var ok = crypto.EC_P256().ecdsa_verify_sha256(pub, msg, sig) + assert(ok == true) + */ + // We have generated the P256 order as a i15 encoding using // static const unsigned char P256_N[] PROGMEM = { // 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,