hf secc crypto bug fixes

This commit is contained in:
Antiklesys
2026-04-12 03:16:41 +08:00
parent 84bc068652
commit d331e57c78
4 changed files with 104 additions and 11 deletions
+4
View File
@@ -1,7 +1,11 @@
{
"_comment_KDD": "Optional 10-byte Key Diversification Data echoed in INITIALIZE UPDATE. When present and non-zero, the SCP02Key above is treated as the static MASTER GP key and diversified per-card via VISA-2 (separate K_ENC/K_MAC). All-zero or absent = no diversification (SCP02Key used directly).",
"_comment_KVN": "Optional 1-byte Key Version Number reported in INITIALIZE UPDATE. Default 0x01 matches the GP factory key set on most JCOP cards. Use 0xFF for an uninitialized JCOP factory test card.",
"UID": "00000000",
"AID": "A0000003820013000101",
"SCP02Key": "404142434445464748494A4B4C4D4E4F",
"KDD": "00000000000000000000",
"KVN": "01",
"ATS": "1478F7B10280590180415254454346477300011B",
"DefaultResponse": "6A82",
"APDUResponses": [
+32 -1
View File
@@ -40,6 +40,8 @@ typedef struct {
uint8_t atqa[2]; // big-endian: [0]=high byte, [1]=low byte
uint8_t sak;
uint8_t scp02_key[16]; // SCP02 master key (from JSON "SCP02Key")
uint8_t kdd[10]; // 10-byte Key Diversification Data (from JSON "KDD"); all-zero = no diversification
uint8_t kvn; // Key Version Number (from JSON "KVN", default 0x01)
uint8_t ats[20]; // ATS bytes without CRC (from JSON "ATS")
uint8_t ats_len; // actual number of valid bytes in ats[]
uint8_t default_resp[HID_APDU_MAX_RESP]; // fallback reply for unmatched APDUs (from JSON "DefaultResponse")
@@ -298,7 +300,7 @@ static int CmdHFHIDConfigSim(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
arg_str1("f", "file", "<fn>", "JSON file with UID, AID, SCP02Key (without .json extension)"),
arg_str1("f", "file", "<fn>", "JSON file with UID, AID, SCP02Key, optional KDD/KVN (no .json ext)"),
arg_int0("n", "num", "<dec>", "Exit after <n> reader interactions. 0 = infinite"),
arg_param_end
};
@@ -345,6 +347,33 @@ static int CmdHFHIDConfigSim(const char *Cmd) {
return PM3_EINVARG;
}
// Parse optional KDD (10 bytes). If present, ARM diversifies SCP02Key
// per-card via VISA-2 on each handshake. If absent, all-zero is sent and
// ARM uses SCP02Key directly (legacy "no diversification" mode).
uint8_t kdd[10] = {0};
if (json_object_get(root, "KDD") != NULL) {
size_t kdd_len = 0;
if (JsonLoadBufAsHex(root, "$.KDD", kdd, sizeof(kdd), &kdd_len) != 0 || kdd_len != 10) {
PrintAndLogEx(ERR, "JSON 'KDD' field invalid (must be 10 bytes)");
json_decref(root);
return PM3_EINVARG;
}
}
// Parse optional KVN (Key Version Number, 1 byte). Default 0x01 matches
// the GP factory key set on most JCOP-based config cards.
uint8_t kvn = 0x01;
if (json_object_get(root, "KVN") != NULL) {
uint8_t kvn_buf[1] = {0};
size_t kvn_len = 0;
if (JsonLoadBufAsHex(root, "$.KVN", kvn_buf, sizeof(kvn_buf), &kvn_len) != 0 || kvn_len != 1) {
PrintAndLogEx(ERR, "JSON 'KVN' field invalid (must be 1 byte)");
json_decref(root);
return PM3_EINVARG;
}
kvn = kvn_buf[0];
}
// Parse ATS (1-20 bytes, without CRC)
uint8_t ats[20] = {0};
size_t ats_len_sz = 0;
@@ -465,10 +494,12 @@ static int CmdHFHIDConfigSim(const char *Cmd) {
payload.atqa[1] = 0x00; // HID Config Card ATQA low byte
payload.sak = 0x38; // HID Config Card SAK
payload.ats_len = (uint8_t)ats_len;
payload.kvn = kvn;
payload.default_resp_len = has_default_resp ? (uint8_t)default_resp_len_sz : 0;
payload.apdu_count = apdu_count;
memcpy(payload.uid, uid, uidlen);
memcpy(payload.scp02_key, scp02_key, sizeof(scp02_key));
memcpy(payload.kdd, kdd, sizeof(kdd));
memcpy(payload.ats, ats, ats_len);
if (has_default_resp)
memcpy(payload.default_resp, default_resp, default_resp_len_sz);