@@ -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
9521049static 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