mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 22:03:42 -07:00
LRP auth works
This commit is contained in:
parent
1c3f4d7e22
commit
df8f5c4655
2 changed files with 60 additions and 49 deletions
|
@ -258,6 +258,8 @@ const char *DesfireAuthErrorToStr(int error) {
|
||||||
return "mbedtls_aes_setkey_dec failed";
|
return "mbedtls_aes_setkey_dec failed";
|
||||||
case 11:
|
case 11:
|
||||||
return "Authentication failed. Cannot verify Session Key.";
|
return "Authentication failed. Cannot verify Session Key.";
|
||||||
|
case 12:
|
||||||
|
return "Authentication failed. Cannot verify CMAC.";
|
||||||
case 100:
|
case 100:
|
||||||
return "Can't find auth method for provided channel parameters.";
|
return "Can't find auth method for provided channel parameters.";
|
||||||
case 200:
|
case 200:
|
||||||
|
@ -1210,7 +1212,7 @@ static int DesfireAuthenticateEV2(DesfireContext *dctx, DesfireSecureChannel sec
|
||||||
PrintAndLogEx(INFO, _CYAN_("Auth %s:") " cmd: 0x%02x keynum: 0x%02x key: %s", (firstauth) ? "first" : "non-first", subcommand, dctx->keyNum, sprint_hex(key, 16));
|
PrintAndLogEx(INFO, _CYAN_("Auth %s:") " cmd: 0x%02x keynum: 0x%02x key: %s", (firstauth) ? "first" : "non-first", subcommand, dctx->keyNum, sprint_hex(key, 16));
|
||||||
|
|
||||||
// Let's send our auth command
|
// Let's send our auth command
|
||||||
uint8_t cdata[2] = {dctx->keyNum, 0x00};
|
uint8_t cdata[] = {dctx->keyNum, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
int res = DesfireExchangeEx(false, dctx, subcommand, cdata, (firstauth) ? sizeof(cdata) : 1, &respcode, recv_data, &recv_len, false, 0);
|
int res = DesfireExchangeEx(false, dctx, subcommand, cdata, (firstauth) ? sizeof(cdata) : 1, &respcode, recv_data, &recv_len, false, 0);
|
||||||
if (res != PM3_SUCCESS) {
|
if (res != PM3_SUCCESS) {
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -1224,12 +1226,16 @@ static int DesfireAuthenticateEV2(DesfireContext *dctx, DesfireSecureChannel sec
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t rdataindx = 0;
|
||||||
if (recv_len != CRYPTO_AES_BLOCK_SIZE) {
|
if (recv_len != CRYPTO_AES_BLOCK_SIZE) {
|
||||||
|
if (recv_len == CRYPTO_AES_BLOCK_SIZE + 1)
|
||||||
|
rdataindx = 1;
|
||||||
|
else
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Part 2
|
// Part 2
|
||||||
memcpy(encRndB, recv_data, 16);
|
memcpy(encRndB, &recv_data[rdataindx], 16);
|
||||||
|
|
||||||
// Part 3
|
// Part 3
|
||||||
if (aes_decode(IV, key, encRndB, RndB, CRYPTO_AES_BLOCK_SIZE))
|
if (aes_decode(IV, key, encRndB, RndB, CRYPTO_AES_BLOCK_SIZE))
|
||||||
|
@ -1375,12 +1381,8 @@ static int DesfireAuthenticateISO(DesfireContext *dctx, DesfireSecureChannel sec
|
||||||
|
|
||||||
static int DesfireAuthenticateLRP(DesfireContext *dctx, DesfireSecureChannel secureChannel, bool firstauth, bool verbose) {
|
static int DesfireAuthenticateLRP(DesfireContext *dctx, DesfireSecureChannel secureChannel, bool firstauth, bool verbose) {
|
||||||
// Crypt constants
|
// Crypt constants
|
||||||
uint8_t IV[16] = {0};
|
|
||||||
uint8_t RndA[CRYPTO_AES_BLOCK_SIZE] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16};
|
uint8_t RndA[CRYPTO_AES_BLOCK_SIZE] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16};
|
||||||
uint8_t RndB[CRYPTO_AES_BLOCK_SIZE] = {0};
|
uint8_t RndB[CRYPTO_AES_BLOCK_SIZE] = {0};
|
||||||
uint8_t encRndB[CRYPTO_AES_BLOCK_SIZE] = {0};
|
|
||||||
uint8_t rotRndA[CRYPTO_AES_BLOCK_SIZE] = {0}; //RndA'
|
|
||||||
uint8_t rotRndB[CRYPTO_AES_BLOCK_SIZE] = {0}; //RndB'
|
|
||||||
uint8_t both[CRYPTO_AES_BLOCK_SIZE * 2 + 1] = {0}; // ek/dk_keyNo(RndA+RndB')
|
uint8_t both[CRYPTO_AES_BLOCK_SIZE * 2 + 1] = {0}; // ek/dk_keyNo(RndA+RndB')
|
||||||
|
|
||||||
uint8_t subcommand = firstauth ? MFDES_AUTHENTICATE_EV2F : MFDES_AUTHENTICATE_EV2NF;
|
uint8_t subcommand = firstauth ? MFDES_AUTHENTICATE_EV2F : MFDES_AUTHENTICATE_EV2NF;
|
||||||
|
@ -1394,7 +1396,7 @@ static int DesfireAuthenticateLRP(DesfireContext *dctx, DesfireSecureChannel sec
|
||||||
PrintAndLogEx(INFO, _CYAN_("Auth %s:") " cmd: 0x%02x keynum: 0x%02x key: %s", (firstauth) ? "first" : "non-first", subcommand, dctx->keyNum, sprint_hex(key, 16));
|
PrintAndLogEx(INFO, _CYAN_("Auth %s:") " cmd: 0x%02x keynum: 0x%02x key: %s", (firstauth) ? "first" : "non-first", subcommand, dctx->keyNum, sprint_hex(key, 16));
|
||||||
|
|
||||||
// Let's send our auth command
|
// Let's send our auth command
|
||||||
uint8_t cdata[] = {dctx->keyNum, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02};
|
uint8_t cdata[] = {dctx->keyNum, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
int res = DesfireExchangeEx(false, dctx, subcommand, cdata, (firstauth) ? sizeof(cdata) : 1, &respcode, recv_data, &recv_len, false, 0);
|
int res = DesfireExchangeEx(false, dctx, subcommand, cdata, (firstauth) ? sizeof(cdata) : 1, &respcode, recv_data, &recv_len, false, 0);
|
||||||
if (res != PM3_SUCCESS) {
|
if (res != PM3_SUCCESS) {
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -1408,39 +1410,40 @@ static int DesfireAuthenticateLRP(DesfireContext *dctx, DesfireSecureChannel sec
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recv_len != CRYPTO_AES_BLOCK_SIZE) {
|
if (recv_len != CRYPTO_AES_BLOCK_SIZE + 1) {
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Part 2
|
if (recv_data[0] != 0x01) {
|
||||||
memcpy(encRndB, recv_data, 16);
|
PrintAndLogEx(WARNING, "NOT LRP! rec data[0]=: 0x%02x", recv_data[0]);
|
||||||
|
//return 50;
|
||||||
|
}
|
||||||
|
|
||||||
// Part 3
|
// PICC return RndB in plain
|
||||||
if (aes_decode(IV, key, encRndB, RndB, CRYPTO_AES_BLOCK_SIZE))
|
memcpy(RndB, &recv_data[1], 16);
|
||||||
return 5;
|
|
||||||
|
|
||||||
if (g_debugMode > 1) {
|
if (g_debugMode > 1) {
|
||||||
PrintAndLogEx(DEBUG, "encRndB: %s", sprint_hex(encRndB, CRYPTO_AES_BLOCK_SIZE));
|
|
||||||
PrintAndLogEx(DEBUG, "RndB: %s", sprint_hex(RndB, CRYPTO_AES_BLOCK_SIZE));
|
PrintAndLogEx(DEBUG, "RndB: %s", sprint_hex(RndB, CRYPTO_AES_BLOCK_SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
// - Rotate RndB by 8 bits
|
// cmac(sessionkey, rnda+rndb)
|
||||||
memcpy(rotRndB, RndB, CRYPTO_AES_BLOCK_SIZE);
|
uint8_t sessionkey[32] = {0};
|
||||||
rol(rotRndB, CRYPTO_AES_BLOCK_SIZE);
|
DesfireGenSessionKeyLRP(key, RndA, RndB, false, sessionkey);
|
||||||
|
|
||||||
// - Encrypt our response
|
uint8_t tmp[CRYPTO_AES_BLOCK_SIZE * 4] = {0};
|
||||||
uint8_t tmp[32] = {0x00};
|
|
||||||
memcpy(tmp, RndA, CRYPTO_AES_BLOCK_SIZE);
|
memcpy(tmp, RndA, CRYPTO_AES_BLOCK_SIZE);
|
||||||
memcpy(tmp + CRYPTO_AES_BLOCK_SIZE, rotRndB, CRYPTO_AES_BLOCK_SIZE);
|
memcpy(tmp + CRYPTO_AES_BLOCK_SIZE, RndB, CRYPTO_AES_BLOCK_SIZE);
|
||||||
if (g_debugMode > 1) {
|
|
||||||
PrintAndLogEx(DEBUG, "rotRndB: %s", sprint_hex(rotRndB, CRYPTO_AES_BLOCK_SIZE));
|
|
||||||
PrintAndLogEx(DEBUG, "Both: %s", sprint_hex(tmp, CRYPTO_AES_BLOCK_SIZE * 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aes_encode(IV, key, tmp, both, CRYPTO_AES_BLOCK_SIZE * 2))
|
uint8_t cmac[CRYPTO_AES_BLOCK_SIZE] = {0};
|
||||||
return 6;
|
LRPContext ctx = {0};
|
||||||
|
LRPSetKey(&ctx, sessionkey, 0, true);
|
||||||
|
LRPCMAC(&ctx, tmp, 32, cmac);
|
||||||
|
|
||||||
|
// response = rnda + cmac(sessionkey, rnda+rndb)
|
||||||
|
memcpy(both, RndA, CRYPTO_AES_BLOCK_SIZE);
|
||||||
|
memcpy(both + CRYPTO_AES_BLOCK_SIZE, cmac, CRYPTO_AES_BLOCK_SIZE);
|
||||||
if (g_debugMode > 1) {
|
if (g_debugMode > 1) {
|
||||||
PrintAndLogEx(DEBUG, "EncBoth: %s", sprint_hex(both, CRYPTO_AES_BLOCK_SIZE * 2));
|
PrintAndLogEx(DEBUG, "Both: %s", sprint_hex(tmp, CRYPTO_AES_BLOCK_SIZE * 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
res = DesfireExchangeEx(false, dctx, MFDES_ADDITIONAL_FRAME, both, CRYPTO_AES_BLOCK_SIZE * 2, &respcode, recv_data, &recv_len, false, 0);
|
res = DesfireExchangeEx(false, dctx, MFDES_ADDITIONAL_FRAME, both, CRYPTO_AES_BLOCK_SIZE * 2, &respcode, recv_data, &recv_len, false, 0);
|
||||||
|
@ -1457,39 +1460,47 @@ static int DesfireAuthenticateLRP(DesfireContext *dctx, DesfireSecureChannel sec
|
||||||
}
|
}
|
||||||
|
|
||||||
// Part 4
|
// Part 4
|
||||||
uint8_t data[32] = {0};
|
uint8_t data[64] = {0};
|
||||||
|
|
||||||
if (aes_decode(IV, key, recv_data, data, recv_len))
|
// clear IV here
|
||||||
return 10;
|
DesfireClearIV(dctx);
|
||||||
|
|
||||||
// rotate rndA to check
|
// check mac
|
||||||
memcpy(rotRndA, RndA, CRYPTO_AES_BLOCK_SIZE);
|
memcpy(tmp, RndB, CRYPTO_AES_BLOCK_SIZE);
|
||||||
rol(rotRndA, CRYPTO_AES_BLOCK_SIZE);
|
memcpy(tmp + CRYPTO_AES_BLOCK_SIZE, RndA, CRYPTO_AES_BLOCK_SIZE);
|
||||||
|
memcpy(tmp + CRYPTO_AES_BLOCK_SIZE * 2, recv_data, CRYPTO_AES_BLOCK_SIZE);
|
||||||
uint8_t *recRndA = (firstauth) ? &data[4] : data;
|
LRPSetKey(&ctx, sessionkey, 0, true);
|
||||||
|
LRPCMAC(&ctx, tmp, CRYPTO_AES_BLOCK_SIZE * 3, cmac);
|
||||||
if (memcmp(rotRndA, recRndA, CRYPTO_AES_BLOCK_SIZE) != 0) {
|
if (memcmp(&recv_data[CRYPTO_AES_BLOCK_SIZE], cmac, CRYPTO_AES_BLOCK_SIZE) != 0) {
|
||||||
if (g_debugMode > 1) {
|
if (g_debugMode > 1) {
|
||||||
PrintAndLogEx(DEBUG, "Expected_RndA' : %s", sprint_hex(rotRndA, CRYPTO_AES_BLOCK_SIZE));
|
PrintAndLogEx(DEBUG, "Expected cmac : %s", sprint_hex(&recv_data[CRYPTO_AES_BLOCK_SIZE], CRYPTO_AES_BLOCK_SIZE));
|
||||||
PrintAndLogEx(DEBUG, "Generated_RndA' : %s", sprint_hex(recRndA, CRYPTO_AES_BLOCK_SIZE));
|
PrintAndLogEx(DEBUG, "Generated cmac : %s", sprint_hex(cmac, CRYPTO_AES_BLOCK_SIZE));
|
||||||
}
|
}
|
||||||
return 11;
|
return 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// decode data
|
||||||
|
LRPSetKeyEx(&ctx, sessionkey, dctx->IV, 4 * 2, 1, false);
|
||||||
|
size_t declen = 0;
|
||||||
|
LRPDecode(&ctx, recv_data, 16, data, &declen);
|
||||||
|
memcpy(dctx->IV, ctx.counter, 4);
|
||||||
|
PrintAndLogEx(INFO, "--decoded <%d>: %s", declen, sprint_hex(data, 16));
|
||||||
|
PrintAndLogEx(INFO, "iv : %s", sprint_hex(dctx->IV, 4));
|
||||||
|
|
||||||
if (firstauth) {
|
if (firstauth) {
|
||||||
dctx->cmdCntr = 0;
|
dctx->cmdCntr = 0;
|
||||||
memcpy(dctx->TI, data, 4);
|
memcpy(dctx->TI, data, 4);
|
||||||
}
|
}
|
||||||
DesfireClearIV(dctx);
|
|
||||||
DesfireGenSessionKeyEV2(dctx->key, RndA, RndB, true, dctx->sessionKeyEnc);
|
memcpy(dctx->sessionKeyEnc, sessionkey, CRYPTO_AES_BLOCK_SIZE);
|
||||||
DesfireGenSessionKeyEV2(dctx->key, RndA, RndB, false, dctx->sessionKeyMAC);
|
memcpy(dctx->sessionKeyMAC, sessionkey, CRYPTO_AES_BLOCK_SIZE);
|
||||||
dctx->secureChannel = secureChannel;
|
dctx->secureChannel = secureChannel;
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
if (firstauth) {
|
if (firstauth) {
|
||||||
PrintAndLogEx(INFO, "TI : %s", sprint_hex(data, 4));
|
PrintAndLogEx(INFO, "TI : %s", sprint_hex(data, 4));
|
||||||
PrintAndLogEx(INFO, "pic : %s", sprint_hex(&data[20], 6));
|
PrintAndLogEx(INFO, "pic : %s", sprint_hex(&data[4], 6));
|
||||||
PrintAndLogEx(INFO, "pcd : %s", sprint_hex(&data[26], 6));
|
PrintAndLogEx(INFO, "pcd : %s", sprint_hex(&data[10], 6));
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(INFO, "TI : %s", sprint_hex(dctx->TI, 4));
|
PrintAndLogEx(INFO, "TI : %s", sprint_hex(dctx->TI, 4));
|
||||||
}
|
}
|
||||||
|
|
|
@ -195,7 +195,7 @@ void LRPDecode(LRPContext *ctx, uint8_t *data, size_t datalen, uint8_t *resp, si
|
||||||
void LRPEncDec(uint8_t *key, uint8_t *iv, bool encode, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen) {
|
void LRPEncDec(uint8_t *key, uint8_t *iv, bool encode, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen) {
|
||||||
LRPContext ctx = {0};
|
LRPContext ctx = {0};
|
||||||
|
|
||||||
LRPSetKeyEx(&ctx, key, iv, 4 * 2, 0, false);
|
LRPSetKeyEx(&ctx, key, iv, 4 * 2, 0, true);
|
||||||
if (encode)
|
if (encode)
|
||||||
LRPEncode(&ctx, data, datalen, resp, resplen);
|
LRPEncode(&ctx, data, datalen, resp, resplen);
|
||||||
else
|
else
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue