Berry `crypto.AES_CCM` (required by Matter protocol) (#17586)

This commit is contained in:
s-hadinger 2023-01-03 20:26:46 +01:00 committed by GitHub
parent f570dcc913
commit d59caa7203
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 141 additions and 1 deletions

View File

@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file.
### Added
- Support for PCA9632 4-channel 8-bit PWM driver as light driver by Pascal Heinrich (#17557)
- Berry `bytes()` now evaluates to `false` if empty
- Berry ``crypto.AES_CCM`` (required by Matter protocol)
### Breaking Changed

View File

@ -11,6 +11,11 @@
extern int be_class_crypto_member(bvm *vm);
extern int m_crypto_random(bvm *vm);
extern int m_aes_ccm_init(bvm *vm);
extern int m_aes_ccm_encryt(bvm *vm);
extern int m_aes_ccm_decryt(bvm *vm);
extern int m_aes_ccm_tag(bvm *vm);
extern int m_aes_gcm_init(bvm *vm);
extern int m_aes_gcm_encryt(bvm *vm);
extern int m_aes_gcm_decryt(bvm *vm);
@ -47,6 +52,7 @@ extern const bclass be_class_md5;
#include "solidify/solidified_crypto_pbkdf2_hmac_sha256.h"
#include "solidify/solidified_crypto_spake2p_matter.h"
#include "be_fixed_be_class_aes_ccm.h"
#include "be_fixed_be_class_aes_gcm.h"
#include "be_fixed_be_class_aes_ctr.h"
#include "be_fixed_be_class_ec_p256.h"
@ -65,11 +71,17 @@ extern const bclass be_class_md5;
#define USE_BERRY_CRYPTO_HMAC_SHA256
#undef USE_BERRY_CRYPTO_HKDF_SHA256
#define USE_BERRY_CRYPTO_HKDF_SHA256
#undef USE_BERRY_CRYPTO_AES_CCM
#define USE_BERRY_CRYPTO_AES_CCM
#endif
const be_const_member_t be_crypto_members[] = {
// name with prefix '/' indicates a Berry class
// entries need to be sorted (ignoring the prefix char)
#ifdef USE_BERRY_CRYPTO_AES_CCM
{ "/AES_CCM", (intptr_t) &be_class_aes_ccm },
#endif // USE_BERRY_CRYPTO_AES_CTR
#ifdef USE_BERRY_CRYPTO_AES_CTR
{ "/AES_CTR", (intptr_t) &be_class_aes_ctr },
#endif // USE_BERRY_CRYPTO_AES_CTR
@ -114,6 +126,16 @@ const size_t be_crypto_members_size = sizeof(be_crypto_members)/sizeof(be_crypto
/* @const_object_info_begin
class be_class_aes_ccm (scope: global, name: AES_CCM) {
.p1, var
.p2, var
init, func(m_aes_ccm_init)
encrypt, func(m_aes_ccm_encryt)
decrypt, func(m_aes_ccm_decryt)
tag, func(m_aes_ccm_tag)
}
class be_class_aes_gcm (scope: global, name: AES_GCM) {
.p1, var
.p2, var

View File

@ -1120,7 +1120,8 @@
// #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_AES_CCM // enable AES CCM 128 bits
// #define USE_BERRY_CRYPTO_AES_CTR // enable AES CTR 256 bits
// #define USE_BERRY_CRYPTO_EC_P256 // enable EC P256r1
// #define USE_BERRY_CRYPTO_EC_C25519 // enable Elliptic Curve C C25519
#define USE_BERRY_CRYPTO_SHA256 // enable SHA256 hash function

View File

@ -180,6 +180,122 @@ extern "C" {
}
}
/*********************************************************************************************\
* AES_CCM class
*
\*********************************************************************************************/
extern "C" {
// `AES_CCM.init(secret_key:bytes(16 or 32), iv:bytes(7..13), aad:bytes(), data_len:int, tag_len:int) -> instance`
//
int32_t m_aes_ccm_init(struct bvm *vm);
int32_t m_aes_ccm_init(struct bvm *vm) {
int32_t argc = be_top(vm); // Get the number of arguments
if (argc >= 6 && be_isbytes(vm, 2) && be_isbytes(vm, 3) && be_isbytes(vm, 4) && be_isint(vm, 5) && be_isint(vm, 6)) {
do {
size_t key_len = 0;
const void * key = be_tobytes(vm, 2, &key_len);
if (key_len != 32 && key_len != 16) {
be_raise(vm, "value_error", "Key size must be 16 or 32 bytes");
}
size_t nonce_len = 0;
const void * nonce = be_tobytes(vm, 3, &nonce_len);
if (nonce_len < 7 || nonce_len > 13) {
be_raise(vm, "value_error", "Nonce size must be 7..13");
}
size_t aad_len = 0;
const void * aad = be_tobytes(vm, 4, &aad_len);
int32_t data_len = be_toint(vm, 5);
int32_t tag_len = be_toint(vm, 6);
if (tag_len < 4 || tag_len > 16) {
be_raise(vm, "value_error", "Tag size must be 4..16");
}
// Initialize an AES CCM structure with the secret key
br_ccm_context * ccm_ctx = (br_ccm_context *) be_os_malloc(sizeof(br_ccm_context));
if (!ccm_ctx) { be_throw(vm, BE_MALLOC_FAIL); }
be_newcomobj(vm, ccm_ctx, &be_commonobj_destroy_generic);
be_setmember(vm, 1, ".p1");
br_aes_small_ctrcbc_keys * key_ctx = (br_aes_small_ctrcbc_keys *) be_os_malloc(sizeof(br_aes_small_ctrcbc_keys));
if (!key_ctx) { be_throw(vm, BE_MALLOC_FAIL); }
br_aes_small_ctrcbc_init(key_ctx, key, key_len);
be_newcomobj(vm, key_ctx, &be_commonobj_destroy_generic);
be_setmember(vm, 1, ".p2");
br_ccm_init(ccm_ctx, &key_ctx->vtable);
int ret = br_ccm_reset(ccm_ctx, nonce, nonce_len, aad_len, data_len, tag_len);
if (ret == 0) { be_raise(vm, "value_error", "br_ccm_reset failed"); }
br_ccm_aad_inject(ccm_ctx, aad, aad_len);
br_ccm_flip(ccm_ctx);
be_return_nil(vm);
// success
} while (0);
}
be_raise(vm, kTypeError, nullptr);
}
// Finish injection of authentication data
int32_t m_aes_ccm_encrypt_or_decryt(bvm *vm, int encrypt);
int32_t m_aes_ccm_encryt(bvm *vm) { return m_aes_ccm_encrypt_or_decryt(vm, 1); }
int32_t m_aes_ccm_decryt(bvm *vm) { return m_aes_ccm_encrypt_or_decryt(vm, 0); }
int32_t m_aes_ccm_encrypt_or_decryt(bvm *vm, int encrypt) {
int32_t argc = be_top(vm); // Get the number of arguments
if (argc >= 2 && be_isbytes(vm, 2)) {
do {
// get CCM context
be_getmember(vm, 1, ".p1");
br_ccm_context * ccm_ctx = (br_ccm_context *) be_tocomptr(vm, -1);
be_pop(vm, 1);
// 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;
br_ccm_run(ccm_ctx, encrypt, bytes, length);
be_return(vm);
// success
} while (0);
}
be_raise(vm, kTypeError, nullptr);
}
int32_t m_aes_ccm_tag(bvm *vm) {
do {
be_getglobal(vm, "bytes"); /* get the bytes class */ /* TODO eventually replace with be_getbuiltin */
// get CCM context
be_getmember(vm, 1, ".p1");
br_ccm_context * ccm_ctx = (br_ccm_context *) be_tocomptr(vm, -1);
be_pop(vm, 1);
// create a bytes buffer of 16 bytes
uint8_t tag[16] = {};
br_ccm_get_tag(ccm_ctx, tag);
be_pushbytes(vm, tag, sizeof(tag));
be_return(vm);
// success
} while (0);
be_raise(vm, kTypeError, nullptr);
}
}
/*********************************************************************************************\
* AES_CTR class
*