diff --git a/src/se05x-aes-key.c b/src/se05x-aes-key.c index a39aff2467c8802cf82a9179ea8bb3a347e49624..9f6af8034eb9f5eacf4090bf649fe7a29fe3599c 100644 --- a/src/se05x-aes-key.c +++ b/src/se05x-aes-key.c @@ -22,6 +22,7 @@ static ex_sss_boot_ctx_t gex_sss_symmetric_boot_ctx; #define MAX_FILE_NAME_SIZE 255 #define MAX_BYTE_LENGTH 32 +#define AES_IV_LENGTH 16 /* ************************************************************************** */ /* Include "main()" with the platform specific startup code for Plug & Trust */ @@ -64,7 +65,7 @@ static int hex2uint(char *hexarr, uint8_t *bytearr, int lenchararr) { static int uint2hex(uint8_t *bytearr, char *hexarr, int lenbytearr) { int i; for (i = 0; i < lenbytearr; i++) { - /* Use sprintf (0 termination is overwritten until write) */ + /* Use sprintf (0 termination is overwritten until last byte) */ sprintf(&hexarr[i * 2], "%02x", bytearr[i]); } return 0; @@ -73,12 +74,17 @@ static int uint2hex(uint8_t *bytearr, char *hexarr, int lenbytearr) { static void usage() { LOG_W("Usage:"); - LOG_W("Write AES key to SE"); - LOG_W("\t ex_aeskey setkey <key-id> <input-file> <i2c-dev>"); - LOG_W("Get AES key from SE"); - LOG_W("\t ex_aeskey getkey <key-id> <ouput-file> <i2c-dev>"); + LOG_W("Write AES key to SE as binary"); + LOG_W("\t se05x-aes-key setbinkey <key-id> <input-file> <i2c-dev>"); + LOG_W("Get AES key from SE (stored as binary)"); + LOG_W("\t se05x-aes-key getbinkey <key-id> <ouput-file> <i2c-dev>"); LOG_W("Erase key from SE"); - LOG_W("\t ex_aeskey erasekey <key-id> <i2c-dev>"); + LOG_W("\t se05x-aes-key erasekey <key-id> <i2c-dev>"); + LOG_W("Write AES key to SE"); + LOG_W("\t se05x-aes-key setaeskey <key-id> <input-file> <i2c-dev>"); + LOG_W("Decrypt file with AES key"); + LOG_W("\t se05x-aes-key decryptaes <key-id> <iv-file> <input-file>" + " <ouput-file> <i2c-dev>"); } sss_status_t ex_sss_entry(ex_sss_boot_ctx_t *pCtx) @@ -86,11 +92,19 @@ sss_status_t ex_sss_entry(ex_sss_boot_ctx_t *pCtx) sss_status_t status = kStatus_SSS_Success; int argc = gex_sss_argc; const char **argv = gex_sss_argv; - int setkey = 0; - int getkey = 0; + int setbinkey = 0; + int getbinkey = 0; int erasekey = 0; + int setaeskey = 0; + int decryptaes = 0; char filepath[MAX_FILE_NAME_SIZE] = {0}; FILE *keyfile = NULL; + FILE *encfile = NULL; + FILE *decfile = NULL; + FILE *ivfile = NULL; + long fsize = 0; + uint8_t *encdata = NULL; + uint8_t *decdata = NULL; uint32_t keyid = 0; sss_key_part_t keyPart; sss_cipher_type_t cipherType; @@ -98,17 +112,12 @@ sss_status_t ex_sss_entry(ex_sss_boot_ctx_t *pCtx) size_t keyByteLenMax = MAX_BYTE_LENGTH; uint8_t keydata[MAX_BYTE_LENGTH] = {0}; char chexdata[MAX_BYTE_LENGTH * 2 + 1] = {0}; + sss_symmetric_t ctx_symm_decrypt = { 0 }; + char civdata[AES_IV_LENGTH * 2] = {0}; + uint8_t ivdata[AES_IV_LENGTH] = {0x00}; + size_t ivlen = 0; keyPart = kSSS_KeyPart_Default; - /* - * We set the cipherType to binary for now, because the AES type - * does not allow to read out the key again. - * It may be possible to inject readable AES by parsing modified - * policies. - */ - //cipherType = kSSS_CipherType_AES; - cipherType = kSSS_CipherType_Binary; - /* Evaluate arguments */ if (argc < 2) { @@ -116,12 +125,16 @@ sss_status_t ex_sss_entry(ex_sss_boot_ctx_t *pCtx) goto cleanup; } - if (strncmp(argv[1], "setkey", sizeof("setkey")) == 0) { - setkey = 1; - } else if (strncmp(argv[1], "getkey", sizeof("getkey")) == 0) { - getkey = 1; + if (strncmp(argv[1], "setbinkey", sizeof("setbinkey")) == 0) { + setbinkey = 1; + } else if (strncmp(argv[1], "getbinkey", sizeof("getbinkey")) == 0) { + getbinkey = 1; } else if (strncmp(argv[1], "erasekey", sizeof("erasekey")) == 0) { erasekey = 1; + } else if (strncmp(argv[1], "setaeskey", sizeof("setaeskey")) == 0) { + setaeskey = 1; + } else if (strncmp(argv[1], "decryptaes", sizeof("decryptaes")) == 0) { + decryptaes = 1; } else { usage(); goto cleanup; @@ -130,10 +143,10 @@ sss_status_t ex_sss_entry(ex_sss_boot_ctx_t *pCtx) /* * setkey function * - Open and parse file and keyid - * - Check if the legth of the parsed key is AES compatible - * - Store key in SE + * - Check if the length of the parsed key is AES compatible + * - Store key as binary in SE */ - if (setkey) { + if (setbinkey) { if (argc < 4) { status = kStatus_SSS_Fail; usage (); @@ -141,6 +154,14 @@ sss_status_t ex_sss_entry(ex_sss_boot_ctx_t *pCtx) } LOG_I("setkey function called"); + /* + * We set the cipherType to binary for now, because the AES type + * does not allow to read out the key again. + * It may be possible to inject readable AES by parsing modified + * policies. + */ + //cipherType = kSSS_CipherType_AES; + cipherType = kSSS_CipherType_Binary; strncpy(filepath, argv[3], sizeof(filepath) - 1); keyfile = fopen(filepath, "rb"); @@ -204,18 +225,96 @@ sss_status_t ex_sss_entry(ex_sss_boot_ctx_t *pCtx) } /* - * getkey function + * setaeskey function + * - Open and parse file and keyid + * - Check if the length of the parsed key is AES compatible + * - Store key in SE + */ + if (setaeskey) { + if (argc < 4) { + status = kStatus_SSS_Fail; + usage (); + goto cleanup; + } + + LOG_I("setbinkey function called"); + cipherType = kSSS_CipherType_AES; + + strncpy(filepath, argv[3], sizeof(filepath) - 1); + keyfile = fopen(filepath, "rb"); + if (keyfile == NULL) { + LOG_E("Can not open file"); + goto cleanup; + } + + fseek(keyfile, 0, SEEK_END); + long fsize = ftell(keyfile); + fseek(keyfile, 0, SEEK_SET); + + /* + * We expect a file that contains only hex numbers + * in text format without trailing new line. Since + * the key is represented in characters, the + * determined file size has twice as many bytes as + * the byte-encoded version. + */ + if (fsize != 32 && fsize != 48 && fsize != 64) { + LOG_E("Invalid AES key length"); + goto cleanup; + } + + if (fread(chexdata, 1, fsize, keyfile) != (size_t) fsize) { + LOG_E("Failed to read key file"); + goto cleanup; + } + + hex2uint(chexdata, keydata, fsize); + + LOG_MAU8_I("Key array:", keydata, fsize/2); + + keyid = (uint32_t) strtoul(argv[2], (char **)NULL, 16); + + status = sss_key_object_init(&key, &pCtx->ks); + ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success); + + status = sss_key_object_allocate_handle( + &key, + keyid, + keyPart, + cipherType, + keyByteLenMax, + kKeyObject_Mode_Persistent + ); + ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success); + + status = sss_key_store_set_key( + &pCtx->ks, + &key, + keydata, + fsize/2, + fsize/2 * 8, + NULL, + 0 + ); + ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success); + + LOG_I("AES key set successfull"); + LOG_X32_I(keyid); + } + + /* + * getbinkey function * - Parse keyid * - Get key from SE * - Write key to output file */ - if (getkey) { + if (getbinkey) { if (argc < 4) { status = kStatus_SSS_Fail; usage (); goto cleanup; } - LOG_I("getkey function called"); + LOG_I("getbinkey function called"); strncpy(filepath, argv[3], sizeof(filepath) - 1); keyfile = fopen(filepath, "wb"); @@ -254,6 +353,127 @@ sss_status_t ex_sss_entry(ex_sss_boot_ctx_t *pCtx) LOG_X32_I(keyid); } + /* + * decryptaes function + * - Parse keyid, IV, decrypted file and ouput file + * - decrypt and return file + */ + if (decryptaes) { + if (argc < 6) { + status = kStatus_SSS_Fail; + usage (); + goto cleanup; + } + LOG_I("decryptaes function called"); + + keyid = (uint32_t) strtoul(argv[2], (char **)NULL, 16); + + /* Parse IV file */ + strncpy(filepath, argv[3], sizeof(filepath) - 1); + ivfile = fopen(filepath, "rb"); + if (ivfile == NULL) { + LOG_E("Can not IV open file"); + goto cleanup; + } + + fseek(ivfile, 0, SEEK_END); + fsize = ftell(ivfile); + fseek(ivfile, 0, SEEK_SET); + ivlen = fsize / 2; + + if (ivlen != AES_IV_LENGTH) { + LOG_E("Invalid IV length, should be 16 Byte"); + goto cleanup; + } + if (fread(civdata, 1, fsize, ivfile) != (size_t) fsize) { + LOG_E("Failed to read IV file"); + goto cleanup; + } + hex2uint(civdata, ivdata, fsize); + + /* Read encrypted data */ + strncpy(filepath, argv[4], sizeof(filepath) - 1); + encfile = fopen(filepath, "rb"); + if (encfile == NULL) { + LOG_E("Can not open file"); + goto cleanup; + } + fseek(encfile, 0, SEEK_END); + fsize = ftell(encfile); + fseek(encfile, 0, SEEK_SET); + + /* At the moment we can only handle a file size <= 512 B */ + if (fsize > 512) { + LOG_E("Size of input data too large (512 byte max)"); + goto cleanup; + } + + uint8_t *encdata = malloc(sizeof(uint8_t) * fsize); + if (encdata == NULL) { + LOG_E("Error allocating memory for encrypted data"); + goto cleanup; + } + + if (fread(encdata, sizeof(uint8_t), fsize, encfile) != (size_t) fsize) { + LOG_E("Failed to read key file"); + goto cleanup; + } + // DEBUG + //LOG_MAU8_I("encdata:", encdata, fsize); + + /* Prepare file and memory for decrypted data */ + strncpy(filepath, argv[5], sizeof(filepath) - 1); + decfile = fopen(filepath, "wb"); + if (decfile == NULL) { + LOG_E("Can not open output file"); + goto cleanup; + } + uint8_t *decdata = malloc(sizeof(uint8_t) * fsize); + if (decdata == NULL) { + LOG_E("Error allocating memory for decrypted data"); + goto cleanup; + } + + status = sss_key_object_init(&key, &pCtx->ks); + ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success); + + status = sss_key_object_get_handle( + &key, + keyid + ); + ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success); + + sss_algorithm_t algorithm = kAlgorithm_SSS_AES_CBC; + sss_mode_t mode = kMode_SSS_Decrypt; + + status = sss_symmetric_context_init( + &ctx_symm_decrypt, + &pCtx->session, + &key, + algorithm, + mode + ); + ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success); + + LOG_MAU8_I("IV:", ivdata, ivlen); + status = sss_cipher_one_go( + &ctx_symm_decrypt, + ivdata, + ivlen, + encdata, + decdata, + fsize + ); + ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success); + + // DEBUG + //LOG_MAU8_I("decdata:", decdata, fsize); + fwrite(decdata, fsize, sizeof(uint8_t), decfile); + + LOG_I("Decryption successfull"); + LOG_X32_I(keyid); + } + /* * erasekey function * - Parse keyid @@ -296,6 +516,18 @@ cleanup: LOG_I("Cleanup"); if (keyfile != NULL) fclose(keyfile); + if (encfile != NULL) + fclose(encfile); + if (decfile != NULL) + fclose(decfile); + if (ivfile != NULL) + fclose(ivfile); + if (ctx_symm_decrypt.session != NULL) + sss_symmetric_context_free(&ctx_symm_decrypt); + if (encdata != NULL) + free(encdata); + if (decdata != NULL) + free(decdata); sss_key_object_free(&key); return status;