diff --git a/client/src/mifare/desfiretest.c b/client/src/mifare/desfiretest.c index dac1416ec..1a4d40d56 100644 --- a/client/src/mifare/desfiretest.c +++ b/client/src/mifare/desfiretest.c @@ -6,6 +6,9 @@ // the license. //----------------------------------------------------------------------------- // tests for desfire +// +// tests for LRP here: Leakage Resilient Primitive (LRP) Specification, https://www.nxp.com/docs/en/application-note/AN12304.pdf +// //----------------------------------------------------------------------------- #include "desfiretest.h" @@ -746,6 +749,8 @@ static bool TestLRPDecode(void) { return res; } +// https://www.nxp.com/docs/en/application-note/AN12304.pdf +// 3.4 LRP CMAC static bool TestLRPSubkeys(void) { bool res = true; @@ -770,9 +775,28 @@ static bool TestLRPSubkeys(void) { return res; } +// https://www.nxp.com/docs/en/application-note/AN12304.pdf +// 3.4 LRP CMAC static bool TestLRPCMAC(void) { bool res = true; + LRPContext ctx = {0}; + uint8_t cmac[CRYPTO_AES128_KEY_SIZE] = {0}; + + uint8_t key1[] = {0x81, 0x95, 0x08, 0x8C, 0xE6, 0xC3, 0x93, 0x70, 0x8E, 0xBB, 0xE6, 0xC7, 0x91, 0x4E, 0xCB, 0x0B}; + LRPSetKey(&ctx, key1, 0, true); + uint8_t data1[] = {0xBB, 0xD5, 0xB8, 0x57, 0x72, 0xC7}; + LRPCMAC(&ctx, data1, sizeof(data1), cmac); + uint8_t cmacres1[] = {0xAD, 0x85, 0x95, 0xE0, 0xB4, 0x9C, 0x5C, 0x0D, 0xB1, 0x8E, 0x77, 0x35, 0x5F, 0x5A, 0xAF, 0xF6}; + res = res && (memcmp(cmac, cmacres1, sizeof(cmacres1)) == 0); + + /*uint8_t key2[] = {0x5A, 0xA9, 0xF6, 0xC6, 0xDE, 0x51, 0x38, 0x11, 0x3D, 0xF5, 0xD6, 0xB6, 0xC7, 0x7D, 0x5D, 0x52}; + LRPSetKey(&ctx, key2, 0, true); + uint8_t data2[] = {0xA4, 0x43, 0x4D, 0x74, 0x0C, 0x2C, 0xB6, 0x65, 0xFE, 0x53, 0x96, 0x95, 0x91, 0x89, 0x38, 0x3F}; + LRPCMAC(&ctx, data2, sizeof(data2), cmac); + uint8_t cmacres2[] = {0xA4, 0x43, 0x4D, 0x74, 0x0C, 0x2C, 0xB6, 0x65, 0xFE, 0x53, 0x96, 0x95, 0x91, 0x89, 0x38, 0x3F}; + res = res && (memcmp(cmac, cmacres2, sizeof(cmacres2)) == 0); +*/ if (res) PrintAndLogEx(INFO, "LRP CMAC.......... " _GREEN_("passed")); diff --git a/client/src/mifare/lrpcrypto.c b/client/src/mifare/lrpcrypto.c index 4a7e2eb72..0e55b3ca8 100644 --- a/client/src/mifare/lrpcrypto.c +++ b/client/src/mifare/lrpcrypto.c @@ -15,6 +15,9 @@ * along with this program. If not, see * * $Id$ + * + * description here: Leakage Resilient Primitive (LRP) Specification, https://www.nxp.com/docs/en/application-note/AN12304.pdf + * */ #include "lrpcrypto.h" @@ -51,6 +54,9 @@ void LRPSetKey(LRPContext *ctx, uint8_t *key, size_t updatedKeyNum, bool useBitP ctx->useUpdatedKeyNum = updatedKeyNum; ctx->useBitPadding = useBitPadding; + + memcpy(ctx->counter, const00, CRYPTO_AES128_KEY_SIZE); + ctx->counterLenNibbles = CRYPTO_AES128_KEY_SIZE; } void LRPSetCounter(LRPContext *ctx, uint8_t *counter, size_t counterLenNibbles) { @@ -158,6 +164,8 @@ void LRPEncode(LRPContext *ctx, uint8_t *data, size_t datalen, uint8_t *resp, si } } +// https://www.nxp.com/docs/en/application-note/AN12304.pdf +// Algorithm 5 void LRPDecode(LRPContext *ctx, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen) { *resplen = 0; if (datalen % CRYPTO_AES128_KEY_SIZE) @@ -199,7 +207,7 @@ static bool shiftLeftBe(uint8_t *data, size_t length) { // GF(2 ^ 128) // poly x^128 + x ^ 7 + x ^ 2 + x + 1 // bit: 1000..0010000111 == 0x1 00 00 .. 00 00 87 -static void shiftPolyLeft(uint8_t *data) { +static void mulPolyX(uint8_t *data) { if (shiftLeftBe(data, 16)) data[15] = data[15] ^ 0x87; } @@ -211,14 +219,43 @@ void LRPGenSubkeys(uint8_t *key, uint8_t *sk1, uint8_t *sk2) { uint8_t y[CRYPTO_AES128_KEY_SIZE] = {0}; LRPEvalLRP(&ctx, const00, CRYPTO_AES128_KEY_SIZE * 2, true, y); PrintAndLogEx(ERR, "--y %s", sprint_hex(y, 16)); - shiftPolyLeft(y); + mulPolyX(y); memcpy(sk1, y, CRYPTO_AES128_KEY_SIZE); PrintAndLogEx(ERR, "--sk1 %s", sprint_hex(y, 16)); - shiftPolyLeft(y); + mulPolyX(y); memcpy(sk2, y, CRYPTO_AES128_KEY_SIZE); PrintAndLogEx(ERR, "--sk2 %s", sprint_hex(y, 16)); } +// https://www.nxp.com/docs/en/application-note/AN12304.pdf +// Algorithm 6 void LRPCMAC(LRPContext *ctx, uint8_t *data, size_t datalen, uint8_t *cmac) { + uint8_t sk1[CRYPTO_AES128_KEY_SIZE] = {0}; + uint8_t sk2[CRYPTO_AES128_KEY_SIZE] = {0}; + LRPGenSubkeys(ctx->key, sk1, sk2); + uint8_t y[CRYPTO_AES128_KEY_SIZE] = {0}; + size_t clen = 0; + for (int i = 0; i < datalen / CRYPTO_AES128_KEY_SIZE; i++) { + bin_xor(y, &data[i * CRYPTO_AES128_KEY_SIZE], CRYPTO_AES128_KEY_SIZE); + LRPEvalLRP(ctx, y, CRYPTO_AES128_KEY_SIZE * 2, true, y); + clen += CRYPTO_AES128_KEY_SIZE; + } + + size_t bllen = datalen - clen; + // padding + if (bllen > 0) { + uint8_t bl[CRYPTO_AES128_KEY_SIZE] = {0}; + memcpy(bl, &data[clen * CRYPTO_AES128_KEY_SIZE], bllen); + bl[bllen] = 0x80; + bin_xor(y, bl, CRYPTO_AES128_KEY_SIZE); + } + + // if there is more data + if (bllen == 0) + bin_xor(y, sk1, CRYPTO_AES128_KEY_SIZE); + else + bin_xor(y, sk2, CRYPTO_AES128_KEY_SIZE); + + LRPEvalLRP(ctx, y, CRYPTO_AES128_KEY_SIZE * 2, true, cmac); } diff --git a/client/src/mifare/lrpcrypto.h b/client/src/mifare/lrpcrypto.h index fe0334d9d..19a811137 100644 --- a/client/src/mifare/lrpcrypto.h +++ b/client/src/mifare/lrpcrypto.h @@ -15,6 +15,9 @@ * along with this program. If not, see * * $Id$ + * + * description here: Leakage Resilient Primitive (LRP) Specification, https://www.nxp.com/docs/en/application-note/AN12304.pdf + * */ #ifndef __LRPCRYPTO_H