This commit is contained in:
iceman1001 2019-12-17 13:38:08 +01:00
commit b6db3bb43a
2 changed files with 206 additions and 16 deletions

View file

@ -292,7 +292,7 @@ static int usage_hf_felica_authentication1() {
PrintAndLogEx(NORMAL, " - Number of Services m: 1-byte (1 <= n <= 8)");
PrintAndLogEx(NORMAL, " - Service Code List: 2n byte");
PrintAndLogEx(NORMAL, " - 3DES-Key: 128-bit master secret used for the encryption");
PrintAndLogEx(NORMAL, " - M1c: Encrypted random number (challenge for tag authentication) 8-byte");
PrintAndLogEx(NORMAL, " - M1c: Encrypted random number - challenge for tag authentication (8-byte)");
PrintAndLogEx(NORMAL, " - Response:");
PrintAndLogEx(NORMAL, " - Response Code: 11h 1-byte");
PrintAndLogEx(NORMAL, " - Manufacture ID(IDm): 8-byte");
@ -301,13 +301,37 @@ static int usage_hf_felica_authentication1() {
PrintAndLogEx(NORMAL, " - Success: Card Mode switches to Mode1. You can check this with the request response command.");
PrintAndLogEx(NORMAL, " - Unsuccessful: Card should not respond at all.");
PrintAndLogEx(NORMAL, "\nUsage: hf felica auth1 [-h][-i] <01 Number of Areas hex> <0A0B... Area Code List hex> <01 Number of Services hex> <0A0B... Service Code List hex> <0x0102030405060809 3DES-key hex (128bit)>");
PrintAndLogEx(NORMAL, "\nUsage: hf felica auth1 [-h][-i] <01 Number of Areas hex> <0A0B... Area Code List hex> <01 Number of Services hex> <0A0B... Service Code List hex> <0x0102030405060809... 3DES-key hex (16-byte)>");
PrintAndLogEx(NORMAL, " -h this help");
PrintAndLogEx(NORMAL, " -i <0A0B0C ... hex> set custom IDm to use");
PrintAndLogEx(NORMAL, "\nExamples: ");
PrintAndLogEx(NORMAL, " hf felica auth1 01 0000 01 8B00 FFFFFFFFFFFFFFFF ");
PrintAndLogEx(NORMAL, " hf felica auth1 01 0000 01 8B00 FFFFFFFFAAAAAAAAFFFFFFFF ");
PrintAndLogEx(NORMAL, " hf felica auth1 -i 11100910C11BC407 01 0000 01 8B00 FFFFFFFFFFFFFFFF\n\n");
PrintAndLogEx(NORMAL, " hf felica auth1 01 0000 01 8B00 AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBB ");
PrintAndLogEx(NORMAL, " hf felica auth1 01 0000 01 8B00 AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA ");
PrintAndLogEx(NORMAL, " hf felica auth1 -i 11100910C11BC407 01 0000 01 8B00 AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBB\n\n");
return PM3_SUCCESS;
}
static int usage_hf_felica_authentication2() {
PrintAndLogEx(NORMAL, "\nInfo: Complete mutual authentication. This command can only be executed subsquent to Authentication1"
" command.");
PrintAndLogEx(NORMAL, " - Auth2 Parameters:");
PrintAndLogEx(NORMAL, " - Manufacturer IDm: (8-byte)");
PrintAndLogEx(NORMAL, " - M3c: card challenge (8-byte)");
PrintAndLogEx(NORMAL, " - 3DES Key: key used for decryption of M3c (16-byte)");
PrintAndLogEx(NORMAL, " - Response (encrypted):");
PrintAndLogEx(NORMAL, " - Response Code: 13h (1-byte)");
PrintAndLogEx(NORMAL, " - IDtc: (8-byte)");
PrintAndLogEx(NORMAL, " - IDi (encrypted): (8-byte)");
PrintAndLogEx(NORMAL, " - PMi (encrypted): (8-byte)");
PrintAndLogEx(NORMAL, " - Success: Card switches to mode2 and sends response frame.");
PrintAndLogEx(NORMAL, " - Unsuccessful: Card should not respond at all.");
PrintAndLogEx(NORMAL, "\nUsage: hf felica auth2 [-h][-i] <0102030405060708 M3c hex> <0x0102030405060809... 3DES-key hex (16-byte)>");
PrintAndLogEx(NORMAL, " -h this help");
PrintAndLogEx(NORMAL, " -i <0A0B0C ... hex> set custom IDm to use");
PrintAndLogEx(NORMAL, "\nExamples: ");
PrintAndLogEx(NORMAL, " hf felica auth2 0102030405060708 AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBB");
PrintAndLogEx(NORMAL, " hf felica auth2 -i 11100910C11BC407 0102030405060708 AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBB\n\n");
return PM3_SUCCESS;
}
@ -530,6 +554,18 @@ int send_wr_unencrypted(uint8_t flags, uint16_t datalen, uint8_t *data, bool ver
}
}
/**
* Reverses the master secret. Example: AA AA AA AA AA AA AA BB to BB AA AA AA AA AA AA AA
* @param master_key the secret which order will be reversed.
* @param length in bytes of the master secret.
* @param reverse_master_key output in which the reversed secret is stored.
*/
static void reverse_3des_key(uint8_t *master_key, int length, uint8_t *reverse_master_key) {
for (int i = 0; i < length; i++) {
reverse_master_key[i] = master_key[(length - 1) - i];
}
};
/**
* Command parser for auth1
* @param Cmd input data of the user.
@ -539,6 +575,7 @@ static int CmdHFFelicaAuthentication1(const char *Cmd) {
if (strlen(Cmd) < 4) {
return usage_hf_felica_authentication1();
}
PrintAndLogEx(INFO, "EXPERIMENTAL COMMAND");
uint8_t data[PM3_CMD_DATA_SIZE];
bool custom_IDm = false;
strip_cmds(Cmd);
@ -582,7 +619,7 @@ static int CmdHFFelicaAuthentication1(const char *Cmd) {
}
}
// READER CHALLENGE - (RANDOM To Encrypt)
// READER CHALLENGE - (RANDOM To Encrypt = Rac)
unsigned char input[8];
input[0] = 0x1;
input[1] = 0x2;
@ -592,19 +629,21 @@ static int CmdHFFelicaAuthentication1(const char *Cmd) {
input[5] = 0x6;
input[6] = 0x7;
input[7] = 0x8;
PrintAndLogEx(INFO, "Reader challenge (unencrypted): %s", sprint_hex(input, 8));
unsigned char output[8];
// Create M1c Challenge with 3DES (3 Keys = 24, 2 Keys = 16)
uint8_t master_key[PM3_CMD_DATA_SIZE];
mbedtls_des3_context des3_ctx;
mbedtls_des3_init(&des3_ctx);
if (param_getlength(Cmd, paramCount) == 24) {
param_gethex(Cmd, paramCount, master_key, 24);
if (param_getlength(Cmd, paramCount) == 48) {
param_gethex(Cmd, paramCount, master_key, 48);
mbedtls_des3_set3key_enc(&des3_ctx, master_key);
PrintAndLogEx(INFO, "3DES Master Secret: %s", sprint_hex(master_key, 12));
} else if (param_getlength(Cmd, paramCount) == 16) {
param_gethex(Cmd, paramCount, master_key, 16);
PrintAndLogEx(INFO, "3DES Master Secret: %s", sprint_hex(master_key, 24));
} else if (param_getlength(Cmd, paramCount) == 32) {
param_gethex(Cmd, paramCount, master_key, 32);
// Assumption: Master secret split in half for Kac, Kbc
mbedtls_des3_set2key_enc(&des3_ctx, master_key);
PrintAndLogEx(INFO, "3DES Master Secret: %s", sprint_hex(master_key, 8));
PrintAndLogEx(INFO, "3DES Master Secret: %s", sprint_hex(master_key, 16));
} else {
PrintAndLogEx(ERR, "Invalid key length");
return PM3_EINVARG;
@ -631,12 +670,149 @@ static int CmdHFFelicaAuthentication1(const char *Cmd) {
PrintAndLogEx(ERR, "\nGot no Response from card");
return PM3_ERFTRANS;
} else {
PrintAndLogEx(NORMAL, "AUTH1 SUCCESS!");
PrintAndLogEx(NORMAL, "%s", sprint_hex(resp.data.asBytes, 256));
felica_auth1_response_t auth1_response;
memcpy(&auth1_response, (felica_auth1_response_t *)resp.data.asBytes, sizeof(felica_auth1_response_t));
if (auth1_response.frame_response.IDm[0] != 0) {
PrintAndLogEx(SUCCESS, "\nGot auth1 response:");
PrintAndLogEx(SUCCESS, "IDm: %s", sprint_hex(auth1_response.frame_response.IDm, sizeof(auth1_response.frame_response.IDm)));
PrintAndLogEx(SUCCESS, "M2C: %s", sprint_hex(auth1_response.m2c, sizeof(auth1_response.m2c)));
PrintAndLogEx(SUCCESS, "M3C: %s", sprint_hex(auth1_response.m3c, sizeof(auth1_response.m3c)));
// Assumption: Key swap method used
uint8_t reverse_master_key[PM3_CMD_DATA_SIZE];
reverse_3des_key(master_key, 16, reverse_master_key);
mbedtls_des3_set2key_dec(&des3_ctx, reverse_master_key);
bool isKeyCorrect = false;
unsigned char p2c[8];
mbedtls_des3_crypt_ecb(&des3_ctx, auth1_response.m2c, p2c);
for (int i = 0; i < 8; i++) {
if (p2c[i] != input[i]) {
isKeyCorrect = false;
break;
} else {
isKeyCorrect = true;
}
}
if (isKeyCorrect) {
PrintAndLogEx(SUCCESS, "\nAuth1 done with correct key material! Use Auth2 now with M3C and same key");
} else {
PrintAndLogEx(INFO, "3DES secret (swapped decryption): %s", sprint_hex(reverse_master_key, 16));
PrintAndLogEx(INFO, "P2c: %s", sprint_hex(p2c, 8));
PrintAndLogEx(ERR, "Can't decrypt M2C with master secret (P1c != P2c)! Probably wrong keys or wrong decryption method");
}
}
}
return PM3_SUCCESS;
}
/**
* Command parser for auth2
* @param Cmd input data of the user.
* @return client result code.
*/
static int CmdHFFelicaAuthentication2(const char *Cmd) {
if (strlen(Cmd) < 2) {
return usage_hf_felica_authentication2();
}
PrintAndLogEx(INFO, "EXPERIMENTAL COMMAND - M2c/P2c will be not checked");
uint8_t data[PM3_CMD_DATA_SIZE];
bool custom_IDm = false;
strip_cmds(Cmd);
uint16_t datalen = 18; // Length (1), Command ID (1), IDm (8), M4c (8)
uint8_t paramCount = 0;
uint8_t flags = 0;
int i = 0;
while (Cmd[i] != '\0') {
if (Cmd[i] == '-') {
switch (tolower(Cmd[i + 1])) {
case 'h':
return usage_hf_felica_authentication2();
case 'i':
paramCount++;
custom_IDm = true;
if (!add_param(Cmd, paramCount, data, 2, 16)) {
return PM3_EINVARG;
}
paramCount++;
i += 16;
break;
default:
return usage_hf_felica_authentication1();
}
}
i++;
}
data[0] = int_to_hex(&datalen);
data[1] = 0x12; // Command ID
if (!custom_IDm && !check_last_idm(data, datalen)) {
return PM3_EINVARG;
}
// M3c (8)
unsigned char m3c[8];
if (add_param(Cmd, paramCount, m3c, 0, 16)) {
paramCount++;
} else {
return PM3_EINVARG;
}
// Create M4c challenge response with 3DES
uint8_t master_key[PM3_CMD_DATA_SIZE];
uint8_t reverse_master_key[PM3_CMD_DATA_SIZE];
mbedtls_des3_context des3_ctx;
mbedtls_des3_init(&des3_ctx);
unsigned char p3c[8];
if (param_getlength(Cmd, paramCount) == 32) {
param_gethex(Cmd, paramCount, master_key, 32);
reverse_3des_key(master_key, 16, reverse_master_key);
mbedtls_des3_set2key_dec(&des3_ctx, reverse_master_key);
mbedtls_des3_set2key_enc(&des3_ctx, master_key);
// Assumption: Key swap method used for E2
PrintAndLogEx(INFO, "3DES Master Secret (encryption): %s", sprint_hex(master_key, 16));
PrintAndLogEx(INFO, "3DES Master Secret (decryption): %s", sprint_hex(reverse_master_key, 16));
} else {
PrintAndLogEx(ERR, "Invalid key length");
return PM3_EINVARG;
}
// Decrypt m3c with reverse_master_key
mbedtls_des3_crypt_ecb(&des3_ctx, m3c, p3c);
PrintAndLogEx(INFO, "3DES decrypted M3c = P3c: %s", sprint_hex(p3c, 8));
// Encrypt p3c with master_key
unsigned char m4c[8];
mbedtls_des3_crypt_ecb(&des3_ctx, p3c, m4c);
PrintAndLogEx(INFO, "3DES encrypted M4c: %s", sprint_hex(m4c, 8));
// Add M4c Challenge to frame
int frame_position = 10;
for (int i = 0; i < 8; i++) {
data[frame_position++] = m4c[i];
}
AddCrc(data, datalen);
datalen += 2;
flags |= FELICA_APPEND_CRC;
flags |= FELICA_RAW;
PrintAndLogEx(INFO, "Client Send AUTH2 Frame: %s", sprint_hex(data, datalen));
clear_and_send_command(flags, datalen, data, 0);
PacketResponseNG resp;
if (!waitCmdFelica(0, &resp, 1)) {
PrintAndLogEx(ERR, "\nGot no Response from card");
return PM3_ERFTRANS;
} else {
felica_auth2_response_t auth2_response;
memcpy(&auth2_response, (felica_auth2_response_t *)resp.data.asBytes, sizeof(felica_auth2_response_t));
if (auth2_response.code[0] != 0x12) {
PrintAndLogEx(SUCCESS, "\nGot auth2 response:");
PrintAndLogEx(SUCCESS, "IDtc: %s", sprint_hex(auth2_response.IDtc, sizeof(auth2_response.IDtc)));
PrintAndLogEx(SUCCESS, "IDi (encrypted): %s", sprint_hex(auth2_response.IDi, sizeof(auth2_response.IDi)));
PrintAndLogEx(SUCCESS, "PMi (encrypted): %s", sprint_hex(auth2_response.PMi, sizeof(auth2_response.PMi)));
} else {
PrintAndLogEx(ERR, "\nGot wrong frame format.");
}
}
return PM3_SUCCESS;
}
/**
* Command parser for wrunencrypted.
* @param Cmd input data of the user.
@ -1644,8 +1820,8 @@ static command_t CommandTable[] = {
{"wrunencrypted", CmdHFFelicaWriteWithoutEncryption, IfPm3Felica, "write Block Data to an authentication-not-required Service."},
{"scsvcode", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire Area Code and Service Code."},
{"rqsyscode", CmdHFFelicaRequestSystemCode, IfPm3Felica, "acquire System Code registered to the card."},
{"auth1", CmdHFFelicaAuthentication1, IfPm3Felica, "authenticate a card. Start mutual authentication with Auth1 (v1)"},
{"auth2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "allow a card to authenticate a Reader/Writer. Auth2 (v1)"},
{"auth1", CmdHFFelicaAuthentication1, IfPm3Felica, "authenticate a card. Start mutual authentication with Auth1"},
{"auth2", CmdHFFelicaAuthentication2, IfPm3Felica, "allow a card to authenticate a Reader/Writer. Complete mutual authentication"},
{"read", CmdHFFelicaNotImplementedYet, IfPm3Felica, "read Block Data from authentication-required Service."},
//{"write", CmdHFFelicaNotImplementedYet, IfPm3Felica, "write Block Data to an authentication-required Service."},
//{"scsvcodev2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "verify the existence of Area or Service, and to acquire Key Version."},

View file

@ -220,6 +220,20 @@ typedef struct {
uint8_t option_version_list[4];
} PACKED felica_request_spec_response_t;
typedef struct {
felica_frame_response_t frame_response;
uint8_t m2c[8];
uint8_t m3c[8];
} PACKED felica_auth1_response_t;
typedef struct {
uint8_t code[1];
uint8_t IDtc[8];
uint8_t IDi[8];
uint8_t PMi[8];
} PACKED felica_auth2_response_t;
typedef enum FELICA_COMMAND {
FELICA_CONNECT = (1 << 0),
FELICA_NO_DISCONNECT = (1 << 1),