mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-08-29 09:48:17 +00:00
Merge pull request #3365 from cindersocket/feat-iclass-des-transport
Add DES and plain iCLASS transport
This commit is contained in:
@@ -4,6 +4,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
||||
|
||||
## [unreleased][unreleased]
|
||||
- Added `hf mfdes getversion` command (@kormax)
|
||||
- Added DES transport mode support for iCLASS credential encode/decode helpers. (@cindersocket)
|
||||
- Changed `doc/magic_cards_notes.md` - updated the ID82xx / Hitag µ clone section with current Proxmark3 support, chip variations, default passwords and detection notes (@mishamyte)
|
||||
- Added two Mifare Classic keys into extensive dictionary which are hardcoded into Mifare Plus SE (@team-orangeBlue)
|
||||
- Fixed `hf mfp rdbl` when using "read multiple" blocks by decrypting the entire buffer instead of one block only (@team-orangeBlue)
|
||||
|
||||
+211
-82
@@ -140,6 +140,22 @@ typedef enum {
|
||||
TRIPLEDES
|
||||
} BLOCK79ENCRYPTION;
|
||||
|
||||
static void iclass_set_transport_mode(uint8_t *data, BLOCK79ENCRYPTION mode);
|
||||
static int iclass_apply_transport_mode_to_block(uint8_t *blk_data, const uint8_t *key, BLOCK79ENCRYPTION mode, bool encrypt);
|
||||
|
||||
static const CLIParserOption IClassEncodeEncryptionOpts[] = {
|
||||
{None, "none"},
|
||||
{DES, "des"},
|
||||
{TRIPLEDES, "2k3des"},
|
||||
{0, NULL},
|
||||
};
|
||||
|
||||
static const CLIParserOption IClassTransportEncryptionOpts[] = {
|
||||
{DES, "des"},
|
||||
{TRIPLEDES, "2k3des"},
|
||||
{0, NULL},
|
||||
};
|
||||
|
||||
// 16 bytes key
|
||||
static int iclass_load_transport(uint8_t *key, uint8_t n) {
|
||||
size_t keylen = 0;
|
||||
@@ -169,41 +185,100 @@ static int iclass_load_transport(uint8_t *key, uint8_t n) {
|
||||
|
||||
static void iclass_decrypt_transport(uint8_t *key, uint8_t limit, uint8_t *enc_data, uint8_t *dec_data, BLOCK79ENCRYPTION aa1_encryption) {
|
||||
|
||||
// tripledes
|
||||
mbedtls_des3_context ctx;
|
||||
mbedtls_des3_set2key_dec(&ctx, key);
|
||||
bool should_decrypt = false;
|
||||
switch (aa1_encryption) {
|
||||
case DES:
|
||||
case TRIPLEDES:
|
||||
should_decrypt = true;
|
||||
break;
|
||||
case RFU:
|
||||
case None:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
bool decrypted_block789 = false;
|
||||
for (uint8_t i = 0; i < limit; ++i) {
|
||||
|
||||
uint16_t idx = i * PICOPASS_BLOCK_SIZE;
|
||||
|
||||
switch (aa1_encryption) {
|
||||
// Right now, only 3DES is supported
|
||||
case TRIPLEDES:
|
||||
// Decrypt block 7,8,9 if configured.
|
||||
if (i > 6 && i <= 9 && memcmp(enc_data + idx, empty, PICOPASS_BLOCK_SIZE) != 0) {
|
||||
mbedtls_des3_crypt_ecb(&ctx, enc_data + idx, dec_data + idx);
|
||||
decrypted_block789 = true;
|
||||
}
|
||||
break;
|
||||
case DES:
|
||||
case RFU:
|
||||
case None:
|
||||
// Nothing to do for None anyway...
|
||||
default:
|
||||
continue;
|
||||
if (should_decrypt == false || i <= 6 || i > 9) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (memcmp(enc_data + idx, empty, PICOPASS_BLOCK_SIZE) == 0 || memcmp(enc_data + idx, zeros, PICOPASS_BLOCK_SIZE) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy(dec_data + idx, enc_data + idx, PICOPASS_BLOCK_SIZE);
|
||||
if (iclass_apply_transport_mode_to_block(dec_data + idx, key, aa1_encryption, false) != PM3_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
decrypted_block789 = true;
|
||||
|
||||
if (decrypted_block789) {
|
||||
// Set the 2 last bits of block6 to 0 to mark the data as decrypted
|
||||
dec_data[(6 * PICOPASS_BLOCK_SIZE) + 7] &= 0xFC;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void iclass_set_transport_mode(uint8_t *data, BLOCK79ENCRYPTION mode) {
|
||||
data[7] &= 0xFC;
|
||||
data[7] |= (mode & 0x03);
|
||||
}
|
||||
|
||||
static void iclass_des_block_transform(uint8_t *blk_data, const uint8_t *key, bool encrypt) {
|
||||
mbedtls_des_context ctx;
|
||||
if (encrypt) {
|
||||
mbedtls_des_setkey_enc(&ctx, key);
|
||||
} else {
|
||||
mbedtls_des_setkey_dec(&ctx, key);
|
||||
}
|
||||
mbedtls_des_crypt_ecb(&ctx, blk_data, blk_data);
|
||||
mbedtls_des_free(&ctx);
|
||||
}
|
||||
|
||||
static void iclass_2k3des_block_transform(uint8_t *blk_data, const uint8_t *key, bool encrypt) {
|
||||
mbedtls_des3_context ctx;
|
||||
if (encrypt) {
|
||||
mbedtls_des3_set2key_enc(&ctx, key);
|
||||
} else {
|
||||
mbedtls_des3_set2key_dec(&ctx, key);
|
||||
}
|
||||
mbedtls_des3_crypt_ecb(&ctx, blk_data, blk_data);
|
||||
mbedtls_des3_free(&ctx);
|
||||
}
|
||||
|
||||
static int iclass_apply_transport_mode_to_block(uint8_t *blk_data, const uint8_t *key, BLOCK79ENCRYPTION mode, bool encrypt) {
|
||||
if (blk_data == NULL) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case None:
|
||||
case RFU:
|
||||
return PM3_SUCCESS;
|
||||
case DES:
|
||||
iclass_des_block_transform(blk_data, key, encrypt);
|
||||
return PM3_SUCCESS;
|
||||
case TRIPLEDES:
|
||||
iclass_2k3des_block_transform(blk_data, key, encrypt);
|
||||
return PM3_SUCCESS;
|
||||
default:
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
}
|
||||
|
||||
static int iclass_apply_transport_mode_to_credential(uint8_t *credential, const uint8_t *key, BLOCK79ENCRYPTION mode, bool encrypt) {
|
||||
for (uint8_t blockno = 0; blockno < 3; blockno++) {
|
||||
int res = iclass_apply_transport_mode_to_block(credential + (blockno * PICOPASS_BLOCK_SIZE), key, mode, encrypt);
|
||||
if (res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static inline uint32_t leadingzeros(uint64_t a) {
|
||||
#if defined __GNUC__
|
||||
return __builtin_clzll(a);
|
||||
@@ -1200,6 +1275,8 @@ static int CmdHFiClassTagSim(const char *Cmd) {
|
||||
"the tool tries to load " ICLASS_DECRYPTION_BIN ".",
|
||||
"hf iclass tagsim --fc 101 --cn 1337\n"
|
||||
"hf iclass tagsim -w H10301 --fc 101 --cn 1337 --ki 0\n"
|
||||
"hf iclass tagsim -w H10301 --fc 101 --cn 1337 --enc none\n"
|
||||
"hf iclass tagsim -w H10301 --fc 101 --cn 1337 --enc des\n"
|
||||
"hf iclass tagsim -w H10301 --fc 101 --cn 1337 --kd 0102030405060708 --elite\n"
|
||||
"hf iclass tagsim --bin 10001111100000001010100011 --ki 0\n"
|
||||
"hf iclass tagsim -w H10301 --fc 101 --cn 1337 --ki 0 --enckey 00000000000000000000000000000000\n"
|
||||
@@ -1220,6 +1297,7 @@ static int CmdHFiClassTagSim(const char *Cmd) {
|
||||
arg_lit0(NULL, "raw", "Keys are already diversified, skip diversification"),
|
||||
arg_str0(NULL, "csn", "<hex>", "Custom CSN, 8 hex bytes (auto-generated if omitted)"),
|
||||
arg_str0(NULL, "enckey", "<hex>", "3DES transport key, 16 hex bytes"),
|
||||
arg_str0(NULL, "enc", "<none|des|2k3des>", "credential transport mode (default: 2k3des)"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
@@ -1272,9 +1350,15 @@ static int CmdHFiClassTagSim(const char *Cmd) {
|
||||
uint8_t *enckeyptr = NULL;
|
||||
bool have_enc_key = false;
|
||||
CLIGetHexWithReturn(ctx, 13, enc_key, &enc_key_len);
|
||||
BLOCK79ENCRYPTION enc_mode = TRIPLEDES;
|
||||
int enc_mode_res = CLIGetOptionList(arg_get_str(ctx, 14), IClassEncodeEncryptionOpts, (int *)&enc_mode);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (enc_mode_res != 0) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
// --- validation
|
||||
if ((rawkey + elite) > 1) {
|
||||
PrintAndLogEx(ERR, "Cannot combine --elite and --raw");
|
||||
@@ -1341,9 +1425,16 @@ static int CmdHFiClassTagSim(const char *Cmd) {
|
||||
have_enc_key = true;
|
||||
}
|
||||
|
||||
if (have_enc_key == false) {
|
||||
// try smart-card helper first, then fall back to file
|
||||
bool use_sc = IsCardHelperPresent(false);
|
||||
bool use_sc = false;
|
||||
if (enc_mode == None && have_enc_key) {
|
||||
PrintAndLogEx(WARNING, "Transport mode marker is none; --enckey will be ignored.");
|
||||
}
|
||||
|
||||
if (enc_mode != None && have_enc_key == false) {
|
||||
// Try smart-card helper for 2K3DES only, then fall back to file.
|
||||
if (enc_mode == TRIPLEDES) {
|
||||
use_sc = IsCardHelperPresent(false);
|
||||
}
|
||||
if (use_sc == false) {
|
||||
size_t keylen = 0;
|
||||
int res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&enckeyptr, &keylen);
|
||||
@@ -1361,6 +1452,10 @@ static int CmdHFiClassTagSim(const char *Cmd) {
|
||||
}
|
||||
}
|
||||
|
||||
if (enc_mode != None && have_enc_key == false) {
|
||||
enc_mode = None;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Build the 256-byte (32-block) dump in memory
|
||||
// ---------------------------------------------------------------
|
||||
@@ -1461,19 +1556,15 @@ static int CmdHFiClassTagSim(const char *Cmd) {
|
||||
memcpy(credential + 12, &packed.Bot, sizeof(packed.Bot));
|
||||
}
|
||||
|
||||
// Capture smart-card helper state before starting simulation (can't query mid-sim)
|
||||
bool use_sc = have_enc_key ? IsCardHelperPresent(false) : false;
|
||||
|
||||
// Encrypt credential blocks 7, 8, 9
|
||||
if (have_enc_key) {
|
||||
iclass_set_transport_mode(credential, enc_mode);
|
||||
if (enc_mode != None) {
|
||||
if (use_sc) {
|
||||
Encrypt(credential + 8, credential + 8);
|
||||
Encrypt(credential + 16, credential + 16);
|
||||
Encrypt(credential + 24, credential + 24);
|
||||
} else {
|
||||
iclass_encrypt_block_data(credential + 8, enc_key);
|
||||
iclass_encrypt_block_data(credential + 16, enc_key);
|
||||
iclass_encrypt_block_data(credential + 24, enc_key);
|
||||
} else if (iclass_apply_transport_mode_to_credential(credential + 8, enc_key, enc_mode, true) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Failed to encode credential transport blocks");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1599,15 +1690,16 @@ static int CmdHFiClassTagSim(const char *Cmd) {
|
||||
}
|
||||
}
|
||||
|
||||
if (have_enc_key) {
|
||||
iclass_set_transport_mode(new_cred, enc_mode);
|
||||
if (enc_mode != None) {
|
||||
if (use_sc) {
|
||||
Encrypt(new_cred + 8, new_cred + 8);
|
||||
Encrypt(new_cred + 16, new_cred + 16);
|
||||
Encrypt(new_cred + 24, new_cred + 24);
|
||||
} else {
|
||||
iclass_encrypt_block_data(new_cred + 8, enc_key);
|
||||
iclass_encrypt_block_data(new_cred + 16, enc_key);
|
||||
iclass_encrypt_block_data(new_cred + 24, enc_key);
|
||||
} else if (iclass_apply_transport_mode_to_credential(new_cred + 8, enc_key, enc_mode, true) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Failed to encode credential transport blocks");
|
||||
running = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2119,7 +2211,7 @@ static void iclass_decode_credentials(uint8_t *data) {
|
||||
static int CmdHFiClassDecrypt(const char *Cmd) {
|
||||
CLIParserContext *clictx;
|
||||
CLIParserInit(&clictx, "hf iclass decrypt",
|
||||
"3DES decrypt data\n"
|
||||
"DES/3DES decrypt data\n"
|
||||
"This is a naive implementation, it tries to decrypt every block after block 6.\n"
|
||||
"Correct behaviour would be to decrypt only the application areas where the key is valid,\n"
|
||||
"which is defined by the configuration block.\n"
|
||||
@@ -2135,8 +2227,9 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
|
||||
arg_str0("d", "data", "<hex>", "3DES encrypted data"),
|
||||
arg_str0("k", "key", "<hex>", "3DES transport key"),
|
||||
arg_str0("d", "data", "<hex>", "DES/3DES encrypted data"),
|
||||
arg_str0("k", "key", "<hex>", "DES/3DES transport key"),
|
||||
arg_str0(NULL, "enc", "[des|2k3des]", "transport encryption mode"),
|
||||
arg_lit0("v", "verbose", "verbose output"),
|
||||
arg_lit0(NULL, "d6", "decode as block 6"),
|
||||
arg_lit0("z", "dense", "dense dump output style"),
|
||||
@@ -2162,10 +2255,16 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
|
||||
|
||||
CLIGetHexWithReturn(clictx, 3, key, &key_len);
|
||||
|
||||
bool verbose = arg_get_lit(clictx, 4);
|
||||
bool use_decode6 = arg_get_lit(clictx, 5);
|
||||
bool dense_output = g_session.dense_output || arg_get_lit(clictx, 6);
|
||||
bool nosave = arg_get_lit(clictx, 7);
|
||||
int transport_mode = TRIPLEDES;
|
||||
if (CLIGetOptionList(arg_get_str(clictx, 4), IClassTransportEncryptionOpts, &transport_mode)) {
|
||||
CLIParserFree(clictx);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
bool verbose = arg_get_lit(clictx, 5);
|
||||
bool use_decode6 = arg_get_lit(clictx, 6);
|
||||
bool dense_output = g_session.dense_output || arg_get_lit(clictx, 7);
|
||||
bool nosave = arg_get_lit(clictx, 8);
|
||||
CLIParserFree(clictx);
|
||||
|
||||
// sanity checks
|
||||
@@ -2206,15 +2305,9 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
|
||||
bool use_sc = false;
|
||||
if (have_key == false) {
|
||||
use_sc = IsCardHelperPresent(verbose);
|
||||
if (use_sc == false) {
|
||||
size_t keylen = 0;
|
||||
res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&keyptr, &keylen);
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(INFO, "Couldn't find any decryption methods");
|
||||
free(decrypted);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
size_t keylen = 0;
|
||||
res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&keyptr, &keylen);
|
||||
if (res == PM3_SUCCESS) {
|
||||
if (keylen != 16) {
|
||||
PrintAndLogEx(ERR, "Failed to load transport key from file");
|
||||
free(keyptr);
|
||||
@@ -2223,21 +2316,30 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
|
||||
}
|
||||
memcpy(key, keyptr, sizeof(key));
|
||||
free(keyptr);
|
||||
have_key = true;
|
||||
} else if (use_sc == false) {
|
||||
PrintAndLogEx(INFO, "Couldn't find any decryption methods");
|
||||
free(decrypted);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
}
|
||||
|
||||
// tripledes
|
||||
mbedtls_des3_context ctx;
|
||||
mbedtls_des3_set2key_dec(&ctx, key);
|
||||
|
||||
// decrypt user supplied data
|
||||
if (have_data) {
|
||||
|
||||
uint8_t dec_data[PICOPASS_BLOCK_SIZE] = {0};
|
||||
if (use_sc) {
|
||||
memcpy(dec_data, enc_data, sizeof(dec_data));
|
||||
if (use_sc && transport_mode == TRIPLEDES) {
|
||||
Decrypt(enc_data, dec_data);
|
||||
} else if (have_key) {
|
||||
if (iclass_apply_transport_mode_to_block(dec_data, key, (BLOCK79ENCRYPTION)transport_mode, false) != PM3_SUCCESS) {
|
||||
free(decrypted);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
} else {
|
||||
mbedtls_des3_crypt_ecb(&ctx, enc_data, dec_data);
|
||||
PrintAndLogEx(INFO, "Couldn't find any decryption methods");
|
||||
free(decrypted);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "encrypted... %s", sprint_hex_inrow(enc_data, sizeof(enc_data)));
|
||||
@@ -2280,19 +2382,26 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
|
||||
memcpy(enc_data, decrypted + idx, PICOPASS_BLOCK_SIZE);
|
||||
|
||||
switch (aa1_encryption) {
|
||||
// Right now, only 3DES is supported
|
||||
case DES:
|
||||
case TRIPLEDES:
|
||||
// Decrypt block 7,8,9 if configured.
|
||||
if (blocknum > 6 && blocknum <= 9 && memcmp(enc_data, empty, PICOPASS_BLOCK_SIZE) != 0) {
|
||||
if (use_sc) {
|
||||
if (blocknum > 6 && blocknum <= 9 && memcmp(enc_data, empty, PICOPASS_BLOCK_SIZE) != 0 && memcmp(enc_data, zeros, PICOPASS_BLOCK_SIZE) != 0) {
|
||||
if (use_sc && aa1_encryption == TRIPLEDES) {
|
||||
Decrypt(enc_data, decrypted + idx);
|
||||
} else if (have_key) {
|
||||
memcpy(decrypted + idx, enc_data, PICOPASS_BLOCK_SIZE);
|
||||
if (iclass_apply_transport_mode_to_block(decrypted + idx, key, aa1_encryption, false) != PM3_SUCCESS) {
|
||||
free(decrypted);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
} else {
|
||||
mbedtls_des3_crypt_ecb(&ctx, enc_data, decrypted + idx);
|
||||
PrintAndLogEx(INFO, "Couldn't find any decryption methods");
|
||||
free(decrypted);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
decrypted_block789 = true;
|
||||
}
|
||||
break;
|
||||
case DES:
|
||||
case RFU:
|
||||
case None:
|
||||
// Nothing to do for None anyway...
|
||||
@@ -2362,14 +2471,13 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
|
||||
free(decrypted);
|
||||
}
|
||||
|
||||
mbedtls_des3_free(&ctx);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHFiClassEncryptBlk(const char *Cmd) {
|
||||
CLIParserContext *clictx;
|
||||
CLIParserInit(&clictx, "hf iclass encrypt",
|
||||
"3DES encrypt data\n"
|
||||
"DES/3DES encrypt data\n"
|
||||
"OBS! In order to use this function, the file 'iclass_decryptionkey.bin' must reside\n"
|
||||
"in the resources directory. The file should be 16 hex bytes of binary data",
|
||||
"hf iclass encrypt -d 0102030405060708\n"
|
||||
@@ -2378,7 +2486,8 @@ static int CmdHFiClassEncryptBlk(const char *Cmd) {
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str1("d", "data", "<hex>", "data to encrypt"),
|
||||
arg_str0("k", "key", "<hex>", "3DES transport key"),
|
||||
arg_str0("k", "key", "<hex>", "DES/3DES transport key"),
|
||||
arg_str0(NULL, "enc", "[des|2k3des]", "transport encryption mode"),
|
||||
arg_lit0("v", "verbose", "verbose output"),
|
||||
arg_param_end
|
||||
};
|
||||
@@ -2402,6 +2511,12 @@ static int CmdHFiClassEncryptBlk(const char *Cmd) {
|
||||
|
||||
CLIGetHexWithReturn(clictx, 2, key, &key_len);
|
||||
|
||||
int transport_mode = TRIPLEDES;
|
||||
if (CLIGetOptionList(arg_get_str(clictx, 3), IClassTransportEncryptionOpts, &transport_mode)) {
|
||||
CLIParserFree(clictx);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (key_len > 0) {
|
||||
if (key_len != 16) {
|
||||
PrintAndLogEx(ERR, "Transport key must be 16 hex bytes (32 HEX characters)");
|
||||
@@ -2411,13 +2526,15 @@ static int CmdHFiClassEncryptBlk(const char *Cmd) {
|
||||
have_key = true;
|
||||
}
|
||||
|
||||
bool verbose = arg_get_lit(clictx, 3);
|
||||
bool verbose = arg_get_lit(clictx, 4);
|
||||
|
||||
CLIParserFree(clictx);
|
||||
|
||||
bool use_sc = false;
|
||||
if (have_key == false) {
|
||||
use_sc = IsCardHelperPresent(verbose);
|
||||
if (transport_mode == TRIPLEDES) {
|
||||
use_sc = IsCardHelperPresent(verbose);
|
||||
}
|
||||
if (use_sc == false) {
|
||||
size_t keylen = 0;
|
||||
int res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&keyptr, &keylen);
|
||||
@@ -2439,10 +2556,10 @@ static int CmdHFiClassEncryptBlk(const char *Cmd) {
|
||||
|
||||
PrintAndLogEx(SUCCESS, "plain....... %s", sprint_hex_inrow(blk_data, sizeof(blk_data)));
|
||||
|
||||
if (use_sc) {
|
||||
if (use_sc && transport_mode == TRIPLEDES) {
|
||||
Encrypt(blk_data, blk_data);
|
||||
} else {
|
||||
iclass_encrypt_block_data(blk_data, key);
|
||||
} else if (iclass_apply_transport_mode_to_block(blk_data, key, (BLOCK79ENCRYPTION)transport_mode, true) != PM3_SUCCESS) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "encrypted... " _YELLOW_("%s"), sprint_hex_inrow(blk_data, sizeof(blk_data)));
|
||||
@@ -7371,6 +7488,7 @@ static int CmdHFiClassEncode(const char *Cmd) {
|
||||
arg_lit0(NULL, "emu", "Write to emulation memory instead of card"),
|
||||
arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"),
|
||||
arg_lit0("v", NULL, "verbose (print encoded blocks)"),
|
||||
arg_str0(NULL, "enc", "[none|des|2k3des]", "transport encryption mode"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
@@ -7454,6 +7572,11 @@ static int CmdHFiClassEncode(const char *Cmd) {
|
||||
|
||||
bool shallow_mod = arg_get_lit(ctx, 13);
|
||||
bool verbose = arg_get_lit(ctx, 14);
|
||||
int transport_mode = TRIPLEDES;
|
||||
if (CLIGetOptionList(arg_get_str(ctx, 15), IClassEncodeEncryptionOpts, &transport_mode)) {
|
||||
CLIParserFree(ctx);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
@@ -7470,6 +7593,10 @@ static int CmdHFiClassEncode(const char *Cmd) {
|
||||
have_enc_key = true;
|
||||
}
|
||||
|
||||
if (transport_mode == None && enc_key_len != 0) {
|
||||
PrintAndLogEx(WARNING, "Transport mode marker is none; --enckey will be ignored.");
|
||||
}
|
||||
|
||||
if (bin_len > 64) {
|
||||
PrintAndLogEx(ERR, "Binary wiegand string must be less than 64 bits");
|
||||
return PM3_EINVARG;
|
||||
@@ -7480,9 +7607,9 @@ static int CmdHFiClassEncode(const char *Cmd) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (have_enc_key == false) {
|
||||
if (transport_mode != None && have_enc_key == false) {
|
||||
// The IsCardHelperPresent function clears the emulator memory
|
||||
if (use_emulator_memory) {
|
||||
if (use_emulator_memory || transport_mode != TRIPLEDES) {
|
||||
use_sc = false;
|
||||
} else {
|
||||
use_sc = IsCardHelperPresent(false);
|
||||
@@ -7567,18 +7694,20 @@ static int CmdHFiClassEncode(const char *Cmd) {
|
||||
memcpy(credential + 12, &packed.Bot, sizeof(packed.Bot));
|
||||
}
|
||||
|
||||
// encrypt with transport key
|
||||
if (use_sc) {
|
||||
Encrypt(credential + 8, credential + 8);
|
||||
Encrypt(credential + 16, credential + 16);
|
||||
Encrypt(credential + 24, credential + 24);
|
||||
} else {
|
||||
iclass_encrypt_block_data(credential + 8, enc_key);
|
||||
iclass_encrypt_block_data(credential + 16, enc_key);
|
||||
iclass_encrypt_block_data(credential + 24, enc_key);
|
||||
iclass_set_transport_mode(credential, (BLOCK79ENCRYPTION)transport_mode);
|
||||
if (transport_mode != None) {
|
||||
if (use_sc) {
|
||||
Encrypt(credential + 8, credential + 8);
|
||||
Encrypt(credential + 16, credential + 16);
|
||||
Encrypt(credential + 24, credential + 24);
|
||||
} else if (iclass_apply_transport_mode_to_credential(credential + 8, enc_key, (BLOCK79ENCRYPTION)transport_mode, true) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Failed to apply transport mode");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "Mode: %s", CLIGetOptionListStr(IClassEncodeEncryptionOpts, transport_mode));
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
PrintAndLogEx(INFO, "Block %d/0x0%x -> " _YELLOW_("%s"), 6 + i, 6 + i, sprint_hex_inrow(credential + (i * 8), 8));
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ TESTALL=false
|
||||
TESTDESFIREVALUE=false
|
||||
TESTHIDWIEGAND=false
|
||||
TESTMFHIDENCODE=false
|
||||
TESTICLASSREADER=false
|
||||
NEED_MF_HID_ENCODE_WIPE=false
|
||||
TESTMANUAL=false
|
||||
|
||||
@@ -20,12 +21,14 @@ while (( "$#" )); do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
echo """
|
||||
Usage: $0 [--pm3bin /path/to/pm3] [desfire_value|hid_wiegand|mf_hid_encode]
|
||||
Usage: $0 [--pm3bin /path/to/pm3] [--pm3port /dev/tty...] [desfire_value|hid_wiegand|mf_hid_encode|iclass_reader]
|
||||
--pm3bin ...: Specify path to pm3 binary to test
|
||||
--pm3port ...: Specify serial port for client/proxmark3
|
||||
--manual ...: Pause after successful online LF HID clone/read checks for external reader verification
|
||||
desfire_value: Test DESFire value operations with card
|
||||
hid_wiegand: Test LF HID T55xx clone and PM3 readback flows
|
||||
mf_hid_encode: Test MIFARE Classic HID encoding flows
|
||||
iclass_reader: Load iCLASS HID credentials into emulator memory for external reader verification
|
||||
You must specify a test target - no default 'all' for online tests
|
||||
"""
|
||||
exit 0
|
||||
@@ -39,6 +42,15 @@ Usage: $0 [--pm3bin /path/to/pm3] [desfire_value|hid_wiegand|mf_hid_encode]
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--pm3port)
|
||||
if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then
|
||||
PM3PORT=$2
|
||||
shift 2
|
||||
else
|
||||
echo "Error: Argument for $1 is missing" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--manual)
|
||||
TESTMANUAL=true
|
||||
shift
|
||||
@@ -58,6 +70,11 @@ Usage: $0 [--pm3bin /path/to/pm3] [desfire_value|hid_wiegand|mf_hid_encode]
|
||||
TESTMFHIDENCODE=true
|
||||
shift
|
||||
;;
|
||||
iclass_reader)
|
||||
TESTALL=false
|
||||
TESTICLASSREADER=true
|
||||
shift
|
||||
;;
|
||||
-*|--*=) # unsupported flags
|
||||
echo "Error: Unsupported flag $1" >&2
|
||||
exit 1
|
||||
@@ -341,7 +358,7 @@ if command -v git >/dev/null && git rev-parse --is-inside-work-tree >/dev/null 2
|
||||
fi
|
||||
|
||||
# Check that user specified a test
|
||||
if [ "$TESTDESFIREVALUE" = false ] && [ "$TESTHIDWIEGAND" = false ] && [ "$TESTMFHIDENCODE" = false ]; then
|
||||
if [ "$TESTDESFIREVALUE" = false ] && [ "$TESTHIDWIEGAND" = false ] && [ "$TESTMFHIDENCODE" = false ] && [ "$TESTICLASSREADER" = false ]; then
|
||||
echo "Error: You must specify a test target. Use -h for help."
|
||||
exit 1
|
||||
fi
|
||||
@@ -399,6 +416,28 @@ while true; do
|
||||
if ! RestoreMfHidEncodeCard; then break; fi
|
||||
if ! CheckMfHidEncodeCleanup "hf mf encodehid cleanup verify"; then break; fi
|
||||
fi
|
||||
|
||||
if $TESTICLASSREADER; then
|
||||
echo -e "\n${C_BLUE}Testing iCLASS reader verification${C_NC} ${PM3BIN:=./pm3}"
|
||||
if ! CheckFileExist "pm3 exists" "$PM3BIN"; then break; fi
|
||||
if [ -z "${PM3PORT:-}" ]; then
|
||||
PM3PORT="$(ls /dev/cu.usbmodem* 2>/dev/null | head -n 1 || true)"
|
||||
fi
|
||||
if [ -z "${PM3PORT:-}" ]; then
|
||||
echo "Error: No Proxmark3 serial port found. Pass --pm3port /dev/tty..."
|
||||
break
|
||||
fi
|
||||
echo "Using PM3 port: $PM3PORT"
|
||||
PM3CMD="$PM3BIN"
|
||||
PM3CMD="$PM3CMD $PM3PORT"
|
||||
|
||||
WaitForEnter "PRESS ENTER TO START ICLASS PLAIN SIM, PRESENT THE PM3 TO ANOTHER READER, CONFIRM: iCLASS H10301 FC 31 CN 337, THEN PRESS THE PM3 BUTTON TO STOP SIM"
|
||||
if ! CheckExecute "hf iclass emu reader plain" "$PM3CMD -c 'hf iclass tagsim -w H10301 --fc 31 --cn 337 --enc none' 2>&1" "Uploaded .* bytes to emulator memory"; then break; fi
|
||||
WaitForEnter "PRESS ENTER TO START ICLASS DES SIM, PRESENT THE PM3 TO ANOTHER READER, CONFIRM: iCLASS H10301 FC 31 CN 337, THEN PRESS THE PM3 BUTTON TO STOP SIM"
|
||||
if ! CheckExecute "hf iclass emu reader des" "$PM3CMD -c 'hf iclass tagsim -w H10301 --fc 31 --cn 337 --enc des' 2>&1" "Uploaded .* bytes to emulator memory"; then break; fi
|
||||
WaitForEnter "PRESS ENTER TO START ICLASS 2K3DES SIM, PRESENT THE PM3 TO ANOTHER READER, CONFIRM: iCLASS H10301 FC 31 CN 337, THEN PRESS THE PM3 BUTTON TO STOP SIM"
|
||||
if ! CheckExecute "hf iclass emu reader 2k3des" "$PM3CMD -c 'hf iclass tagsim -w H10301 --fc 31 --cn 337 --enc 2k3des' 2>&1" "Uploaded .* bytes to emulator memory"; then break; fi
|
||||
fi
|
||||
|
||||
echo -e "\n------------------------------------------------------------"
|
||||
echo -e "Tests [ ${C_GREEN}OK${C_NC} ] ${C_OK}\n"
|
||||
|
||||
@@ -500,6 +500,15 @@ while true; do
|
||||
if ! CheckExecute "wiegand decode new no padded bin" "if ! $CLIENTBIN -c 'wiegand decode --new 06BD88EB80' 2>&1 | grep -q 'padded bin'; then echo OK; fi" "OK"; then break; fi
|
||||
if ! CheckExecute "wiegand decode new 96-bit" "$CLIENTBIN -c 'wiegand decode --new 00555555555555555555555555'" "hex\\.{14} 555555555555555555555555"; then break; fi
|
||||
if ! CheckExecute "wiegand decode new 48-bit" "$CLIENTBIN -c 'wiegand decode --new 0000A4550148AB'" "C1k48s.*FC: 42069 CN: 42069 parity \( ok \)"; then break; fi
|
||||
|
||||
if ! CheckFileExist "iCLASS transport key exists" "$RESOURCEPATH/iclass_decryptionkey.bin"; then break; fi
|
||||
ICLASS_TRANSPORT_KEY="$(od -An -tx1 -v "$RESOURCEPATH/iclass_decryptionkey.bin" | tr -d ' \n')"
|
||||
if ! CheckExecute "hf iclass encrypt default 2k3des" "$CLIENTBIN -c 'hf iclass encrypt -d 00000000063E02A3 -k $ICLASS_TRANSPORT_KEY'" "encrypted\\.\\.\\. 10A145919ED16F50"; then break; fi
|
||||
if ! CheckExecute "hf iclass decrypt default 2k3des" "$CLIENTBIN -c 'hf iclass decrypt -d 10A145919ED16F50 -k $ICLASS_TRANSPORT_KEY'" "plain\\.\\.\\.\\.\\.\\.\\. 00000000063E02A3"; then break; fi
|
||||
if ! CheckExecute "hf iclass encrypt des" "$CLIENTBIN -c 'hf iclass encrypt -d 00000000063E02A3 --enc des -k $ICLASS_TRANSPORT_KEY'" "encrypted\\.\\.\\. D50D3FC66AF7E0F3"; then break; fi
|
||||
if ! CheckExecute "hf iclass decrypt des" "$CLIENTBIN -c 'hf iclass decrypt -d D50D3FC66AF7E0F3 --enc des -k $ICLASS_TRANSPORT_KEY'" "plain\\.\\.\\.\\.\\.\\.\\. 00000000063E02A3"; then break; fi
|
||||
if ! CheckExecute "hf iclass view dump" "$CLIENTBIN -c 'hf iclass view -f traces/iclass/hf-iclass-dump.json'" "7/0x07 \\| 78 36 02 A2 28 30 10 E8"; then break; fi
|
||||
if ! CheckExecute "hf iclass decrypt dump" "$CLIENTBIN -c 'hf iclass decrypt -f traces/iclass/hf-iclass-dump.json --ns -k $ICLASS_TRANSPORT_KEY'" "C1k48s.*FC: 69 CN: 69420 parity \\( ok \\)"; then break; fi
|
||||
if ! CheckExecute "wiegand Verkada40 encode test 1" "$CLIENTBIN -c 'wiegand encode -w Verkada40 --fc 50 --cn 1001'" "86400007D3"; then break; fi
|
||||
if ! CheckExecute "wiegand Verkada40 decode test 1" "$CLIENTBIN -c 'wiegand decode --raw 86400007D3'" "Verkada40.*FC: 50 CN: 1001 parity \( ok \)"; then break; fi
|
||||
if ! CheckExecute "wiegand Verkada40 encode test 2" "$CLIENTBIN -c 'wiegand encode -w Verkada40 --fc 50 --cn 1004'" "86400007D9"; then break; fi
|
||||
|
||||
Reference in New Issue
Block a user