3636#include <esp_partition.h>
3737#include <esp_sleep.h>
3838#include <esp_system.h>
39+ #include <mbedtls/md5.h>
40+ #include <mbedtls/sha1.h>
41+ #include <mbedtls/sha256.h>
42+ #include <mbedtls/sha512.h>
3943#include <soc/soc.h>
4044#include <stdlib.h>
41- #if defined __has_include
42- # if __has_include (< esp_idf_version .h > )
43- # include <esp_idf_version.h>
44- # endif
45- #endif
46- #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL (4 , 3 , 0 ) && CONFIG_IDF_TARGET_ESP32
47- #include <esp_rom_md5.h>
48- #else
49- #include <rom/md5_hash.h>
50- #endif
51- #if CONFIG_IDF_TARGET_ESP32C3
52- #include "esp32c3/rom/md5_hash.h"
53- #elif CONFIG_IDF_TARGET_ESP32S2
54- #include "esp32s2/rom/md5_hash.h"
55- #elif CONFIG_IDF_TARGET_ESP32S3
56- #include "esp32s3/rom/md5_hash.h"
57- #endif
5845
5946// introduced starting with 4.4
6047#if ESP_IDF_VERSION_MAJOR >= 5
6653
6754#define TAG "atomvm"
6855
69- #define MD5_DIGEST_LENGTH 16
56+ #define MAX_MD_SIZE 64
7057
7158static const char * const esp_rst_unknown_atom = "\xF" "esp_rst_unknown" ;
7259static const char * const esp_rst_poweron = "\xF" "esp_rst_poweron" ;
@@ -93,6 +80,33 @@ static const AtomStringIntPair interface_table[] = {
9380 SELECT_INT_DEFAULT (InvalidInterface )
9481};
9582
83+ enum crypto_algorithm
84+ {
85+ CryptoInvalidAlgorithm = 0 ,
86+ CryptoMd5 ,
87+ CryptoSha1 ,
88+ CryptoSha224 ,
89+ CryptoSha256 ,
90+ CryptoSha384 ,
91+ CryptoSha512
92+ };
93+
94+ static const AtomStringIntPair crypto_algorithm_table [] = {
95+ { ATOM_STR ("\x3" , "md5" ), CryptoMd5 },
96+ { ATOM_STR ("\x3" , "sha" ), CryptoSha1 },
97+ { ATOM_STR ("\x6" , "sha224" ), CryptoSha224 },
98+ { ATOM_STR ("\x6" , "sha256" ), CryptoSha256 },
99+ { ATOM_STR ("\x6" , "sha384" ), CryptoSha384 },
100+ { ATOM_STR ("\x6" , "sha512" ), CryptoSha512 },
101+ SELECT_INT_DEFAULT (CryptoInvalidAlgorithm )
102+ };
103+
104+ #if defined __has_include
105+ #if __has_include (< esp_idf_version .h > )
106+ #include <esp_idf_version.h>
107+ #endif
108+ #endif
109+
96110//
97111// NIFs
98112//
@@ -435,27 +449,156 @@ static term nif_esp_sleep_enable_ext1_wakeup(Context *ctx, int argc, term argv[]
435449
436450#endif
437451
438- static term nif_rom_md5 (Context * ctx , int argc , term argv [])
452+ #define DEFINE_DO_HASH (ALGORITHM , SUFFIX ) \
453+ static InteropFunctionResult ALGORITHM##_hash_fold_fun(term t, void *accum) \
454+ { \
455+ mbedtls_##ALGORITHM##_context *md_ctx = (mbedtls_##ALGORITHM##_context *) accum; \
456+ if (term_is_integer(t)) { \
457+ uint8_t val = term_to_uint8(t); \
458+ mbedtls_##ALGORITHM##_update##SUFFIX(md_ctx, &val, 1); \
459+ } else if (term_is_binary(t)) { \
460+ mbedtls_##ALGORITHM##_update(md_ctx, (uint8_t *) term_binary_data(t), term_binary_size(t)); \
461+ } \
462+ return InteropOk; \
463+ } \
464+ \
465+ static bool do_##ALGORITHM##_hash(term data, unsigned char *dst) \
466+ { \
467+ mbedtls_##ALGORITHM##_context md_ctx; \
468+ \
469+ mbedtls_##ALGORITHM##_init(&md_ctx); \
470+ mbedtls_##ALGORITHM##_starts##SUFFIX(&md_ctx); \
471+ \
472+ InteropFunctionResult result = interop_chardata_fold(data, ALGORITHM##_hash_fold_fun, NULL, (void *) &md_ctx); \
473+ if (UNLIKELY(result != InteropOk)) { \
474+ return false; \
475+ } \
476+ \
477+ if (UNLIKELY(mbedtls_##ALGORITHM##_finish##SUFFIX(&md_ctx, dst) != 0)) { \
478+ return false; \
479+ } \
480+ \
481+ return true; \
482+ }
483+
484+ #define DEFINE_DO_HASH2 (ALGORITHM , SUFFIX , IS_OTHER ) \
485+ static InteropFunctionResult ALGORITHM##_hash_fold_fun_##IS_OTHER(term t, void *accum) \
486+ { \
487+ mbedtls_##ALGORITHM##_context *md_ctx = (mbedtls_##ALGORITHM##_context *) accum; \
488+ if (term_is_any_integer(t)) { \
489+ avm_int64_t tmp = term_maybe_unbox_int64(t); \
490+ if (tmp < 0 || tmp > 255) { \
491+ return InteropBadArg; \
492+ } \
493+ uint8_t val = (avm_int64_t) tmp; \
494+ mbedtls_##ALGORITHM##_update##SUFFIX(md_ctx, &val, 1); \
495+ } else if (term_is_binary(t)) { \
496+ mbedtls_##ALGORITHM##_update(md_ctx, (uint8_t *) term_binary_data(t), term_binary_size(t)); \
497+ } \
498+ return InteropOk; \
499+ } \
500+ \
501+ static bool do_##ALGORITHM##_hash_##IS_OTHER(term data, unsigned char *dst) \
502+ { \
503+ mbedtls_##ALGORITHM##_context md_ctx; \
504+ \
505+ mbedtls_##ALGORITHM##_init(&md_ctx); \
506+ mbedtls_##ALGORITHM##_starts##SUFFIX(&md_ctx, IS_OTHER); \
507+ \
508+ InteropFunctionResult result = interop_chardata_fold(data, ALGORITHM##_hash_fold_fun_##IS_OTHER, NULL, (void *) &md_ctx); \
509+ if (UNLIKELY(result != InteropOk)) { \
510+ return false; \
511+ } \
512+ \
513+ if (UNLIKELY(mbedtls_##ALGORITHM##_finish##SUFFIX(&md_ctx, dst) != 0)) { \
514+ return false; \
515+ } \
516+ \
517+ return true; \
518+ }
519+
520+ #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL (5 , 0 , 0 )
521+
522+ DEFINE_DO_HASH (md5 , _ret )
523+ DEFINE_DO_HASH (sha1 , _ret )
524+ DEFINE_DO_HASH2 (sha256 , _ret , true)
525+ DEFINE_DO_HASH2 (sha256 , _ret , false)
526+ DEFINE_DO_HASH2 (sha512 , _ret , true)
527+ DEFINE_DO_HASH2 (sha512 , _ret , false)
528+
529+ #else
530+
531+ DEFINE_DO_HASH (md5 , )
532+ DEFINE_DO_HASH (sha1 , )
533+ DEFINE_DO_HASH2 (sha256 , , true)
534+ DEFINE_DO_HASH2 (sha256 , , false)
535+ DEFINE_DO_HASH2 (sha512 , , true)
536+ DEFINE_DO_HASH2 (sha512 , , false)
537+
538+ #endif
539+
540+ static term nif_crypto_hash (Context * ctx , int argc , term argv [])
439541{
440542 UNUSED (argc );
441- term data = argv [0 ];
442- VALIDATE_VALUE (data , term_is_binary );
443-
444- unsigned char digest [MD5_DIGEST_LENGTH ];
445- struct MD5Context md5 ;
446- #if __has_include (< esp_idf_version .h > ) && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL (4 , 3 , 0 ) && CONFIG_IDF_TARGET_ESP32
447- esp_rom_md5_init (& md5 );
448- esp_rom_md5_update (& md5 , (const unsigned char * ) term_binary_data (data ), term_binary_size (data ));
449- esp_rom_md5_final (digest , & md5 );
450- #else
451- MD5Init (& md5 );
452- MD5Update (& md5 , (const unsigned char * ) term_binary_data (data ), term_binary_size (data ));
453- MD5Final (digest , & md5 );
454- #endif
455- if (UNLIKELY (memory_ensure_free (ctx , term_binary_heap_size (MD5_DIGEST_LENGTH )) != MEMORY_GC_OK )) {
543+ term type = argv [0 ];
544+ VALIDATE_VALUE (type , term_is_atom );
545+ term data = argv [1 ];
546+
547+ unsigned char digest [MAX_MD_SIZE ];
548+ size_t digest_len = 0 ;
549+
550+ enum crypto_algorithm algo = interop_atom_term_select_int (crypto_algorithm_table , type , ctx -> global );
551+ switch (algo ) {
552+ case CryptoMd5 : {
553+ if (UNLIKELY (!do_md5_hash (data , digest ))) {
554+ RAISE_ERROR (BADARG_ATOM )
555+ }
556+ digest_len = 16 ;
557+ break ;
558+ }
559+ case CryptoSha1 : {
560+ if (UNLIKELY (!do_sha1_hash (data , digest ))) {
561+ RAISE_ERROR (BADARG_ATOM )
562+ }
563+ digest_len = 20 ;
564+ break ;
565+ }
566+ case CryptoSha224 : {
567+ if (UNLIKELY (!do_sha256_hash_true (data , digest ))) {
568+ RAISE_ERROR (BADARG_ATOM )
569+ }
570+ digest_len = 28 ;
571+ break ;
572+ }
573+ case CryptoSha256 : {
574+ if (UNLIKELY (!do_sha256_hash_false (data , digest ))) {
575+ RAISE_ERROR (BADARG_ATOM )
576+ }
577+ digest_len = 32 ;
578+ break ;
579+ }
580+ case CryptoSha384 : {
581+ if (UNLIKELY (!do_sha512_hash_true (data , digest ))) {
582+ RAISE_ERROR (BADARG_ATOM )
583+ }
584+ digest_len = 48 ;
585+ break ;
586+ }
587+ case CryptoSha512 : {
588+ if (UNLIKELY (!do_sha512_hash_false (data , digest ))) {
589+ RAISE_ERROR (BADARG_ATOM )
590+ }
591+ digest_len = 64 ;
592+ break ;
593+ }
594+ default :
595+ RAISE_ERROR (BADARG_ATOM );
596+ }
597+
598+ if (UNLIKELY (memory_ensure_free (ctx , term_binary_heap_size (digest_len )) != MEMORY_GC_OK )) {
456599 RAISE_ERROR (OUT_OF_MEMORY_ATOM );
457600 }
458- return term_from_literal_binary (digest , MD5_DIGEST_LENGTH , & ctx -> heap , ctx -> global );
601+ return term_from_literal_binary (digest , digest_len , & ctx -> heap , ctx -> global );
459602}
460603
461604static term nif_atomvm_platform (Context * ctx , int argc , term argv [])
@@ -566,10 +709,10 @@ static const struct Nif esp_sleep_enable_ext1_wakeup_nif =
566709 .nif_ptr = nif_esp_sleep_enable_ext1_wakeup
567710};
568711#endif
569- static const struct Nif rom_md5_nif =
712+ static const struct Nif crypto_hash_nif =
570713{
571714 .base .type = NIFFunctionType ,
572- .nif_ptr = nif_rom_md5
715+ .nif_ptr = nif_crypto_hash
573716};
574717static const struct Nif atomvm_platform_nif =
575718{
@@ -638,9 +781,9 @@ const struct Nif *platform_nifs_get_nif(const char *nifname)
638781 return & esp_sleep_enable_ext1_wakeup_nif ;
639782 }
640783#endif
641- if (strcmp ("erlang:md5/1 " , nifname ) == 0 ) {
784+ if (strcmp ("crypto:hash/2 " , nifname ) == 0 ) {
642785 TRACE ("Resolved platform nif %s ...\n" , nifname );
643- return & rom_md5_nif ;
786+ return & crypto_hash_nif ;
644787 }
645788 if (strcmp ("atomvm:platform/0" , nifname ) == 0 ) {
646789 TRACE ("Resolved platform nif %s ...\n" , nifname );
0 commit comments