Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

crypto: add support for AES CCM #2579

Merged
merged 5 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
ESP32: add setIP and setAPIP
Graphics.wrapString fix issue with missing final char if immediately after a '.' or other char we can split after (#2572)
Graphics: g.dump/asBMP can now output 16 bit images
Crypto: Add support for AES CCM

2v24 : Bangle.js2: Add 'Bangle.touchRd()', 'Bangle.touchWr()'
Bangle.js2: After Bangle.showTestScreen, put Bangle.js into a hard off state (not soft off)
Expand Down
1 change: 1 addition & 0 deletions boards/BANGLEJS2.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
'TERMINAL',
'GRAPHICS',
'CRYPTO','SHA256','SHA512',
'AES_CCM',
'LCD_MEMLCD',
'TENSORFLOW',
'JIT' # JIT compiler enabled
Expand Down
1 change: 1 addition & 0 deletions boards/EMSCRIPTEN2.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
'LCD_MEMLCD',
# 'FILESYSTEM',
'CRYPTO','SHA256','SHA512',
'AES_CCM',
# 'TLS',
# 'TELNET',
],
Expand Down
1 change: 1 addition & 0 deletions boards/LINUX.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
'GRAPHICS',
'FILESYSTEM',
'CRYPTO','SHA256','SHA512',
'AES_CCM',
'TLS',
'TELNET',
],
Expand Down
134 changes: 134 additions & 0 deletions libs/crypto/jswrap_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
#ifdef USE_AES
#include "mbedtls/aes.h"
#endif
#ifdef USE_AES_CCM
#include "mbedtls/ccm.h"
#endif
#ifndef USE_SHA1_JS
#include "mbedtls/sha1.h"
#endif
Expand Down Expand Up @@ -92,6 +95,9 @@ const char *jswrap_crypto_error_to_str(int err) {
case MBEDTLS_ERR_MD_BAD_INPUT_DATA: return "Bad input data";
#ifdef USE_AES
case MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH: return "Invalid input length";
#endif
#ifdef USE_AES_CCM
case MBEDTLS_ERR_CCM_AUTH_FAILED: return "Authenticated decryption failed";
#endif
}
return 0;
Expand Down Expand Up @@ -485,3 +491,131 @@ JsVar *jswrap_crypto_AES_decrypt(JsVar *message, JsVar *key, JsVar *options) {
return jswrap_crypto_AEScrypt(message, key, options, false);
}
#endif

#ifdef USE_AES_CCM
// if encrypting, tagArg is tag length
// if decrypting, tagArg is tag that came with the message
JsVar *jswrap_crypto_AES_ccmCrypt(JsVar *message, JsVar *key, JsVar *iv, JsVar *tagArg, bool encrypt) {
unsigned char ivVal[13];
memset(ivVal, 0, sizeof(ivVal));
int ivLenVal = 0;
if (jsvIsArray(iv) || jsvIsArrayBuffer(iv)){
jsvIterateCallbackToBytes(iv, ivVal, sizeof(ivVal));
ivLenVal = jsvGetLength(iv);
if (ivLenVal < 2 || ivLenVal > sizeof(ivVal)) {
jswrap_crypto_error(MBEDTLS_ERR_MD_BAD_INPUT_DATA);
return NULL;
}
} else {
jswrap_crypto_error(MBEDTLS_ERR_MD_BAD_INPUT_DATA);
return NULL;
}

JSV_GET_AS_CHAR_ARRAY(messagePtr, messageLen, message);
if (!messagePtr) return NULL;

JSV_GET_AS_CHAR_ARRAY(keyPtr, keyLen, key);
if (!keyPtr) return NULL;

char *outMessagePtr = NULL;
JsVar *outVar = jsvNewArrayBufferWithPtr(messageLen, &outMessagePtr);
if (!outMessagePtr) return NULL;

int err = 0;
mbedtls_ccm_context ctx;
mbedtls_ccm_init(&ctx);
err = mbedtls_ccm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, (unsigned char*)keyPtr, (unsigned int)keyLen*8);
if (err == 0) {
if (encrypt) {
// encrypt and generate tag
int tagLenVal = 0;
if (jsvIsNumeric(tagArg)) {
tagLenVal = jsvGetInteger(tagArg);
} else {
err = MBEDTLS_ERR_MD_BAD_INPUT_DATA;
}
if (err == 0) {
if (tagLenVal < 4 || tagLenVal > 16 || tagLenVal % 2 != 0) {
// invalid tag length; must be one of 4, 6, 8, 10, 12, 14 or 16
err = MBEDTLS_ERR_MD_BAD_INPUT_DATA;
}
}
if (err == 0) {
unsigned char tag[tagLenVal];
memset(tag, 0, sizeof(tag));
err = mbedtls_ccm_encrypt_and_tag(&ctx, messageLen, ivVal, ivLenVal, NULL, 0, (unsigned char*)messagePtr, (unsigned char*)outMessagePtr, tag, sizeof(tag));
if (err == 0) {
JsVar *outMessageVar = outVar;
outVar = jsvNewObject();
jsvObjectSetChildAndUnLock(outVar, "data", outMessageVar);
jsvObjectSetChildAndUnLock(outVar, "tag", jsvNewArrayBufferWithData(tagLenVal, tag));
}
}
} else {
// decrypt and check tag
JSV_GET_AS_CHAR_ARRAY(tagPtr, tagLen, tagArg);
if (!tagPtr) {
err = MBEDTLS_ERR_MD_BAD_INPUT_DATA;
}
if (err == 0) {
err = mbedtls_ccm_auth_decrypt(&ctx, messageLen, ivVal, ivLenVal, NULL, 0, (unsigned char*)messagePtr, (unsigned char*)outMessagePtr, (unsigned char*)tagPtr, tagLen);
}
}
}
mbedtls_ccm_free(&ctx);

