diff --git a/libraries/SE05X/examples/SE05XAESEncryptandDecrypt/SE05XAESEncryptandDecrypt.ino b/libraries/SE05X/examples/SE05XAESEncryptandDecrypt/SE05XAESEncryptandDecrypt.ino new file mode 100644 index 00000000..e163f7d8 --- /dev/null +++ b/libraries/SE05X/examples/SE05XAESEncryptandDecrypt/SE05XAESEncryptandDecrypt.ino @@ -0,0 +1,56 @@ +/* + SE05X AES Encrypt and Decrypt + + This sketch uses the SE05X to encrypt and decrypt given data + with an AES key, which was uploaded in the SE05XWriteAESKey + example. This sketch encrypts 32 bytes with AES ECB Mode + and then decrypt this data for comparing the results. + + Circuit: + - Portenta C33 +*/ + +#include + + +const int AES_KEY_ID = 666; +const byte data[32] = { + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f +}; + + +void print_hex(const byte in[], size_t len) { + for (size_t i = 0; i < len; i++) { + Serial.print(in[i] >> 4, HEX); + Serial.print(in[i] & 0x0f, HEX); + } + Serial.println(); +} + +void setup() { + Serial.begin(9600); + while (!Serial); + + + if (!SE05X.begin()) { + Serial.println("Error with secure element"); + while(1); + } + + + size_t encrypted_data_len = 32; + size_t decrypted_data_len = 32; + byte encrypted_data[32]; + byte decrypted_data[32]; + + int status1 = SE05X.AES_ECB_encrypt(AES_KEY_ID, data, sizeof(data), encrypted_data, &encrypted_data_len); + int status2 = SE05X.AES_ECB_decrypt(AES_KEY_ID, encrypted_data, sizeof(data), decrypted_data, &decrypted_data_len); + print_hex(data,32); + print_hex(encrypted_data,32); + print_hex(decrypted_data,32); +} + +void loop() { + +} \ No newline at end of file diff --git a/libraries/SE05X/examples/SE05XAESWriteKey/SE05XAESWriteKey.ino b/libraries/SE05X/examples/SE05XAESWriteKey/SE05XAESWriteKey.ino new file mode 100644 index 00000000..b17e8aaa --- /dev/null +++ b/libraries/SE05X/examples/SE05XAESWriteKey/SE05XAESWriteKey.ino @@ -0,0 +1,33 @@ +/* + SE05X WriteAESKey + + This sketch uses the SE05X to securely store an AES key. When the key is uploaded to + SE05X, the sketch on the Arduino should be overwritten. + + Circuit: + - Portenta C33 +*/ + +#include + +const int AES_KEY_ID = 666; +const byte aes_key[32] = { + 0xFF, 0x33, 0xFF, 0x33, 0xFF, 0x33, 0xFF, 0x33, 0xFF, 0x33, 0xFF, 0x33, 0x33, 0x33, 0xFF, 0x33, + 0xFF, 0x33, 0xFF, 0x33, 0xFF, 0x33, 0xFF, 0x33, 0xFF, 0x33, 0xFF, 0x33, 0x33, 0x33, 0xFF, 0x44 +}; + +void setup() { + Serial.begin(9600); + + if (!SE05X.begin()) { + Serial.println("Error with secure element"); + while(1); + } + + SE05X.deleteBinaryObject(AES_KEY_ID); + SE05X.writeAESKey(AES_KEY_ID, aes_key, sizeof(aes_key)); +} + +void loop() { + +} diff --git a/libraries/SE05X/examples/SE05XHMAC/SE05XHMAC.ino b/libraries/SE05X/examples/SE05XHMAC/SE05XHMAC.ino new file mode 100644 index 00000000..31dba381 --- /dev/null +++ b/libraries/SE05X/examples/SE05XHMAC/SE05XHMAC.ino @@ -0,0 +1,54 @@ +/* + SE05X HMAC + + This sketch uses the SE05X to securely store and use an HMAC Key + and calculates the HMAC-SHA512 sum of a given message + + Circuit: + - Portenta C33 +*/ + +#include + +const int HMAC_KEY_ID = 667; +const byte hmac_key[32] = { + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F +}; + + +void print_hex(const byte in[], size_t len) { + for (size_t i = 0; i < len; i++) { + Serial.print(in[i] >> 4, HEX); + Serial.print(in[i] & 0x0f, HEX); + } + Serial.println(); +} + +void setup() { + Serial.begin(9600); + while (!Serial); + + if (!SE05X.begin()) { + Serial.println("Error with secure element"); + while(1); + } + + SE05X.deleteBinaryObject(HMAC_KEY_ID); //remove key if already exists + + SE05X.writeHMACKey(HMAC_KEY_ID, hmac_key, sizeof(hmac_key)); + String message = "This is a test for the Arduino Portenta C33 to test HMAC with SHA512 algorithm. This are some bytes of data, which should work"; + + + byte buffer[64]; + for(int i = 0; i < 64; i++) + buffer[i] = 0; + + size_t len = 64; // 64 byte = 512 bit, length for SHA512 + SE05X.HMAC_Generate(HMAC_KEY_ID, kSE05x_MACAlgo_HMAC_SHA512, (const byte*)message.c_str(), message.length(), buffer, &len); + print_hex(buffer,len); +} + +void loop() { + +} diff --git a/libraries/SE05X/src/SE05X.cpp b/libraries/SE05X/src/SE05X.cpp index 30e82e93..43801665 100644 --- a/libraries/SE05X/src/SE05X.cpp +++ b/libraries/SE05X/src/SE05X.cpp @@ -595,6 +595,97 @@ int SE05XClass::readSlot(int slot, byte data[], int length) return readBinaryObject(slot, data, length, &size); } +int SE05XClass::AES_ECB_encrypt(int objectId, const byte data[], size_t data_length, byte output[], size_t *output_len) +{ + smStatus_t status; + status = Se05x_API_CipherOneShot(&_se05x_session, objectId, kSE05x_CipherMode_AES_ECB_NOPAD, data, data_length, 0, 0, output, output_len, kSE05x_Cipher_Oper_OneShot_Encrypt); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_CipherOneShot \n"); + return 0; + } + return 1; +} + +int SE05XClass::AES_ECB_decrypt(int objectId, const byte data[], size_t data_length, byte output[], size_t *output_len) +{ + smStatus_t status; + status = Se05x_API_CipherOneShot(&_se05x_session, objectId, kSE05x_CipherMode_AES_ECB_NOPAD, data, data_length, 0, 0, output, output_len, kSE05x_Cipher_Oper_OneShot_Decrypt); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_CipherOneShot \n"); + return 0; + } + return 1; +} + +int SE05XClass::writeAESKey(int objectId, const byte data[], size_t length) +{ + smStatus_t status; + SE05x_Result_t result; + uint16_t offset = 0; + uint16_t size; + + status = Se05x_API_CheckObjectExists(&_se05x_session, objectId, &result); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_CheckObjectExists \n"); + return 0; + } + + if (result == kSE05x_Result_SUCCESS) { + SMLOG_E("Object exists \n"); + return 0; + } + + uint16_t left = length; + + status = Se05x_API_WriteSymmKey(&_se05x_session, NULL, 3, objectId, NULL, data, length, kSE05x_INS_NA, kSE05x_SymmKeyType_AES); + + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_WriteSymmKey \n"); + return 0; + } + return 1; +} + +int SE05XClass::writeHMACKey(int objectId, const byte data[], size_t length) +{ + smStatus_t status; + SE05x_Result_t result; + uint8_t exists = 0; + uint16_t offset = 0; + uint16_t size; + + status = Se05x_API_CheckObjectExists(&_se05x_session, objectId, &result); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_CheckObjectExists \n"); + return 0; + } + + if (result == kSE05x_Result_SUCCESS) { + SMLOG_E("Object exists \n"); + exists = 1; + } + + status = Se05x_API_WriteSymmKey(&_se05x_session, NULL, 0, objectId, SE05x_KeyID_KEK_NONE, data, length, kSE05x_INS_NA, kSE05x_SymmKeyType_HMAC); + + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_WriteSymmKey \n"); + return 0; + } + return 1; +} + +int SE05XClass::HMAC_Generate(int objectId, uint8_t mac_operation, const byte data[], size_t data_length, byte output[], size_t *output_len) +{ + smStatus_t status; + status = Se05x_API_MACOneShot_G(&_se05x_session, objectId, mac_operation, data, data_length, output, output_len); + + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_CipherOneShot \n"); + return status; + } + return 1; +} + int SE05XClass::writeBinaryObject(int objectId, const byte data[], size_t length) { smStatus_t status; @@ -668,7 +759,7 @@ int SE05XClass::deleteBinaryObject(int objectId) status = Se05x_API_DeleteSecureObject(&_se05x_session, objectId); if (status != SM_OK) { - SMLOG_E("Error in Se05x_API_CheckObjectExists \n"); + SMLOG_E("Error in Se05x_API_DeleteSecureObject \n"); return 0; } diff --git a/libraries/SE05X/src/SE05X.h b/libraries/SE05X/src/SE05X.h index 149414b0..0ed95a60 100644 --- a/libraries/SE05X/src/SE05X.h +++ b/libraries/SE05X/src/SE05X.h @@ -194,6 +194,74 @@ class SE05XClass */ int readBinaryObject(int ObjectId, byte data[], size_t dataMaxLen, size_t* length); + /** AES_ECB_encrypt + * + * Enrypts something with AES ECB + * + * @param[in] ObjectId SE050 object ID + * @param[in] data Input data buffer + * @param[in] length Input data buffer size (should be a multiple of 16 bytes) + * @param[out] output Output data buffer + * @param[out] output_length Output data buffer size (same as input) + * + * @return 0 on Failure 1 on Success + */ + int AES_ECB_encrypt(int objectId, const byte data[], size_t data_length, byte output[], size_t *output_len); + + /** AES_ECB_decrypt + * + * Enrypts something with AES ECB + * + * @param[in] ObjectId SE050 object ID + * @param[in] data Input data buffer + * @param[in] length Input data buffer size (should be a multiple of 16 bytes) + * @param[out] output Output data buffer + * @param[out] output_length Output data buffer size (same as input) + * + * @return 0 on Failure 1 on Success + */ + int AES_ECB_decrypt(int objectId, const byte data[], size_t data_length, byte output[], size_t *output_len); + + /** writeAESKey + * + * Writes symmetric key into SE050 object. + * + * @param[in] ObjectId SE050 object ID + * @param[in] data Input data buffer + * @param[in] length Input data buffer size + * + * @return 0 on Failure 1 on Success + */ + int writeAESKey(int ObjectId, const byte data[], size_t length); + + /** writeHMACKey + * + * Writes symmetric key into SE050 object. + * + * @param[in] ObjectId SE050 object ID for the hmac key + * @param[in] data Input data buffer + * @param[in] length Input data buffer size + * + * @return 0 on Failure 1 on Success + */ + int writeHMACKey(int ObjectId, const byte data[], size_t length); + + /** HMAC_Generate + * + * Computes the HMAC digest with SE050 chip + * + * @param[in] objectId SE050 object ID for the hmac key + * @param[in] mac_operation Type of Hash function for HMAC + * @param[in] data Input data buffer + * @param[in] length Input data buffer size + * @param[out] output Output data buffer + * @param[out] output_length Output data buffer size (should be 32 bytes for SHA256) + * + * @return 0 on Failure 1 on Success + */ + int HMAC_Generate(int objectId, uint8_t mac_operation, const byte data[], size_t data_length, byte output[], size_t *output_len); + + /** writeBinaryObject * * Writes binary data into SE050 object. diff --git a/libraries/SE05X/src/lib/apdu/se05x_APDU_apis.h b/libraries/SE05X/src/lib/apdu/se05x_APDU_apis.h index 2550d6e5..cb4c7097 100644 --- a/libraries/SE05X/src/lib/apdu/se05x_APDU_apis.h +++ b/libraries/SE05X/src/lib/apdu/se05x_APDU_apis.h @@ -1104,6 +1104,84 @@ smStatus_t Se05x_API_DigestOneShot(pSe05xSession_t session_ctx, uint8_t *hashValue, size_t *phashValueLen); + +/** Se05x_API_MACOneShot_G + * + * Generate. See @ref Se05x_API_MACOneShot_V for Verfiication. + * + * Performs a MAC operation in one shot (without keeping state). + * + * The 4-byte identifier of the key must refer to an AESKey, DESKey or HMACKey. + * + * # Command to Applet + * + * @rst + * +---------+------------------------+---------------------------------------------+ + * | Field | Value | Description | + * +=========+========================+=============================================+ + * | CLA | 0x80 | | + * +---------+------------------------+---------------------------------------------+ + * | INS | INS_CRYPTO | :cpp:type:`SE05x_INS_t` | + * +---------+------------------------+---------------------------------------------+ + * | P1 | P1_MAC | See :cpp:type:`SE05x_P1_t` | + * +---------+------------------------+---------------------------------------------+ + * | P2 | P2_GENERATE_ONESHOT or | See :cpp:type:`SE05x_P2_t` | + * | | P2_VALIDATE_ONESHOT | | + * +---------+------------------------+---------------------------------------------+ + * | Lc | #(Payload) | | + * +---------+------------------------+---------------------------------------------+ + * | Payload | TLV[TAG_1] | 4-byte identifier of the key object. | + * +---------+------------------------+---------------------------------------------+ + * | | TLV[TAG_2] | 1-byte :cpp:type:`MACAlgoRef` | + * +---------+------------------------+---------------------------------------------+ + * | | TLV[TAG_3] | Byte array containing data to be taken as | + * | | | input to MAC. | + * +---------+------------------------+---------------------------------------------+ + * | | TLV[TAG_5] | MAC to verify (when P2=P2_VALIDATE_ONESHOT) | + * +---------+------------------------+---------------------------------------------+ + * | Le | 0x00 | Expecting MAC or Result. | + * +---------+------------------------+---------------------------------------------+ + * @endrst + * + * # R-APDU Body + * + * @rst + * +------------+---------------------------------------+ + * | Value | Description | + * +============+=======================================+ + * | TLV[TAG_1] | MAC value (P2=P2_GENERATE_ONESHOT) or | + * | | :cpp:type:`SE05x_Result_t` (when | + * | | p2=P2_VALIDATE_ONESHOT). | + * +------------+---------------------------------------+ + * @endrst + * + * # R-APDU Trailer + * + * @rst + * +-------------+--------------------------------------+ + * | SW | Description | + * +=============+======================================+ + * | SW_NO_ERROR | The command is handled successfully. | + * +-------------+--------------------------------------+ + * @endrst + * + * @param[in] session_ctx Session Context [0:kSE05x_pSession] + * @param[in] objectID objectID [1:kSE05x_TAG_1] + * @param[in] macOperation macOperation [2:kSE05x_TAG_2] + * @param[in] inputData inputData [3:kSE05x_TAG_3] + * @param[in] inputDataLen Length of inputData + * @param[out] macValue [0:kSE05x_TAG_1] + * @param[in,out] pmacValueLen Length for macValue + */ +smStatus_t Se05x_API_MACOneShot_G(pSe05xSession_t session_ctx, + uint32_t objectID, + uint8_t macOperation, + const uint8_t *inputData, + size_t inputDataLen, + uint8_t *macValue, + size_t *pmacValueLen); + + /** Se05x_API_CreateCryptoObject * * Creates a Crypto Object on the SE05X . Once the Crypto Object is created, it diff --git a/libraries/SE05X/src/lib/apdu/se05x_APDU_impl.c b/libraries/SE05X/src/lib/apdu/se05x_APDU_impl.c index 3de6bd42..344df1e9 100644 --- a/libraries/SE05X/src/lib/apdu/se05x_APDU_impl.c +++ b/libraries/SE05X/src/lib/apdu/se05x_APDU_impl.c @@ -854,6 +854,62 @@ smStatus_t Se05x_API_DigestOneShot(pSe05xSession_t session_ctx, return retStatus; } + +smStatus_t Se05x_API_MACOneShot_G(pSe05xSession_t session_ctx, + uint32_t objectID, + uint8_t macOperation, + const uint8_t *inputData, + size_t inputDataLen, + uint8_t *macValue, + size_t *pmacValueLen) +{ + smStatus_t retStatus = SM_NOT_OK; + tlvHeader_t hdr = {{kSE05x_CLA, kSE05x_INS_CRYPTO, kSE05x_P1_MAC, kSE05x_P2_GENERATE_ONESHOT}}; + size_t cmdbufLen = 0; + uint8_t *pCmdbuf = NULL; + int tlvRet = 0; + uint8_t *pRspbuf = NULL; + size_t rspbufLen = 0; + + ENSURE_OR_GO_CLEANUP(session_ctx != NULL); + + SMLOG_D("APDU - Se05x_API_MACOneShot_G [] \n"); + + pCmdbuf = &session_ctx->apdu_buffer[0]; + pRspbuf = &session_ctx->apdu_buffer[0]; + rspbufLen = sizeof(session_ctx->apdu_buffer); + + tlvRet = TLVSET_U32("objectID", &pCmdbuf, &cmdbufLen, kSE05x_TAG_1, objectID); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_U8("macOperation", &pCmdbuf, &cmdbufLen, kSE05x_TAG_2, macOperation); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_u8bufOptional("inputData", &pCmdbuf, &cmdbufLen, kSE05x_TAG_3, inputData, inputDataLen); + if (0 != tlvRet) { + goto cleanup; + } + retStatus = DoAPDUTxRx(session_ctx, &hdr, session_ctx->apdu_buffer, cmdbufLen, pRspbuf, &rspbufLen, 0); + + if (retStatus == SM_OK) { + retStatus = SM_NOT_OK; + size_t rspIndex = 0; + tlvRet = tlvGet_u8buf(pRspbuf, &rspIndex, rspbufLen, kSE05x_TAG_1, macValue, pmacValueLen); + if (0 != tlvRet) { + goto cleanup; + } + if ((rspIndex + 2) == rspbufLen) { + retStatus = (smStatus_t)((pRspbuf[rspIndex] << 8) | (pRspbuf[rspIndex + 1])); + } + } + +cleanup: + return retStatus; +} + + smStatus_t Se05x_API_CreateCryptoObject(pSe05xSession_t session_ctx, SE05x_CryptoObjectID_t cryptoObjectID, SE05x_CryptoContext_t cryptoContext, diff --git a/libraries/SE05X/src/lib/apdu/se05x_types.h b/libraries/SE05X/src/lib/apdu/se05x_types.h index c16fad9a..876094d8 100644 --- a/libraries/SE05X/src/lib/apdu/se05x_types.h +++ b/libraries/SE05X/src/lib/apdu/se05x_types.h @@ -198,6 +198,8 @@ typedef enum kSE05x_P2_DH = 0x0F, kSE05x_P2_ENCRYPT_ONESHOT = 0x37, kSE05x_P2_DECRYPT_ONESHOT = 0x38, + kSE05x_P2_GENERATE_ONESHOT = 0x45, + kSE05x_P2_VALIDATE_ONESHOT = 0x46, kSE05x_P2_RANDOM = 0x49, kSE05x_P2_SCP = 0x52, } SE05x_P2_t;