diff --git a/client/cmdflashmem.c b/client/cmdflashmem.c index df17e2b9e..2b86bdcfc 100644 --- a/client/cmdflashmem.c +++ b/client/cmdflashmem.c @@ -9,11 +9,21 @@ //----------------------------------------------------------------------------- #include "cmdflashmem.h" -#define FLASH_MEM_BLOCK_SIZE 256 -#define FLASH_MEM_MAX_SIZE 0x3FFFF +#include "rsa.h" +#include "sha1.h" static int CmdHelp(const char *Cmd); - +int usage_flashmem_read(void){ + PrintAndLogEx(NORMAL, "Read flash memory on device"); + PrintAndLogEx(NORMAL, "Usage: mem read o l "); + PrintAndLogEx(NORMAL, " o : offset in memory"); + PrintAndLogEx(NORMAL, " l : length"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " mem read o 0 l 32"); // read 32 bytes starting at offset 0 + PrintAndLogEx(NORMAL, " mem read o 1024 l 10"); // read 10 bytes starting at offset 1024 + return 0; +} int usage_flashmem_load(void){ PrintAndLogEx(NORMAL, "Loads binary file into flash memory on device"); PrintAndLogEx(NORMAL, "Usage: mem load o f "); @@ -43,7 +53,7 @@ int usage_flashmem_wipe(void){ PrintAndLogEx(WARNING, "[OBS] use with caution."); PrintAndLogEx(NORMAL, "Wipe flash memory on device, which fills memory with 0xFF\n"); - PrintAndLogEx(NORMAL, " Usage: mem save p "); + PrintAndLogEx(NORMAL, " Usage: mem wipe p "); PrintAndLogEx(NORMAL, " p : 0,1,2 page memory"); // PrintAndLogEx(NORMAL, " i : inital total wipe"); PrintAndLogEx(NORMAL, ""); @@ -52,6 +62,56 @@ int usage_flashmem_wipe(void){ PrintAndLogEx(NORMAL, " mem wipe p 0"); // wipes first page. return 0; } +int usage_flashmem_info(void){ + PrintAndLogEx(NORMAL, "Collect signature and verify it from flash memory\n"); + PrintAndLogEx(NORMAL, " Usage: mem info [h|s|w]"); + PrintAndLogEx(NORMAL, " s : create a signature"); + PrintAndLogEx(NORMAL, " w : write signature to flash memory"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " mem info"); + PrintAndLogEx(NORMAL, " mem info s"); + return 0; +} + +int CmdFlashMemRead(const char *Cmd) { + + uint8_t cmdp = 0; + bool errors = false; + uint32_t start_index = 0, len = 0; + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'o': + start_index = param_get32ex(Cmd, cmdp+1, 0, 10); + cmdp += 2; + break; + case 'l': + len = param_get32ex(Cmd, cmdp+1, 0, 10); + cmdp += 2; + break; + case 'h': + return usage_flashmem_read(); + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + //Validations + if (errors || cmdp == 0 ) return usage_flashmem_read(); + + if (start_index + len > FLASH_MEM_MAX_SIZE) { + PrintAndLogDevice(WARNING, "error, start_index + length is larger than available memory"); + return 1; + } + + UsbCommand c = {CMD_READ_FLASH_MEM, {start_index, len, 0}}; + clearCommandBuffer(); + SendCommand(&c); + return 0; +} int CmdFlashMemLoad(const char *Cmd){ FILE *f; @@ -258,9 +318,198 @@ int CmdFlashMemWipe(const char *Cmd){ return 0; } +int CmdFlashMemInfo(const char *Cmd){ + + uint8_t sha_hash[20] = {0}; + rsa_context rsa; + + uint8_t cmdp = 0; + bool errors = false, shall_write = false, shall_sign = false; + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': return usage_flashmem_info(); + case 's': { + shall_sign = true; + cmdp++; + break; + } + case 'w': + shall_write = true; + cmdp++; + break; + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + //Validations + if (errors ) return usage_flashmem_info(); + + UsbCommand c = {CMD_INFO_FLASH_MEM, {0, 0, 0}}; + clearCommandBuffer(); + SendCommand(&c); + UsbCommand resp; + if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2500) ) { + PrintAndLogEx(WARNING, "timeout while waiting for reply."); + return 1; + } + + uint8_t isok = resp.arg[0] & 0xFF; + if (!isok) { + PrintAndLogEx(FAILED, "failed"); + return 1; + } + + // validate signature here + rdv40_validation_t mem; + memcpy(&mem, (rdv40_validation_t *)resp.d.asBytes, sizeof(rdv40_validation_t)); + + // Flash ID hash (sha1) + sha1( mem.flashid, sizeof(mem.flashid), sha_hash ); + + // print header + PrintAndLogEx(INFO, "\n--- Flash memory Information ---------"); + PrintAndLogEx(INFO, "-------------------------------------------------------------"); + PrintAndLogEx(INFO, "ID | %s", sprint_hex(mem.flashid, sizeof(mem.flashid) )); + PrintAndLogEx(INFO, "SHA1 | %s", sprint_hex(sha_hash, sizeof(sha_hash))); + PrintAndLogEx(INFO, "RSA SIGNATURE |"); + print_hex_break( mem.signature, sizeof(mem.signature), 32); + +//------------------------------------------------------------------------------- +// Example RSA-1024 keypair, for test purposes (from common/polarssl/rsa.c) +// + +// public key modulus N +#define RSA_N "9292758453063D803DD603D5E777D788" \ + "8ED1D5BF35786190FA2F23EBC0848AEA" \ + "DDA92CA6C3D80B32C4D109BE0F36D6AE" \ + "7130B9CED7ACDF54CFC7555AC14EEBAB" \ + "93A89813FBF3C4F8066D2D800F7C38A8" \ + "1AE31942917403FF4946B0A83D3D3E05" \ + "EE57C6F5F5606FB5D4BC6CD34EE0801A" \ + "5E94BB77B07507233A0BC7BAC8F90F79" + +// public key Exponent E +#define RSA_E "10001" + +// private key Exponent D +#define RSA_D "24BF6185468786FDD303083D25E64EFC" \ + "66CA472BC44D253102F8B4A9D3BFA750" \ + "91386C0077937FE33FA3252D28855837" \ + "AE1B484A8A9A45F7EE8C0C634F99E8CD" \ + "DF79C5CE07EE72C7F123142198164234" \ + "CABB724CF78B8173B9F880FC86322407" \ + "AF1FEDFDDE2BEB674CA15F3E81A1521E" \ + "071513A1E85B5DFA031F21ECAE91A34D" + +// prime P +#define RSA_P "C36D0EB7FCD285223CFB5AABA5BDA3D8" \ + "2C01CAD19EA484A87EA4377637E75500" \ + "FCB2005C5C7DD6EC4AC023CDA285D796" \ + "C3D9E75E1EFC42488BB4F1D13AC30A57" + +// prime Q +#define RSA_Q "C000DF51A7C77AE8D7C7370C1FF55B69" \ + "E211C2B9E5DB1ED0BF61D0D9899620F4" \ + "910E4168387E3C30AA1E00C339A79508" \ + "8452DD96A9A5EA5D9DCA68DA636032AF" + +#define RSA_DP "C1ACF567564274FB07A0BBAD5D26E298" \ + "3C94D22288ACD763FD8E5600ED4A702D" \ + "F84198A5F06C2E72236AE490C93F07F8" \ + "3CC559CD27BC2D1CA488811730BB5725" + +#define RSA_DQ "4959CBF6F8FEF750AEE6977C155579C7" \ + "D8AAEA56749EA28623272E4F7D0592AF" \ + "7C1F1313CAC9471B5C523BFE592F517B" \ + "407A1BD76C164B93DA2D32A383E58357" + +#define RSA_QP "9AE7FBC99546432DF71896FC239EADAE" \ + "F38D18D2B2F0E2DD275AA977E2BF4411" \ + "F5A3B2A5D33605AEBBCCBA7FEB9F2D2F" \ + "A74206CEC169D74BF5A8C50D6F48EA08" + + +#define KEY_LEN 128 + + rsa_init(&rsa, RSA_PKCS_V15, 0); + + rsa.len = KEY_LEN; + + mpi_read_string( &rsa.N , 16, RSA_N ); + mpi_read_string( &rsa.E , 16, RSA_E ); + mpi_read_string( &rsa.D , 16, RSA_D ); + mpi_read_string( &rsa.P , 16, RSA_P ); + mpi_read_string( &rsa.Q , 16, RSA_Q ); + mpi_read_string( &rsa.DP, 16, RSA_DP ); + mpi_read_string( &rsa.DQ, 16, RSA_DQ ); + mpi_read_string( &rsa.QP, 16, RSA_QP ); + + PrintAndLogEx(INFO, "KEY length | %d", KEY_LEN); + + bool is_keyok = ( rsa_check_pubkey( &rsa ) == 0 || rsa_check_privkey( &rsa ) == 0 ); + if (is_keyok) + PrintAndLogEx(SUCCESS, "RSA key validation ok"); + else + PrintAndLogEx(FAILED, "RSA key validation failed"); + + // + uint8_t from_device[KEY_LEN]; + uint8_t sign[KEY_LEN]; + + // to be verified + memcpy(from_device, mem.signature, KEY_LEN); + + // to be signed (all zeros + memset(sign, 0, KEY_LEN); + + // Signing (private key) + if (shall_sign) { + + int is_signed = rsa_pkcs1_sign( &rsa, NULL, NULL, RSA_PRIVATE, SIG_RSA_SHA1, 20, sha_hash, sign ); + if (is_signed == 0) + PrintAndLogEx(SUCCESS, "RSA Signing ok"); + else + PrintAndLogEx(FAILED, "RSA Signing failed"); + + if (shall_write) { + // save to mem + c = (UsbCommand){CMD_WRITE_FLASH_MEM, {FLASH_MEM_SIGNATURE_OFFSET, FLASH_MEM_SIGNATURE_LEN, 0}}; + memcpy(c.d.asBytes, sign, sizeof(sign)); + clearCommandBuffer(); + SendCommand(&c); + if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2000) ) { + PrintAndLogEx(WARNING, "timeout while waiting for reply."); + } else { + + if (!resp.arg[0]) + PrintAndLogEx(FAILED, "Writing signature failed"); + else + PrintAndLogEx(SUCCESS, "Writing signature ok [offset: %u]", FLASH_MEM_SIGNATURE_OFFSET); + + } + } + PrintAndLogEx(INFO, "Signed | "); + print_hex_break( sign, sizeof(sign), 32); + } + + // Verify (public key) + int is_verified = rsa_pkcs1_verify( &rsa, RSA_PUBLIC, SIG_RSA_SHA1, 20, sha_hash, from_device ); + if (is_verified == 0) + PrintAndLogEx(SUCCESS, "RSA Verification ok"); + else + PrintAndLogEx(FAILED, "RSA Verification failed"); + + rsa_free(&rsa); + return 0; +} static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, + {"read", CmdFlashMemRead, 1, "Read Flash memory [rdv40]"}, + {"info", CmdFlashMemInfo, 1, "Flash memory information [rdv40]"}, {"load", CmdFlashMemLoad, 1, "Load data into flash memory [rdv40]"}, {"save", CmdFlashMemSave, 1, "Save data from flash memory [rdv40]"}, {"wipe", CmdFlashMemWipe, 1, "Wipe data from flash memory [rdv40]"}, diff --git a/client/cmdflashmem.h b/client/cmdflashmem.h index cf1545602..99b18b4c5 100644 --- a/client/cmdflashmem.h +++ b/client/cmdflashmem.h @@ -26,7 +26,9 @@ extern int CmdFlashMem(const char *Cmd); +extern int CmdFlashMemRead(const char* cmd); extern int CmdFlashMemLoad(const char* cmd); extern int CmdFlashMemSave(const char* cmd); extern int CmdFlashMemWipe(const char *Cmd); +extern int CmdFlashMemInfo(const char *Cmd); #endif \ No newline at end of file