From b710c0214120f951b082752e0388936e1f8f4ff2 Mon Sep 17 00:00:00 2001 From: Jaeyong Lee Date: Fri, 23 Aug 2024 17:22:34 +0900 Subject: [PATCH 1/4] build/tools/amebad/gnu_utility: SE Support GCM mode for RTL8721CSM Support GCM mode for RTL8721CSM --- .../amebad/gnu_utility/km4_image3_all.bin | Bin 6176 -> 6240 bytes .../amebad/gnu_utility/km4_image3_all_fpu.bin | Bin 9552 -> 9744 bytes .../amebad/gnu_utility/km4_image3_psram.bin | Bin 130384 -> 143584 bytes .../gnu_utility/km4_image3_psram_fpu.bin | Bin 130800 -> 144016 bytes os/board/rtl8721csm/src/libs/cmse_implib.a | Bin 2590 -> 2666 bytes .../rtl8721csm/src/libs/cmse_implib_fpu.a | Bin 2590 -> 2666 bytes 6 files changed, 0 insertions(+), 0 deletions(-) diff --git a/build/tools/amebad/gnu_utility/km4_image3_all.bin b/build/tools/amebad/gnu_utility/km4_image3_all.bin index 68023a275bc013041a3c2ca73b59f33758862f2a..397f9ede306611570b6cceadc39f198e8b0be018 100644 GIT binary patch delta 1038 zcmX|HqA&o zLMah`ij>Hj2)ZOxCV zUSWa7V(U>`&|ptVHu~DrK=dX#4srpd3xfvub|TX`P+#4W6WA>Oxt&jC9G#t6?B zaY-_<^2z8LspU)1BI)Ck&`~nV7og{4kxxOnBtghZcDIW7Hq|4lX{s5jKUA1r#?VHp zgdM1boD&YCW>PQe$edtTIq6-;NS^Agt0ljbn_Yo`u|VMmMpcm#n~D`SFb*=#GEOn> zKB=tx)vU1kyu#0n6&Fgmi=(nsFHg>KHb{eX$mlA+M4Ci3>5WU|WvMc9I+e{MOZJ#6 zi@E%mGg7BV+hg(8h~sRYkvh@F(K-joGn(HQ9e2@DNA9ZQP*KE*H$5G+zA2i^qT{BK z1vN&fn}p)qw!9BpCIR3jvdgjvcPQ^urM8m(^=Fg(L8~2{$iVxQ9t(b9i0?}Ucc6(F zH9e@4Olfj6G^>K2AL9BT)g6di#S^tFn}YzEv>7%kS{yq@bP1#U&ep%-9{`7F8yr-v zv{T0@Yp9M>_0rfupXES=WEt0^8d9w_AuqYA%|=@CSet@sMts^~UM+a790ULyq(k?@ zGW66n@0wqe-Y|AY8ItaeN9IG)Fyp5&C0-(~#4^`|3FWVT#!kkEjNvCreu;6$tHk9j zf0@mnVQgotVm!ha&(^Q9SW@Z`qrMW+ljtkTsmRVjX(h@v$rZiN Mn$*ZxH!id99~!yY%K!iX delta 979 zcmY+Ce@IhN6vxkf@6Ffzk#{Yd;BS*PY1JOG)YR!8)mCJf6r>^LAC+2>f{<3E;Eyya zS@#c{SSa;}85C>{vP^@JGB7owKZI(5ltRG@Y^K{@cYD`C7ryUv&bjZNd)|4+V;V52 z^Q3%pUalm8T`i$*dqFmOWj{%D@p2U80Ll~|7+}6Ot7gDz0`T^ccyvR8P7&KWL~Oh( z;scbi0CvI7@}uO_Z_r>_cr1A zd~P*JEPN_DL#p@!G({YI5-KKcJ{R31KlwDIC2_)*R9m}EC@E0fqrWfF{`Gl8+I0QUzWj}lB;lnafxwHo)W*rc#QGuX(j&f zf{VrX%rpP^c(X=C|Je8~hHCNIQ$EcGF2pr%a~GqB=}{OegI`h{UX^MwdyiW(S%h zuQl07BEK|gDA}di@R(OOc3L>_(!^vkVM4k#*0R{L==VKhtPeBb>l_Ki1HK-{v8Rgv zj*M?AuD(91oVv(Z$9R+R&vRw}8{>y(imzWg$KrL2R~Yv*mXq_k$jxveSM2vSGM*Zd*`nS2Z~X%=cBpdz diff --git a/build/tools/amebad/gnu_utility/km4_image3_all_fpu.bin b/build/tools/amebad/gnu_utility/km4_image3_all_fpu.bin index ebe51298eb6e201ffb367a8791141a9fc454a288..827890352d25e1f6d92568e0ffd39aa0d0401a4e 100644 GIT binary patch delta 1220 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 delta 19299 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 l0ayv}03HSW1@IQ&eELOO1U7Qwa} zL=lImA=;{`wx+;_s3Eu|=nuR-HFyub%e|lP!STL7t`>d`AH=j{JH8xhwfYA8MPx`^ zHHPPzUH!5;n#fDjdvOc9Lc^;0ESK+wloGK$Ey`c8t6uAb^ zklS#YdRU%)2$9xnA9an&H zcoy4hy4)gs*M9SNv{=4qtQ7J)2T^!EtP Plb(p|=^_*O@BXhJHw2}w delta 621 zcmZ9~F-yZh7{>AU(!`ohMhi9$+R()=mLd*u>)4?~5d=X&9o;H82fB!hG#m&nMHj(> zU?>#CZ{Q$)gUl8|GB^~4^O?+pw;aF!!NGgnv^*>is%ke5_PyJrxG*mwi;|gD?Dz5I zcQjEV?~nPx8=R4+@QmzOB8o1m!Y+9m_Q)OBCm+H=?qhR`P|t%ohnwUpI3z#7E%FQ8 zCZ}+h{H0H=S*W_2&rN{VyJ@TB5VaYxmkT>Ca?#Ofy zT6r)BaGQJvcgcNtk34{n$aip${0ukADIET}l9?ZbgeF{aM4l3z7FNc-JyPROXW3Ra Yx>%|?GYq?>8>L!h!xdS_2l~H$0gZ@|B>(^b diff --git a/os/board/rtl8721csm/src/libs/cmse_implib_fpu.a b/os/board/rtl8721csm/src/libs/cmse_implib_fpu.a index 36d8ce4b6880a4a396d00385a4449eaabc64c988..476a1bfec56abedcace88b2a787df82f00aba04d 100644 GIT binary patch delta 676 zcmZ9~KS%;$9LDkA`G-1MGAy*A6qlUBmS_rx2B8L_B?ykwtcZ+^7F%u>LOO1U7Qwa} zL=lImA=;{`wx+;_s3Eu|=nuR-HFyub%e|lP!STL7t`>d`AH=j{JH8xhwfYA8MPx`^ zHHPPzUH!5;n#fDjdvOc9Lc^;0ESK+wloGK$Ey`c8t6uAb^ zklS#YdRU%)2$9xnA9an&H zcoy4hy4)gs*M9SNv{=4qtQ7J)2T^!EtP Plb(p|=^_*O@BXhJHw2}w delta 621 zcmZ9~F-yZh7{>AU(!`ohMhi9$+R()=mLd*u>)4?~5d=X&9o;H82fB!hG#m&nMHj(> zU?>#CZ{Q$)gUl8|GB^~4^O?+pw;aF!!NGgnv^*>is%ke5_PyJrxG*mwi;|gD?Dz5I zcQjEV?~nPx8=R4+@QmzOB8o1m!Y+9m_Q)OBCm+H=?qhR`P|t%ohnwUpI3z#7E%FQ8 zCZ}+h{H0H=S*W_2&rN{VyJ@TB5VaYxmkT>Ca?#Ofy zT6r)BaGQJvcgcNtk34{n$aip${0ukADIET}l9?ZbgeF{aM4l3z7FNc-JyPROXW3Ra Yx>%|?GYq?>8>L!h!xdS_2l~H$0gZ@|B>(^b From f8406047307bdb838519d77f6ca473122186acd4 Mon Sep 17 00:00:00 2001 From: Jaeyong Lee Date: Mon, 12 Aug 2024 15:15:06 +0900 Subject: [PATCH 2/4] os/drivers/seclink/seclink_drv.c: Change vdbg to dbg There is a hang when enable all below configs ``` CONFIG_DEBUG_WARN=y CONFIG_DEBUG_VERBOSE=y CONFIG_DEBUG_SECURE_ELEMENT_ERROR=y CONFIG_DEBUG_SECURE_ELEMENT_INFO=y ``` To avoid this hang, this commit changes vdbg to dbg. --- os/drivers/seclink/seclink_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/drivers/seclink/seclink_drv.c b/os/drivers/seclink/seclink_drv.c index 664540078e..b1bd9ff614 100644 --- a/os/drivers/seclink/seclink_drv.c +++ b/os/drivers/seclink/seclink_drv.c @@ -159,7 +159,7 @@ int seclink_ioctl(FAR struct file *filep, int cmd, unsigned long arg) ****************************************************************************/ int se_register(const char *path, struct sec_lowerhalf_s *lower) { - vdbg("Registering %s\n", path); + dbg("Registering %s\n", path); if (!lower) { return -1; From 36d58084cb07d23a1bfb4e2f893dd175f8aa82c7 Mon Sep 17 00:00:00 2001 From: Jaeyong Lee Date: Mon, 23 Sep 2024 12:17:43 +0900 Subject: [PATCH 3/4] seclink, security: Implementation of GCM Security API Add GCM mode in seclink and security - sl_gcm_encrypt / sl_gcm_decrypt - crypto_gcm_encryption / crypto_gcm_decryption Signed-off-by: Jaeyong Lee --- framework/include/security/security_common.h | 15 ++++ framework/include/security/security_crypto.h | 2 + framework/src/seclink/seclink.c | 42 ++++++++++- framework/src/security/security_crypto.c | 79 ++++++++++++++++++++ framework/src/security/security_internal.h | 10 +++ framework/src/security/security_utils.c | 31 ++++++++ os/drivers/seclink/seclink_drv_crypto.c | 6 ++ os/include/tinyara/seclink.h | 5 ++ 8 files changed, 186 insertions(+), 4 deletions(-) diff --git a/framework/include/security/security_common.h b/framework/include/security/security_common.h index ea1cc6350b..68d6090bd4 100644 --- a/framework/include/security/security_common.h +++ b/framework/include/security/security_common.h @@ -157,6 +157,11 @@ typedef enum { AES_UNKNOWN, } security_aes_mode; +typedef enum { + GCM_AES, + GCM_UNKNOWN, +} security_gcm_mode; + typedef enum { HASH_MD5, HASH_SHA1, @@ -180,6 +185,16 @@ typedef struct _security_aes_param { unsigned int iv_len; } security_aes_param; +typedef struct _security_gcm_param { + security_gcm_mode cipher; + unsigned char *iv; + unsigned int iv_len; + unsigned char *aad; + unsigned int aad_len; + unsigned char *tag; + unsigned int tag_len; +} security_gcm_param; + typedef struct _security_ecdsa_param { security_ecdsa_mode curve; security_hash_mode hash_t; diff --git a/framework/include/security/security_crypto.h b/framework/include/security/security_crypto.h index 6f99fd75d6..6a2d7680f5 100644 --- a/framework/include/security/security_crypto.h +++ b/framework/include/security/security_crypto.h @@ -33,6 +33,8 @@ security_error crypto_aes_encryption(security_handle hnd, security_aes_param *pa security_error crypto_aes_decryption(security_handle hnd, security_aes_param *param, const char *key_name, security_data *input, security_data *output); security_error crypto_rsa_encryption(security_handle hnd, security_rsa_param *param, const char *key_name, security_data *input, security_data *output); security_error crypto_rsa_decryption(security_handle hnd, security_rsa_param *param, const char *key_name, security_data *input, security_data *output); +security_error crypto_gcm_encryption(security_handle hnd, security_gcm_param *param, const char *key_name, security_data *input, security_data *output); +security_error crypto_gcm_decryption(security_handle hnd, security_gcm_param *param, const char *key_name, security_data *input, security_data *output); #ifdef __cplusplus } diff --git a/framework/src/seclink/seclink.c b/framework/src/seclink/seclink.c index b7864e4467..c339ab1aca 100644 --- a/framework/src/seclink/seclink.c +++ b/framework/src/seclink/seclink.c @@ -507,7 +507,7 @@ int sl_aes_encrypt(sl_ctx hnd, hal_data *dec_data, hnd, key_idx, aes_param->mode, aes_param->iv_len); struct _seclink_s_ *sl = (struct _seclink_s_ *)hnd; - struct seclink_crypto_info info = {key_idx, dec_data, enc_data, aes_param, NULL}; + struct seclink_crypto_info info = {key_idx, dec_data, enc_data, aes_param, NULL, NULL}; struct seclink_req req = {.req_type.crypto = &info, 0}; SL_CALL(sl, SECLINKIOC_AESENCRYPT, req); @@ -523,7 +523,7 @@ int sl_aes_decrypt(sl_ctx hnd, hal_data *enc_data, SLC_LOGI(TAG, "--> hnd(%p) idx(%d) aes mode(%d) iv len(%d)\n", hnd, key_idx, aes_param->mode, aes_param->iv_len); struct _seclink_s_ *sl = (struct _seclink_s_ *)hnd; - struct seclink_crypto_info info = {key_idx, enc_data, dec_data, aes_param, NULL}; + struct seclink_crypto_info info = {key_idx, enc_data, dec_data, aes_param, NULL, NULL}; struct seclink_req req = {.req_type.crypto = &info, 0}; SL_CALL(sl, SECLINKIOC_AESDECRYPT, req); @@ -539,7 +539,7 @@ int sl_rsa_encrypt(sl_ctx hnd, hal_data *dec_data, SLC_LOGI(TAG, "--> hnd(%p) idx(%d) RSA mode(%d) hash(%d) mgf(%d) salt len(%d)\n", hnd, key_idx, rsa_mode->rsa_a, rsa_mode->hash_t, rsa_mode->mgf, rsa_mode->salt_byte_len); struct _seclink_s_ *sl = (struct _seclink_s_ *)hnd; - struct seclink_crypto_info info = {key_idx, dec_data, enc_data, NULL, rsa_mode}; + struct seclink_crypto_info info = {key_idx, dec_data, enc_data, NULL, rsa_mode, NULL}; struct seclink_req req = {.req_type.crypto = &info, 0}; SL_CALL(sl, SECLINKIOC_RSAENCRYPT, req); @@ -557,13 +557,47 @@ int sl_rsa_decrypt(sl_ctx hnd, hnd, key_idx, rsa_mode->rsa_a, rsa_mode->hash_t, rsa_mode->mgf, rsa_mode->salt_byte_len); struct _seclink_s_ *sl = (struct _seclink_s_ *)hnd; - struct seclink_crypto_info info = {key_idx, enc_data, dec_data, NULL, rsa_mode}; + struct seclink_crypto_info info = {key_idx, enc_data, dec_data, NULL, rsa_mode, NULL}; struct seclink_req req = {.req_type.crypto = &info, 0}; SL_CALL(sl, SECLINKIOC_RSADECRYPT, req); return _sl_convert_res(req.res); } +int sl_gcm_encrypt(sl_ctx hnd, hal_data *dec_data, + hal_gcm_param *gcm_param, + uint32_t key_idx, + _OUT_ hal_data *enc_data) +{ + SL_CHECK_VALID(hnd); + SLC_LOGI(TAG, "--> hnd(%p) idx(%d) gcm cipher(%d) iv_len(%d) aad_len(%d) tag_len(%d)\n", + hnd, key_idx, gcm_param->cipher, gcm_param->iv_len, gcm_param->aad_len, gcm_param->tag_len); + + struct _seclink_s_ *sl = (struct _seclink_s_ *)hnd; + struct seclink_crypto_info info = {key_idx, dec_data, enc_data, NULL, NULL, gcm_param}; + struct seclink_req req = {.req_type.crypto = &info, 0}; + + SL_CALL(sl, SECLINKIOC_GCMENCRYPT, req); + return _sl_convert_res(req.res); +} + +int sl_gcm_decrypt(sl_ctx hnd, hal_data *enc_data, + hal_gcm_param *gcm_param, + uint32_t key_idx, + _OUT_ hal_data *dec_data) +{ + SL_CHECK_VALID(hnd); + SLC_LOGI(TAG, "--> hnd(%p) idx(%d) gcm cipher(%d) iv_len(%d) aad_len(%d) tag_len(%d)\n", + hnd, key_idx, gcm_param->cipher, gcm_param->iv_len, gcm_param->aad_len, gcm_param->tag_len); + + struct _seclink_s_ *sl = (struct _seclink_s_ *)hnd; + struct seclink_crypto_info info = {key_idx, enc_data, dec_data, NULL, NULL, gcm_param}; + struct seclink_req req = {.req_type.crypto = &info, 0}; + + SL_CALL(sl, SECLINKIOC_GCMDECRYPT, req); + return _sl_convert_res(req.res); +} + /* Secure Storage */ int sl_write_storage(sl_ctx hnd, uint32_t ss_idx, hal_data *data) { diff --git a/framework/src/security/security_crypto.c b/framework/src/security/security_crypto.c index 7fd5f61ba3..152be5ab43 100644 --- a/framework/src/security/security_crypto.c +++ b/framework/src/security/security_crypto.c @@ -168,3 +168,82 @@ security_error crypto_rsa_decryption(security_handle hnd, SECAPI_DATA_DCOPY(dec, output); SECAPI_RETURN(SECURITY_OK); } + +security_error crypto_gcm_encryption(security_handle hnd, + security_gcm_param *param, + const char *key_name, + security_data *input, + security_data *output) +{ + SECAPI_ENTER; + SECAPI_ISHANDLE_VALID(hnd); + struct security_ctx *ctx = (struct security_ctx *)hnd; + + HAL_INIT_GCM_PARAM(hparam); + SECAPI_CONVERT_GCMPARAM(param, &hparam); + + // convert path + uint32_t key_idx = 0; + SECAPI_CONVERT_PATH(key_name, &key_idx); + + if (!input || !input->data) { + SECAPI_RETURN(SECURITY_INVALID_INPUT_PARAMS); + } + if (!output) { + SECAPI_RETURN(SECURITY_INVALID_INPUT_PARAMS); + } + hal_data dec = {input->data, input->length, NULL, 0}; + hal_data enc = {ctx->data1, ctx->dlen1, NULL, 0}; + + SECAPI_CALL(sl_gcm_encrypt(ctx->sl_hnd, &dec, &hparam, key_idx, &enc)); + + param->tag = (unsigned char *)malloc(hparam.tag_len); + if (!param->tag) { + SECAPI_RETURN(SECURITY_ALLOC_ERROR); + } + + output->data = (unsigned char *)malloc(enc.data_len); + if (!output->data) { + SECAPI_RETURN(SECURITY_ALLOC_ERROR); + } + + memcpy(param->tag, hparam.tag, hparam.tag_len); + param->tag_len = hparam.tag_len; + SECAPI_DATA_DCOPY(enc, output); + SECAPI_RETURN(SECURITY_OK); +} + +security_error crypto_gcm_decryption(security_handle hnd, + security_gcm_param *param, + const char *key_name, + security_data *input, + security_data *output) +{ + SECAPI_ENTER; + SECAPI_ISHANDLE_VALID(hnd); + struct security_ctx *ctx = (struct security_ctx *)hnd; + + HAL_INIT_GCM_PARAM(hparam); + SECAPI_CONVERT_GCMPARAM(param, &hparam); + + // convert path + uint32_t key_idx = 0; + SECAPI_CONVERT_PATH(key_name, &key_idx); + + if (!input || !input->data) { + SECAPI_RETURN(SECURITY_INVALID_INPUT_PARAMS); + } + if (!output) { + SECAPI_RETURN(SECURITY_INVALID_INPUT_PARAMS); + } + hal_data enc = {input->data, input->length, NULL, 0}; + hal_data dec = {ctx->data1, ctx->dlen1, NULL, 0}; + + SECAPI_CALL(sl_gcm_decrypt(ctx->sl_hnd, &enc, &hparam, key_idx, &dec)); + output->data = (unsigned char *)malloc(dec.data_len); + if (!output->data) { + SECAPI_RETURN(SECURITY_ALLOC_ERROR); + } + SECAPI_DATA_DCOPY(dec, output); + SECAPI_RETURN(SECURITY_OK); +} diff --git a/framework/src/security/security_internal.h b/framework/src/security/security_internal.h index 2befe462dc..949e1a373b 100644 --- a/framework/src/security/security_internal.h +++ b/framework/src/security/security_internal.h @@ -138,6 +138,14 @@ } \ } while (0) +#define SECAPI_CONVERT_GCMPARAM(sec, hal) \ + do { \ + int c_res = secutils_convert_gcmparam_s2h(sec, hal); \ + if (c_res < 0) { \ + SECAPI_RETURN(SECURITY_INVALID_INPUT_PARAMS); \ + } \ + } while (0) + #define SECAPI_CONVERT_KEYTYPE(sec, hal) \ do { \ hal = secutils_convert_key_s2h(sec); \ @@ -224,7 +232,9 @@ hal_key_type secutils_convert_ecdsamode_to_key_s2h(security_ecdsa_mode mode); security_error secutils_convert_error_h2s(int herr); int secutils_convert_path_s2h(const char *path, uint32_t *slot); int secutils_convert_aesparam_s2h(security_aes_param *sparam, hal_aes_param *hparam); +int secutils_convert_gcmparam_s2h(security_gcm_param *sparam, hal_gcm_param *hparam); int secutils_convert_rsaparam_s2h(security_rsa_param *sparam, hal_rsa_mode *hparam); +int secutils_convert_gcmparam_s2h(security_gcm_param *sparam, hal_gcm_param *hparam); int secutils_convert_ecdsaparam_s2h(security_ecdsa_param *eparam, hal_ecdsa_mode *hmode); int secutils_convert_dhparam_s2h(security_dh_param *dparam, hal_dh_data *hdata); int secutils_convert_ecdhparam_s2h(security_ecdh_param *eparam, hal_ecdh_data *hdata); diff --git a/framework/src/security/security_utils.c b/framework/src/security/security_utils.c index f681e28b0d..b016cd4006 100644 --- a/framework/src/security/security_utils.c +++ b/framework/src/security/security_utils.c @@ -199,6 +199,17 @@ hal_aes_algo secutils_convert_aesmode_s2h(security_aes_mode mode) return HAL_AES_UNKNOWN; } +hal_gcm_type secutils_convert_gcmmode_s2h(security_gcm_mode mode) +{ + switch (mode) { + case GCM_AES: + return HAL_GCM_AES; + case GCM_UNKNOWN: + return HAL_GCM_UNKNOWN; + } + return HAL_GCM_UNKNOWN; +} + hal_rsa_algo secutils_convert_rsamode_s2h(security_rsa_mode mode) { switch (mode) { @@ -286,6 +297,26 @@ int secutils_convert_aesparam_s2h(security_aes_param *sparam, hal_aes_param *hpa return 0; } +int secutils_convert_gcmparam_s2h(security_gcm_param *sparam, hal_gcm_param *hparam) +{ + if (!hparam || !sparam) { + return -1; + } + + hparam->cipher = secutils_convert_gcmmode_s2h(sparam->cipher); + if (hparam->cipher == HAL_GCM_UNKNOWN) { + return -1; + } + hparam->iv = sparam->iv; + hparam->iv_len = sparam->iv_len; + hparam->aad = sparam->aad; + hparam->aad_len = sparam->aad_len; + hparam->tag = sparam->tag; + hparam->tag_len = sparam->tag_len; + + return 0; +} + int secutils_convert_rsaparam_s2h(security_rsa_param *sparam, hal_rsa_mode *hparam) { if (!hparam || !sparam) { diff --git a/os/drivers/seclink/seclink_drv_crypto.c b/os/drivers/seclink/seclink_drv_crypto.c index ee0ddc793f..ecbe9759d9 100644 --- a/os/drivers/seclink/seclink_drv_crypto.c +++ b/os/drivers/seclink/seclink_drv_crypto.c @@ -63,6 +63,12 @@ int hd_handle_crypto_request(int cmd, unsigned long arg, void *lower) case SECLINKIOC_RSADECRYPT: SLDRV_CALL(res, req->res, rsa_decrypt, (info->input, info->rsa_mode, info->key_idx, info->output)); break; + case SECLINKIOC_GCMENCRYPT: + SLDRV_CALL(res, req->res, gcm_encrypt, (info->input, info->gcm_param, info->key_idx, info->output)); + break; + case SECLINKIOC_GCMDECRYPT: + SLDRV_CALL(res, req->res, gcm_decrypt, (info->input, info->gcm_param, info->key_idx, info->output)); + break; default: res = -ENOSYS; } diff --git a/os/include/tinyara/seclink.h b/os/include/tinyara/seclink.h index 13febb5703..73d40e15d6 100644 --- a/os/include/tinyara/seclink.h +++ b/os/include/tinyara/seclink.h @@ -59,6 +59,8 @@ #define SECLINKIOC_AESDECRYPT _SECLINKIOC((SECLINKIOC_CRYPTO | 0x01)) #define SECLINKIOC_RSAENCRYPT _SECLINKIOC((SECLINKIOC_CRYPTO | 0x02)) #define SECLINKIOC_RSADECRYPT _SECLINKIOC((SECLINKIOC_CRYPTO | 0x03)) +#define SECLINKIOC_GCMENCRYPT _SECLINKIOC((SECLINKIOC_CRYPTO | 0x04)) +#define SECLINKIOC_GCMDECRYPT _SECLINKIOC((SECLINKIOC_CRYPTO | 0x05)) /* Authenticate */ #define SECLINKIOC_AUTH _SECLINKIOC(0x20) @@ -135,6 +137,7 @@ struct seclink_crypto_info { hal_data *output; hal_aes_param *aes_param; hal_rsa_mode *rsa_mode; + hal_gcm_param *gcm_param; }; struct seclink_ss_info { @@ -193,6 +196,8 @@ int sl_aes_encrypt(sl_ctx hnd, hal_data *dec_data, hal_aes_param *aes_param, uin int sl_aes_decrypt(sl_ctx hnd, hal_data *enc_data, hal_aes_param *aes_param, uint32_t key_idx, _OUT_ hal_data *dec_data); int sl_rsa_encrypt(sl_ctx hnd, hal_data *dec_data, hal_rsa_mode *rsa_mode, uint32_t key_idx, _OUT_ hal_data *enc_data); int sl_rsa_decrypt(sl_ctx hnd, hal_data *enc_data, hal_rsa_mode *rsa_mode, uint32_t key_idx, _OUT_ hal_data *dec_data); +int sl_gcm_encrypt(sl_ctx hnd, hal_data *dec_data, hal_gcm_param *gcm_param, uint32_t key_idx, _OUT_ hal_data *enc_data); +int sl_gcm_decrypt(sl_ctx hnd, hal_data *enc_data, hal_gcm_param *gcm_param, uint32_t key_idx, _OUT_ hal_data *dec_data); /* Secure Storage */ int sl_write_storage(sl_ctx hnd, uint32_t ss_idx, hal_data *data); From 32bfdc75c991cb26cc455fcb210a2f16596143ef Mon Sep 17 00:00:00 2001 From: Jaeyong Lee Date: Mon, 23 Sep 2024 12:19:40 +0900 Subject: [PATCH 4/4] apps/examples/security_test: Add examples of GCM mode Add UTC and examples of GCM API Keys should be generated before encryption/decryption. Factory key is not available in GCM mode. 1) sl_crypto_test - Example of sl_gcm_encrypt / sl_gcm_decrypt 2) utc_crypto - UTC of crypto_gcm_encryption / crypto_gcm_decryption Signed-off-by: Jaeyong Lee --- .../security_test/seclink/sl_crypto_table.h | 1 + .../security_test/seclink/sl_crypto_test.c | 43 ++ .../testcase/ta_tc/security/utc/utc_crypto.c | 497 +++++++++++++++++- .../ta_tc/security/utc/utc_security.h | 1 + 4 files changed, 541 insertions(+), 1 deletion(-) diff --git a/apps/examples/security_test/seclink/sl_crypto_table.h b/apps/examples/security_test/seclink/sl_crypto_table.h index aa074199a8..c43d0744ed 100644 --- a/apps/examples/security_test/seclink/sl_crypto_table.h +++ b/apps/examples/security_test/seclink/sl_crypto_table.h @@ -20,3 +20,4 @@ SL_CRYPTO_TEST_POOL("aes_ecb", SL_CRYPTO_TYPE_AES_ECB, sl_handle_crypto_aes_ecb) SL_CRYPTO_TEST_POOL("aes_cbc", SL_CRYPTO_TYPE_AES_CBC, sl_handle_crypto_aes_cbc) SL_CRYPTO_TEST_POOL("aes_cfb128", SL_CRYPTO_TYPE_AES_CFB128, sl_handle_crypto_aes_cfb128) SL_CRYPTO_TEST_POOL("aes_ctr", SL_CRYPTO_TYPE_AES_CTR, sl_handle_crypto_aes_ctr) +SL_CRYPTO_TEST_POOL("gcm_aes", SL_CRYPTO_TYPE_GCM_AES, sl_handle_crypto_gcm_aes) diff --git a/apps/examples/security_test/seclink/sl_crypto_test.c b/apps/examples/security_test/seclink/sl_crypto_test.c index 03472c45ed..ee19e22a09 100644 --- a/apps/examples/security_test/seclink/sl_crypto_test.c +++ b/apps/examples/security_test/seclink/sl_crypto_test.c @@ -209,6 +209,44 @@ START_TEST_F(aes_ctr) } END_TEST_F +START_TEST_F(gcm_aes) +{ + hal_data aes_key = HAL_DATA_INITIALIZER; + hal_data enc = HAL_DATA_INITIALIZER; + hal_data dec = HAL_DATA_INITIALIZER; + HAL_INIT_GCM_PARAM(param); + unsigned char aad[16] = {0,}; + unsigned char tag[16] = {0,}; + aes_key.data = g_key_128; + aes_key.data_len = 16; + param.cipher = HAL_GCM_AES; + param.iv = (unsigned char *)g_iv; + param.iv_len = 16; + param.aad = aad; + param.aad_len = 16; + param.tag = tag; + param.tag_len = 16; + + enc.data = g_plaintext; + enc.data_len = 64; + dec.data = g_ciphertext; + dec.data_len = 64; + + ST_EXPECT_EQ(SECLINK_OK, sl_set_key(g_hnd, HAL_KEY_AES_128, ST_AES_ENC_KEY_IDX, &aes_key, NULL)); + ST_EXPECT_EQ(SECLINK_OK, sl_gcm_encrypt(g_hnd, &dec, ¶m, ST_AES_ENC_KEY_IDX, &enc)); + sl_test_print_buffer(enc.data, enc.data_len, "GCM-AES plaintext"); + sl_test_print_buffer(dec.data, dec.data_len, "GCM-AES ciphertext"); + sl_test_print_buffer((char *)g_iv, 16, "IV"); + sl_test_print_buffer((char *)aad, 16, "AAD"); + sl_test_print_buffer((char *)param.tag, 16, "TAG"); + + ST_EXPECT_EQ(SECLINK_OK, sl_gcm_decrypt(g_hnd, &dec, ¶m, ST_AES_ENC_KEY_IDX, &enc)); + sl_test_print_buffer(enc.data, enc.data_len, "GCM-AES plaintext (decrypted text)"); + + ST_EXPECT_EQ(SECLINK_OK, sl_remove_key(g_hnd, HAL_KEY_AES_128, ST_AES_ENC_KEY_IDX)); +} +END_TEST_F + void sl_handle_crypto_aes_ecb(sl_options *opt) { ST_SET_SMOKE1(sl_crypto, opt->count, 0, "aes test", aes_ecb); @@ -229,6 +267,11 @@ void sl_handle_crypto_aes_ctr(sl_options *opt) ST_SET_SMOKE1(sl_crypto, opt->count, 0, "aes test", aes_ctr); } +void sl_handle_crypto_gcm_aes(sl_options *opt) +{ + ST_SET_SMOKE1(sl_crypto, opt->count, 0, "gcm test", gcm_aes); +} + void sl_handle_crypto(sl_options *opt) { ST_TC_SET_GLOBAL(sl_crypto, sl_crypto_global); diff --git a/apps/examples/testcase/ta_tc/security/utc/utc_crypto.c b/apps/examples/testcase/ta_tc/security/utc/utc_crypto.c index fb842e9587..c2fce272c4 100644 --- a/apps/examples/testcase/ta_tc/security/utc/utc_crypto.c +++ b/apps/examples/testcase/ta_tc/security/utc/utc_crypto.c @@ -54,6 +54,16 @@ static security_aes_mode g_aes_mode_table[] = { AES_CTR, }; +static security_key_type g_aes_key_type_table[] = { + KEY_AES_128, + KEY_AES_192, + KEY_AES_256, +}; + +static security_gcm_mode g_gcm_mode_table[] = { + GCM_AES, +}; + static security_handle g_hnd = NULL; /** @@ -757,6 +767,478 @@ static void utc_crypto_rsa_decryption_output_n(void) TC_SUCCESS_RESULT(); } +/** + * @testcase utc_crypto_gcm_encryption_p + * @brief encrypt GCM with AES + * @scenario encrypt GCM with AES + * @apicovered crypto_gcm_encryption + * @precondition key should be set by keymgr_set_key() or keymgr_generate_key with AES type. Only AES key type is supported on GCM mode. + * @postcondition none + */ +static void utc_crypto_gcm_encryption_p(void) +{ + /* Recommanded IV length : 12 bytes */ + unsigned char iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b }; + + unsigned char plain_text[] = { 0x4d, 0x79, 0x20, 0x42, 0x79, 0x74, 0x65, 0x20, + 0x50, 0x72, 0x69, 0x6e, 0x74, 0x00, 0x00, 0x00 }; + + unsigned char aad[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; + + unsigned char tag[16] = { 0, }; + + security_data plain = { plain_text, sizeof(plain_text) }; + security_data enc = { NULL, 0 }; + + for (int gcm_mode = 0; gcm_mode < sizeof(g_gcm_mode_table) / sizeof(g_gcm_mode_table); gcm_mode++) { + /* Generate AES key for GCM encryption / decryption */ + for (int i = 0; i < sizeof(g_aes_key_type_table) / sizeof(g_aes_key_type_table); i++) { + /* Check whether hang occurs during repeated encrypt function */ + for (int iter = 0; iter < ITER_COUNT; iter++) { + security_error res = keymgr_generate_key(g_hnd, g_aes_key_type_table[i], UTC_CRYPTO_USER_KEY_NAME); + + security_gcm_mode cipher = g_aes_mode_table[gcm_mode]; + security_gcm_param param = { cipher, iv, sizeof(iv), aad, sizeof(aad), tag, sizeof(tag) }; + + res = crypto_gcm_encryption(g_hnd, ¶m, UTC_CRYPTO_USER_KEY_NAME, &plain, &enc); + TC_ASSERT_EQ("utc_crypto_gcm_encryption_p", res, SECURITY_OK); + TC_SUCCESS_RESULT(); + + res = keymgr_remove_key(g_hnd, g_aes_key_type_table[i], UTC_CRYPTO_USER_KEY_NAME); + } + } + } +} + +/** + * @testcase utc_crypto_gcm_encryption_hnd_n + * @brief encrypt GCM with AES + * @scenario encrypt GCM with AES (without handler) + * @apicovered crypto_gcm_encryption + * @precondition key should be set by keymgr_set_key() or keymgr_generate_key with AES type. Only AES key type is supported on GCM mode. + * @postcondition none + */ +static void utc_crypto_gcm_encryption_hnd_n(void) +{ + /* Recommanded IV length : 12 bytes */ + unsigned char iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b }; + + unsigned char plain_text[] = { 0x4d, 0x79, 0x20, 0x42, 0x79, 0x74, 0x65, 0x20, + 0x50, 0x72, 0x69, 0x6e, 0x74, 0x00, 0x00, 0x00 }; + + unsigned char aad[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; + + unsigned char tag[16] = { 0, }; + + security_data plain = { plain_text, sizeof(plain_text) }; + security_data enc = { NULL, 0 }; + + /* Generate AES key for GCM encryption / decryption */ + security_error res = keymgr_generate_key(g_hnd, KEY_AES_128, UTC_CRYPTO_USER_KEY_NAME); + + security_gcm_mode cipher = GCM_AES; + security_gcm_param param = { cipher, iv, sizeof(iv), aad, sizeof(aad), tag, sizeof(tag) }; + + res = crypto_gcm_encryption(NULL, ¶m, UTC_CRYPTO_USER_KEY_NAME, &plain, &enc); + TC_ASSERT_EQ("utc_crypto_gcm_encryption_hnd_n", res, SECURITY_INVALID_INPUT_PARAMS); + TC_SUCCESS_RESULT(); + + /* Remove AES key for GCM encryption / decryption */ + res = keymgr_remove_key(g_hnd, KEY_AES_128, UTC_CRYPTO_USER_KEY_NAME); +} + +/** + * @testcase utc_crypto_gcm_encryption_param_n + * @brief encrypt GCM with AES + * @scenario encrypt GCM with AES (without param) + * @apicovered crypto_gcm_encryption + * @precondition key should be set by keymgr_set_key() or keymgr_generate_key with AES type. Only AES key type is supported on GCM mode. + * @postcondition none + */ +static void utc_crypto_gcm_encryption_param_n(void) +{ + /* Recommanded IV length : 12 bytes */ + unsigned char iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b }; + + unsigned char plain_text[] = { 0x4d, 0x79, 0x20, 0x42, 0x79, 0x74, 0x65, 0x20, + 0x50, 0x72, 0x69, 0x6e, 0x74, 0x00, 0x00, 0x00 }; + + unsigned char aad[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; + + unsigned char tag[16] = { 0, }; + + security_data plain = { plain_text, sizeof(plain_text) }; + security_data enc = { NULL, 0 }; + + /* Generate AES key for GCM encryption / decryption */ + security_error res = keymgr_generate_key(g_hnd, KEY_AES_128, UTC_CRYPTO_USER_KEY_NAME); + + security_gcm_param param = { GCM_UNKNOWN, iv, sizeof(iv), aad, sizeof(aad), tag, sizeof(tag) }; + + res = crypto_gcm_encryption(g_hnd, ¶m, UTC_CRYPTO_USER_KEY_NAME, &plain, &enc); + TC_ASSERT_EQ("utc_crypto_gcm_encryption_param_n", res, SECURITY_INVALID_INPUT_PARAMS); + TC_SUCCESS_RESULT(); + + /* Remove AES key for GCM encryption / decryption */ + res = keymgr_remove_key(g_hnd, KEY_AES_128, UTC_CRYPTO_USER_KEY_NAME); +} + +/** + * @testcase utc_crypto_gcm_encryption_key_n + * @brief encrypt GCM with AES + * @scenario encrypt GCM with AES (without key) + * @apicovered crypto_gcm_encryption + * @precondition key should be set by keymgr_set_key() or keymgr_generate_key with AES type. Only AES key type is supported on GCM mode. + * @postcondition none + */ +static void utc_crypto_gcm_encryption_key_n(void) +{ + /* Recommanded IV length : 12 bytes */ + unsigned char iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b }; + + unsigned char plain_text[] = { 0x4d, 0x79, 0x20, 0x42, 0x79, 0x74, 0x65, 0x20, + 0x50, 0x72, 0x69, 0x6e, 0x74, 0x00, 0x00, 0x00 }; + + unsigned char aad[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; + + unsigned char tag[16] = { 0, }; + + security_data plain = { plain_text, sizeof(plain_text) }; + security_data enc = { NULL, 0 }; + + security_gcm_mode cipher = GCM_AES; + security_gcm_param param = { cipher, iv, sizeof(iv), aad, sizeof(aad), tag, sizeof(tag) }; + + security_error res = crypto_gcm_encryption(g_hnd, ¶m, NULL, &plain, &enc); + + TC_ASSERT_EQ("utc_crypto_gcm_encryption_key_n", res, SECURITY_INVALID_KEY_INDEX); + TC_SUCCESS_RESULT(); +} + +/** + * @testcase utc_crypto_gcm_encryption_input_n + * @brief encrypt GCM with AES + * @scenario encrypt GCM with AES (without input) + * @apicovered crypto_gcm_encryption + * @precondition key should be set by keymgr_set_key() or keymgr_generate_key with AES type. Only AES key type is supported on GCM mode. + * @postcondition none + */ +static void utc_crypto_gcm_encryption_input_n(void) +{ + /* Recommanded IV length : 12 bytes */ + unsigned char iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b }; + + unsigned char plain_text[] = { 0x4d, 0x79, 0x20, 0x42, 0x79, 0x74, 0x65, 0x20, + 0x50, 0x72, 0x69, 0x6e, 0x74, 0x00, 0x00, 0x00 }; + + unsigned char aad[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; + + unsigned char tag[16] = { 0, }; + + security_data plain = { plain_text, sizeof(plain_text) }; + security_data enc = { NULL, 0 }; + + /* Generate AES key for GCM encryption / decryption */ + security_error res = keymgr_generate_key(g_hnd, KEY_AES_128, UTC_CRYPTO_USER_KEY_NAME); + + security_gcm_mode cipher = GCM_AES; + security_gcm_param param = { cipher, iv, sizeof(iv), aad, sizeof(aad), tag, sizeof(tag) }; + + res = crypto_gcm_encryption(g_hnd, ¶m, UTC_CRYPTO_USER_KEY_NAME, NULL, &enc); + TC_ASSERT_EQ("utc_crypto_gcm_encryption_input_n", res, SECURITY_INVALID_INPUT_PARAMS); + TC_SUCCESS_RESULT(); + + /* Remove AES key for GCM encryption / decryption */ + res = keymgr_remove_key(g_hnd, KEY_AES_128, UTC_CRYPTO_USER_KEY_NAME); +} + +/** + * @testcase utc_crypto_gcm_encryption_output_n + * @brief encrypt GCM with AES + * @scenario encrypt GCM with AES (without output) + * @apicovered crypto_gcm_encryption + * @precondition key should be set by keymgr_set_key() or keymgr_generate_key with AES type. Only AES key type is supported on GCM mode. + * @postcondition none + */ +static void utc_crypto_gcm_encryption_output_n(void) +{ + /* Recommanded IV length : 12 bytes */ + unsigned char iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b }; + + unsigned char plain_text[] = { 0x4d, 0x79, 0x20, 0x42, 0x79, 0x74, 0x65, 0x20, + 0x50, 0x72, 0x69, 0x6e, 0x74, 0x00, 0x00, 0x00 }; + + unsigned char aad[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; + + unsigned char tag[16] = { 0, }; + + security_data plain = { plain_text, sizeof(plain_text) }; + security_data enc = { NULL, 0 }; + + /* Generate AES key for GCM encryption / decryption */ + security_error res = keymgr_generate_key(g_hnd, KEY_AES_128, UTC_CRYPTO_USER_KEY_NAME); + + security_gcm_mode cipher = GCM_AES; + security_gcm_param param = { cipher, iv, sizeof(iv), aad, sizeof(aad), tag, sizeof(tag) }; + + res = crypto_gcm_encryption(g_hnd, ¶m, UTC_CRYPTO_USER_KEY_NAME, &plain, NULL); + TC_ASSERT_EQ("utc_crypto_gcm_encryption_output_n", res, SECURITY_INVALID_INPUT_PARAMS); + TC_SUCCESS_RESULT(); + + /* Remove AES key for GCM encryption / decryption */ + res = keymgr_remove_key(g_hnd, KEY_AES_128, UTC_CRYPTO_USER_KEY_NAME); +} + +/** + * @testcase utc_crypto_gcm_decryption_p + * @brief decrypt GCM with AES + * @scenario decrypt GCM with AES + * @apicovered crypto_gcm_decryption + * @precondition key should be set by keymgr_set_key() or keymgr_generate_key with AES type. Only AES key type is supported on GCM mode. + * @postcondition none + */ +static void utc_crypto_gcm_decryption_p(void) +{ + /* Recommanded IV length : 12 bytes */ + unsigned char iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b }; + + unsigned char enc_text[] = { 0x4d, 0x79, 0x20, 0x42, 0x79, 0x74, 0x65, 0x20, + 0x50, 0x72, 0x69, 0x6e, 0x74, 0x00, 0x00, 0x00 }; + + unsigned char aad[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; + + unsigned char tag[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; + + security_data enc = { enc_text, sizeof(enc_text) }; + security_data dec = { NULL, 0 }; + + for (int gcm_mode = 0; gcm_mode < sizeof(g_gcm_mode_table) / sizeof(g_gcm_mode_table); gcm_mode++) { + /* Set AES key for GCM encryption / decryption */ + for (int i = 0; i < sizeof(g_aes_key_type_table) / sizeof(g_aes_key_type_table); i++) { + /* Check whether hang occurs during repeated encrypt function */ + for (int iter = 0; iter < ITER_COUNT; iter++) { + security_error res = keymgr_generate_key(g_hnd, g_aes_key_type_table[i], UTC_CRYPTO_USER_KEY_NAME); + security_gcm_mode cipher = g_aes_mode_table[gcm_mode]; + security_gcm_param param = { cipher, iv, sizeof(iv), aad, sizeof(aad), tag, sizeof(tag) }; + + res = crypto_gcm_decryption(g_hnd, ¶m, UTC_CRYPTO_USER_KEY_NAME, &enc, &dec); + TC_ASSERT_EQ("utc_crypto_gcm_decryption_p", res, SECURITY_OK); + TC_SUCCESS_RESULT(); + + res = keymgr_remove_key(g_hnd, g_aes_key_type_table[i], UTC_CRYPTO_USER_KEY_NAME); + } + } + } +} + +/** + * @testcase utc_crypto_gcm_decryption_hnd_n + * @brief decrypt GCM with AES + * @scenario decrypt GCM with AES (without handler) + * @apicovered crypto_gcm_decryption + * @precondition key should be set by keymgr_set_key() or keymgr_generate_key with AES type. Only AES key type is supported on GCM mode. + * @postcondition none + */ +static void utc_crypto_gcm_decryption_hnd_n(void) +{ + /* Recommanded IV length : 12 bytes */ + unsigned char iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b }; + + unsigned char enc_text[] = { 0x4d, 0x79, 0x20, 0x42, 0x79, 0x74, 0x65, 0x20, + 0x50, 0x72, 0x69, 0x6e, 0x74, 0x00, 0x00, 0x00 }; + + unsigned char aad[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; + + unsigned char tag[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; + + security_data enc = { enc_text, sizeof(enc_text) }; + security_data dec = { NULL, 0 }; + + /* Generate AES key for GCM encryption / decryption */ + security_error res = keymgr_generate_key(g_hnd, KEY_AES_128, UTC_CRYPTO_USER_KEY_NAME); + + security_gcm_mode cipher = GCM_AES; + security_gcm_param param = { cipher, iv, sizeof(iv), aad, sizeof(aad), tag, sizeof(tag) }; + + res = crypto_gcm_decryption(NULL, ¶m, UTC_CRYPTO_USER_KEY_NAME, &enc, &dec); + TC_ASSERT_EQ("utc_crypto_gcm_decryption_hnd_n", res, SECURITY_INVALID_INPUT_PARAMS); + TC_SUCCESS_RESULT(); + + /* Remove AES key for GCM encryption / decryption */ + res = keymgr_remove_key(g_hnd, KEY_AES_128, UTC_CRYPTO_USER_KEY_NAME); +} + +/** + * @testcase utc_crypto_gcm_decryption_param_n + * @brief decrypt GCM with AES + * @scenario decrypt GCM with AES (without param) + * @apicovered crypto_gcm_decryption + * @precondition key should be set by keymgr_set_key() or keymgr_generate_key with AES type. Only AES key type is supported on GCM mode. + * @postcondition none + */ +static void utc_crypto_gcm_decryption_param_n(void) +{ + /* Recommanded IV length : 12 bytes */ + unsigned char iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b }; + + unsigned char enc_text[] = { 0x4d, 0x79, 0x20, 0x42, 0x79, 0x74, 0x65, 0x20, + 0x50, 0x72, 0x69, 0x6e, 0x74, 0x00, 0x00, 0x00 }; + + unsigned char aad[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; + + unsigned char tag[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; + + security_data enc = { enc_text, sizeof(enc_text) }; + security_data dec = { NULL, 0 }; + + /* Generate AES key for GCM encryption / decryption */ + security_error res = keymgr_generate_key(g_hnd, KEY_AES_128, UTC_CRYPTO_USER_KEY_NAME); + + security_gcm_param param = { GCM_UNKNOWN, iv, sizeof(iv), aad, sizeof(aad), tag, sizeof(tag) }; + + res = crypto_gcm_decryption(g_hnd, ¶m, UTC_CRYPTO_USER_KEY_NAME, &enc, &dec); + TC_ASSERT_EQ("utc_crypto_gcm_decryption_param_n", res, SECURITY_INVALID_INPUT_PARAMS); + TC_SUCCESS_RESULT(); + + /* Remove AES key for GCM encryption / decryption */ + res = keymgr_remove_key(g_hnd, KEY_AES_128, UTC_CRYPTO_USER_KEY_NAME); +} + +/** + * @testcase utc_crypto_gcm_decryption_key_n + * @brief decrypt GCM with AES + * @scenario decrypt GCM with AES (without key) + * @apicovered crypto_gcm_decryption + * @precondition key should be set by keymgr_set_key() or keymgr_generate_key with AES type. Only AES key type is supported on GCM mode. + * @postcondition none + */ +static void utc_crypto_gcm_decryption_key_n(void) +{ + /* Recommanded IV length : 12 bytes */ + unsigned char iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b }; + + unsigned char enc_text[] = { 0x4d, 0x79, 0x20, 0x42, 0x79, 0x74, 0x65, 0x20, + 0x50, 0x72, 0x69, 0x6e, 0x74, 0x00, 0x00, 0x00 }; + + unsigned char aad[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; + + unsigned char tag[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; + + security_data enc = { enc_text, sizeof(enc_text) }; + security_data dec = { NULL, 0 }; + + security_gcm_mode cipher = GCM_AES; + security_gcm_param param = { cipher, iv, sizeof(iv), aad, sizeof(aad), tag, sizeof(tag) }; + + security_error res = crypto_gcm_decryption(g_hnd, ¶m, NULL, &enc, &dec); + + TC_ASSERT_EQ("utc_crypto_gcm_decryption_key_n", res, SECURITY_INVALID_KEY_INDEX); + TC_SUCCESS_RESULT(); +} + +/** + * @testcase utc_crypto_gcm_decryption_input_n + * @brief decrypt GCM with AES + * @scenario decrypt GCM with AES (without input) + * @apicovered crypto_gcm_decryption + * @precondition key should be set by keymgr_set_key() or keymgr_generate_key with AES type. Only AES key type is supported on GCM mode. + * @postcondition none + */ +static void utc_crypto_gcm_decryption_input_n(void) +{ + /* Recommanded IV length : 12 bytes */ + unsigned char iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b }; + + unsigned char enc_text[] = { 0x4d, 0x79, 0x20, 0x42, 0x79, 0x74, 0x65, 0x20, + 0x50, 0x72, 0x69, 0x6e, 0x74, 0x00, 0x00, 0x00 }; + + unsigned char aad[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; + + unsigned char tag[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; + + security_data enc = { enc_text, sizeof(enc_text) }; + security_data dec = { NULL, 0 }; + + /* Generate AES key for GCM encryption / decryption */ + security_error res = keymgr_generate_key(g_hnd, KEY_AES_128, UTC_CRYPTO_USER_KEY_NAME); + + security_gcm_mode cipher = GCM_AES; + security_gcm_param param = { cipher, iv, sizeof(iv), aad, sizeof(aad), tag, sizeof(tag) }; + + res = crypto_gcm_decryption(g_hnd, ¶m, UTC_CRYPTO_USER_KEY_NAME, NULL, &dec); + TC_ASSERT_EQ("utc_crypto_gcm_decryption_input_n", res, SECURITY_INVALID_INPUT_PARAMS); + TC_SUCCESS_RESULT(); + + /* Remove AES key for GCM encryption / decryption */ + res = keymgr_remove_key(g_hnd, KEY_AES_128, UTC_CRYPTO_USER_KEY_NAME); +} + +/** + * @testcase utc_crypto_gcm_decryption_output_n + * @brief decrypt GCM with AES + * @scenario decrypt GCM with AES (without output) + * @apicovered crypto_gcm_decryption + * @precondition key should be set by keymgr_set_key() or keymgr_generate_key with AES type. Only AES key type is supported on GCM mode. + * @postcondition none + */ +static void utc_crypto_gcm_decryption_output_n(void) +{ + /* Recommanded IV length : 12 bytes */ + unsigned char iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b }; + + unsigned char enc_text[] = { 0x4d, 0x79, 0x20, 0x42, 0x79, 0x74, 0x65, 0x20, + 0x50, 0x72, 0x69, 0x6e, 0x74, 0x00, 0x00, 0x00 }; + + unsigned char aad[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; + + unsigned char tag[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; + + security_data enc = { enc_text, sizeof(enc_text) }; + security_data dec = { NULL, 0 }; + + /* Generate AES key for GCM encryption / decryption */ + security_error res = keymgr_generate_key(g_hnd, KEY_AES_128, UTC_CRYPTO_USER_KEY_NAME); + + security_gcm_mode cipher = GCM_AES; + security_gcm_param param = { cipher, iv, sizeof(iv), aad, sizeof(aad), tag, sizeof(tag) }; + + res = crypto_gcm_decryption(g_hnd, ¶m, UTC_CRYPTO_USER_KEY_NAME, &enc, NULL); + TC_ASSERT_EQ("utc_crypto_gcm_decryption_output_n", res, SECURITY_INVALID_INPUT_PARAMS); + TC_SUCCESS_RESULT(); + + /* Remove AES key for GCM encryption / decryption */ + res = keymgr_remove_key(g_hnd, KEY_AES_128, UTC_CRYPTO_USER_KEY_NAME); +} void utc_crypto_main(void) { @@ -780,7 +1262,7 @@ void utc_crypto_main(void) utc_crypto_aes_decryption_key_n(); utc_crypto_aes_decryption_input_n(); utc_crypto_aes_decryption_output_n(); - /* RSA */ + // /* RSA */ utc_crypto_rsa_encryption_p(); utc_crypto_rsa_encryption_hnd_n(); utc_crypto_rsa_encryption_param_n(); @@ -795,6 +1277,19 @@ void utc_crypto_main(void) utc_crypto_rsa_decryption_param3_n(); utc_crypto_rsa_decryption_input_n(); utc_crypto_rsa_decryption_output_n(); + /* GCM */ + utc_crypto_gcm_encryption_p(); + utc_crypto_gcm_encryption_hnd_n(); + utc_crypto_gcm_encryption_param_n(); + utc_crypto_gcm_encryption_key_n(); + utc_crypto_gcm_encryption_input_n(); + utc_crypto_gcm_encryption_output_n(); + utc_crypto_gcm_decryption_p(); + utc_crypto_gcm_decryption_hnd_n(); + utc_crypto_gcm_decryption_param_n(); + utc_crypto_gcm_decryption_key_n(); + utc_crypto_gcm_decryption_input_n(); + utc_crypto_gcm_decryption_output_n(); res = security_deinit(g_hnd); if (res != SECURITY_OK) { diff --git a/apps/examples/testcase/ta_tc/security/utc/utc_security.h b/apps/examples/testcase/ta_tc/security/utc/utc_security.h index 689c3b75db..82f2579025 100644 --- a/apps/examples/testcase/ta_tc/security/utc/utc_security.h +++ b/apps/examples/testcase/ta_tc/security/utc/utc_security.h @@ -5,6 +5,7 @@ #define UTC_CRYPTO_KEY_NAME "ss/01" #define UTC_CERT_NAME "ss/02" +#define UTC_CRYPTO_USER_KEY_NAME "ss/32" /* Debugging */ #define US_ERROR \