Skip to content

Commit 4c07de1

Browse files
committed
WIP: Add support to crypto:mac
Signed-off-by: Davide Bettio <davide@uninstall.it>
1 parent 4df0f9d commit 4c07de1

File tree

1 file changed

+101
-0
lines changed

1 file changed

+101
-0
lines changed

src/libAtomVM/otp_crypto.c

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -895,6 +895,99 @@ static term nif_crypto_compute_key(Context *ctx, int argc, term argv[])
895895
return result;
896896
}
897897

898+
static const AtomStringIntPair hmac_algorithm_table[] = {
899+
{ ATOM_STR("\x6", "sha256"), PSA_ALG_SHA_256 },
900+
SELECT_INT_DEFAULT(0)
901+
};
902+
903+
static term nif_crypto_mac(Context *ctx, int argc, term argv[])
904+
{
905+
906+
term key_term = argv[2];
907+
VALIDATE_VALUE(key_term, term_is_binary);
908+
const void *key = term_binary_data(key_term);
909+
size_t key_len = term_binary_size(key_term);
910+
psa_key_bits_t key_bit_size = key_len * 8;
911+
912+
term data_term = argv[3];
913+
VALIDATE_VALUE(data_term, term_is_binary);
914+
const void *data = term_binary_data(data_term);
915+
size_t data_len = term_binary_size(data_term);
916+
917+
UNUSED(argc);
918+
919+
do_psa_init();
920+
921+
GlobalContext *glb = ctx->global;
922+
923+
// let's check argv[0] is always hmac
924+
psa_algorithm_t sub_type_algo
925+
= interop_atom_term_select_int(hmac_algorithm_table, argv[1], glb);
926+
927+
size_t mac_out_size
928+
= PSA_MAC_LENGTH(PSA_KEY_TYPE_HMAC, key_bit_size, PSA_ALG_HMAC(sub_type_algo));
929+
void *mac_out = malloc(mac_out_size);
930+
931+
bool success = false;
932+
term result = ERROR_ATOM;
933+
934+
psa_key_id_t key_id = 0;
935+
psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT;
936+
937+
psa_set_key_type(&attr, PSA_KEY_TYPE_HMAC);
938+
939+
psa_set_key_bits(&attr, key_bit_size);
940+
941+
psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_SIGN_MESSAGE);
942+
psa_set_key_algorithm(&attr, PSA_ALG_HMAC(sub_type_algo));
943+
944+
psa_status_t status = psa_import_key(&attr, key, key_len, &key_id);
945+
psa_reset_key_attributes(&attr);
946+
switch (status) {
947+
case PSA_SUCCESS:
948+
break;
949+
case PSA_ERROR_NOT_SUPPORTED:
950+
RAISE_ERROR(make_crypto_error(__FILE__, __LINE__, "Unsupported algorithm", ctx));
951+
default:
952+
RAISE_ERROR(make_crypto_error(__FILE__, __LINE__, "Unexpected error", ctx));
953+
}
954+
955+
size_t mac_len = 0;
956+
status = psa_mac_compute(
957+
key_id, PSA_ALG_HMAC(sub_type_algo), data, data_len, mac_out, mac_out_size, &mac_len);
958+
switch (status) {
959+
case PSA_SUCCESS:
960+
break;
961+
case PSA_ERROR_NOT_SUPPORTED:
962+
result = make_crypto_error(__FILE__, __LINE__, "Unsupported algorithm", ctx);
963+
goto cleanup;
964+
default:
965+
result = make_crypto_error(__FILE__, __LINE__, "Unexpected error", ctx);
966+
goto cleanup;
967+
}
968+
969+
if (UNLIKELY(memory_ensure_free(ctx, TERM_BINARY_HEAP_SIZE(mac_len)) != MEMORY_GC_OK)) {
970+
result = OUT_OF_MEMORY_ATOM;
971+
goto cleanup;
972+
}
973+
974+
success = true;
975+
result = term_from_literal_binary(mac_out, mac_len, &ctx->heap, glb);
976+
977+
cleanup:
978+
psa_destroy_key(key_id);
979+
if (mac_out) {
980+
memset(mac_out, 0, mac_out_size);
981+
}
982+
free(mac_out);
983+
984+
if (UNLIKELY(!success)) {
985+
RAISE_ERROR(result);
986+
}
987+
988+
return result;
989+
}
990+
898991
#endif
899992

900993
// not static since we are using it elsewhere to provide backward compatibility
@@ -948,6 +1041,10 @@ static const struct Nif crypto_compute_key_nif = {
9481041
.base.type = NIFFunctionType,
9491042
.nif_ptr = nif_crypto_compute_key
9501043
};
1044+
static const struct Nif crypto_mac_nif = {
1045+
.base.type = NIFFunctionType,
1046+
.nif_ptr = nif_crypto_mac
1047+
};
9511048
#endif
9521049
static const struct Nif crypto_strong_rand_bytes_nif = {
9531050
.base.type = NIFFunctionType,
@@ -983,6 +1080,10 @@ const struct Nif *otp_crypto_nif_get_nif(const char *nifname)
9831080
TRACE("Resolved platform nif %s ...\n", nifname);
9841081
return &crypto_compute_key_nif;
9851082
}
1083+
if (strcmp("mac/4", rest) == 0) {
1084+
TRACE("Resolved platform nif %s ...\n", nifname);
1085+
return &crypto_mac_nif;
1086+
}
9861087
#endif
9871088
if (strcmp("strong_rand_bytes/1", rest) == 0) {
9881089
TRACE("Resolved platform nif %s ...\n", nifname);

0 commit comments

Comments
 (0)