diff --git a/client/src/mifare/desfiretest.c b/client/src/mifare/desfiretest.c index 2cd8ba1be..2eb9f703d 100644 --- a/client/src/mifare/desfiretest.c +++ b/client/src/mifare/desfiretest.c @@ -617,6 +617,32 @@ static bool TestLRPIncCounter(void) { return res; } +static bool TestLRPEncode(void) { + bool res = true; + + uint8_t resp[100] = {0}; + size_t resplen = 0; + + LRPContext ctx = {0}; + + uint8_t key1[] = {0xE0, 0xC4, 0x93, 0x5F, 0xF0, 0xC2, 0x54, 0xCD, 0x2C, 0xEF, 0x8F, 0xDD, 0xC3, 0x24, 0x60, 0xCF}; + uint8_t iv1[] = {0xC3, 0x31, 0x5D, 0xBF}; + LRPSetKeyEx(&ctx, key1, iv1, sizeof(iv1) * 2, 0, true); + uint8_t data1[] = {0x01, 0x2D, 0x7F, 0x16, 0x53, 0xCA, 0xF6, 0x50, 0x3C, 0x6A, 0xB0, 0xC1, 0x01, 0x0E, 0x8C, 0xB0}; + LRPEncode(&ctx, data1, sizeof (data1), resp, &resplen); + uint8_t res1[] = {0xFC, 0xBB, 0xAC, 0xAA, 0x4F, 0x29, 0x18, 0x24, 0x64, 0xF9, 0x9D, 0xE4, 0x10, 0x85, 0x26, 0x6F, + 0x48, 0x0E, 0x86, 0x3E, 0x48, 0x7B, 0xAA, 0xF6, 0x87, 0xB4, 0x3E, 0xD1, 0xEC, 0xE0, 0xD6, 0x23}; + res = res && (resplen == sizeof(res1)); + res = res && (memcmp(resp, res1, sizeof(res1)) == 0); + + if (res) + PrintAndLogEx(INFO, "LRP encode........ " _GREEN_("passed")); + else + PrintAndLogEx(ERR, "LRP encode........ " _RED_("fail")); + + return res; +} + bool DesfireTest(bool verbose) { bool res = true; @@ -639,6 +665,7 @@ bool DesfireTest(bool verbose) { res = res && TestLRPUpdatedKeys(); res = res && TestLRPEval(); res = res && TestLRPIncCounter(); + res = res && TestLRPEncode(); PrintAndLogEx(INFO, "---------------------------"); if (res) diff --git a/client/src/mifare/lrpcrypto.c b/client/src/mifare/lrpcrypto.c index 217747dc8..bff85d289 100644 --- a/client/src/mifare/lrpcrypto.c +++ b/client/src/mifare/lrpcrypto.c @@ -53,6 +53,17 @@ void LRPSetKey(LRPContext *ctx, uint8_t *key, size_t updatedKeyNum, bool useBitP ctx->useBitPadding = useBitPadding; } +void LRPSetCounter(LRPContext *ctx, uint8_t *counter, size_t counterLenNibbles) { + memcpy(ctx->counter, counter, counterLenNibbles / 2); + ctx->counterLenNibbles = counterLenNibbles; +} + +void LRPSetKeyEx(LRPContext *ctx, uint8_t *key, uint8_t *counter, size_t counterLenNibbles, size_t updatedKeyNum, bool useBitPadding){ + LRPSetKey(ctx, key, updatedKeyNum, useBitPadding); + LRPSetCounter(ctx, counter, counterLenNibbles); +} + + // https://www.nxp.com/docs/en/application-note/AN12304.pdf // Algorithm 1 void LRPGeneratePlaintexts(LRPContext *ctx, size_t plaintextsCount) { @@ -120,3 +131,29 @@ void LRPIncCounter(uint8_t *ctr, size_t ctrlen) { } } +// https://www.nxp.com/docs/en/application-note/AN12304.pdf +// Algorithm 4 +void LRPEncode(LRPContext *ctx, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen) { + *resplen = 0; + + uint8_t xdata[1024] = {0}; + memcpy(xdata, data, datalen); + if (ctx->useBitPadding) { + xdata[datalen] = 0x80; + datalen++; + } + + if (datalen % CRYPTO_AES128_KEY_SIZE) + datalen = datalen + CRYPTO_AES128_KEY_SIZE - (datalen % CRYPTO_AES128_KEY_SIZE); + + if (datalen == 0) + return; + + uint8_t y[CRYPTO_AES128_KEY_SIZE] = {0}; + for (int i = 0; i < datalen / CRYPTO_AES128_KEY_SIZE; i++) { + LRPEvalLRP(ctx, ctx->counter, ctx->counterLenNibbles, true, y); + aes_encode(NULL, y, &xdata[i * CRYPTO_AES128_KEY_SIZE], &resp[i * CRYPTO_AES128_KEY_SIZE], CRYPTO_AES128_KEY_SIZE); + *resplen += CRYPTO_AES128_KEY_SIZE; + LRPIncCounter(ctx->counter, ctx->counterLenNibbles); + } +} diff --git a/client/src/mifare/lrpcrypto.h b/client/src/mifare/lrpcrypto.h index a8dbefdb6..17e0858f0 100644 --- a/client/src/mifare/lrpcrypto.h +++ b/client/src/mifare/lrpcrypto.h @@ -25,6 +25,7 @@ #define LRP_MAX_PLAINTEXTS_SIZE 16 #define LRP_MAX_UPDATED_KEYS_SIZE 4 +#define LRP_MAX_COUNTER_SIZE (CRYPTO_AES128_KEY_SIZE * 4) typedef struct { uint8_t key[CRYPTO_AES128_KEY_SIZE]; @@ -35,14 +36,19 @@ typedef struct { size_t updatedKeysCount; uint8_t updatedKeys[LRP_MAX_UPDATED_KEYS_SIZE][CRYPTO_AES128_KEY_SIZE]; size_t useUpdatedKeyNum; + + uint8_t counter[LRP_MAX_COUNTER_SIZE]; + size_t counterLenNibbles; // len in bytes * 2 (or * 2 - 1) } LRPContext; void LRPClearContext(LRPContext *ctx); void LRPSetKey(LRPContext *ctx, uint8_t *key, size_t updatedKeyNum, bool useBitPadding); +void LRPSetKeyEx(LRPContext *ctx, uint8_t *key, uint8_t *counter, size_t counterLenNibbles, size_t updatedKeyNum, bool useBitPadding); +void LRPSetCounter(LRPContext *ctx, uint8_t *counter, size_t counterLenNibbles); void LRPGeneratePlaintexts(LRPContext *ctx, size_t plaintextsCount); void LRPGenerateUpdatedKeys(LRPContext *ctx, size_t updatedKeysCount); void LRPEvalLRP(LRPContext *ctx, uint8_t *iv, size_t ivlen, bool final, uint8_t *y); void LRPIncCounter(uint8_t *ctr, size_t ctrlen); -void LRPEncode(LRPContext *ctx, uint8_t *ctr, size_t ctrlen, uint8_t *resp, size_t *resplen); +void LRPEncode(LRPContext *ctx, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen); #endif // __LRPCRYPTO_H