if (err == 0) {
return outVar;
} else {
jswrap_crypto_error(err);
jsvUnLock(outVar);
return NULL;
}
}

/*TYPESCRIPT
type AES_CCM_EncryptResult = {
data: ArrayBuffer,
tag: ArrayBuffer,
};
*/

/*JSON{
"type" : "staticmethod",
"class" : "AES",
"name" : "ccmEncrypt",
"generate" : "jswrap_crypto_AES_ccmEncrypt",
"params" : [
["message","JsVar","Message to encrypt"],
["key","JsVar","Key to encrypt message - must be an `ArrayBuffer` of 128, 192, or 256 BITS"],
["iv","JsVar","nonce (initialization vector) - must be an `ArrayBuffer` of 2 to 13 bytes"],
["tagLen","JsVar","Length of tag to generate in bytes - must be one of 4, 6, 8, 10, 12, 14 or 16"]
],
"return" : ["JsVar","An object"],
"return_object" : "AES_CCM_EncryptResult",
"ifdef" : "USE_AES_CCM"
}
*/
JsVar *jswrap_crypto_AES_ccmEncrypt(JsVar *message, JsVar *key, JsVar *iv, JsVar *tagLen) {
return jswrap_crypto_AES_ccmCrypt(message, key, iv, tagLen, true);
}

/*JSON{
"type" : "staticmethod",
"class" : "AES",
"name" : "ccmDecrypt",
"generate" : "jswrap_crypto_AES_ccmDecrypt",
"params" : [
["message","JsVar","Message to decrypt"],
["key","JsVar","Key to decrypt message - must be an `ArrayBuffer` of 128, 192, or 256 BITS"],
["iv","JsVar","Nonce (initialization vector) - must be an `ArrayBuffer` of 2 to 13 bytes"],
["tag","JsVar","Tag that came with the message - must be an `ArrayBuffer`"]
],
"return" : ["JsVar","Decrypted message, or null on error (for example if the tag doesn't match)"],
"ifdef" : "USE_AES_CCM"
}
*/
JsVar *jswrap_crypto_AES_ccmDecrypt(JsVar *message, JsVar *key, JsVar *iv, JsVar *tag) {
return jswrap_crypto_AES_ccmCrypt(message, key, iv, tag, false);
}
#endif
4 changes: 4 additions & 0 deletions libs/crypto/jswrap_crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,7 @@ JsVar *jswrap_crypto_PBKDF2(JsVar *passphrase, JsVar *salt, JsVar *options);
JsVar *jswrap_crypto_AES_encrypt(JsVar *message, JsVar *key, JsVar *options);
JsVar *jswrap_crypto_AES_decrypt(JsVar *message, JsVar *key, JsVar *options);
#endif
#ifdef USE_AES_CCM
JsVar *jswrap_crypto_AES_ccmEncrypt(JsVar *message, JsVar *key, JsVar *iv, JsVar *tagLen);
JsVar *jswrap_crypto_AES_ccmDecrypt(JsVar *message, JsVar *key, JsVar *iv, JsVar *tag);
#endif
9 changes: 9 additions & 0 deletions libs/crypto/mbedtls/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@

#endif

#ifdef USE_AES
/* common mbed TLS feature support */
#define MBEDTLS_CIPHER_MODE_CBC
#define MBEDTLS_CIPHER_MODE_CFB
Expand All @@ -98,6 +99,7 @@
#define MBEDTLS_MD_C
#define MBEDTLS_OID_C
#define MBEDTLS_PKCS5_C
#endif
#ifndef USE_SHA1_JS
#define MBEDTLS_SHA1_C
#endif
Expand All @@ -107,6 +109,13 @@
#ifdef USE_SHA512
#define MBEDTLS_SHA512_C
#endif
#ifdef USE_AES_CCM
#define MBEDTLS_CCM_C
#ifndef USE_AES
#define MBEDTLS_AES_C
#define MBEDTLS_CIPHER_C
#endif
#endif

#include "jsvar.h"

Expand Down
11 changes: 11 additions & 0 deletions make/crypto/default.make
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,14 @@ libs/crypto/mbedtls/library/md_wrap.c \
libs/crypto/mbedtls/library/oid.c \
libs/crypto/mbedtls/library/pkcs5.c
endif
ifdef USE_AES_CCM
DEFINES += -DUSE_AES_CCM
SOURCES += \
libs/crypto/mbedtls/library/ccm.c
ifndef USE_AES
SOURCES += \
libs/crypto/mbedtls/library/aes.c \
libs/crypto/mbedtls/library/cipher.c \
libs/crypto/mbedtls/library/cipher_wrap.c
endif
endif
Loading