This is the major changes made to the HITAG2 commands. Its heavly based on RFIDLers implementation and its been converted to work with Proxmark3. Special thanks to @kevsecurity for his amazing implementations of the Gone in 360 Seconds paper by Roel, Flavio & Balasch. Thanks to @adamlaurie for his RFIDler project. It wouldnt been doable without it.

This commit is contained in:
iceman1001
2024-04-22 16:20:24 +02:00
parent fc2a3dd2c5
commit c8849af5e0
20 changed files with 2703 additions and 708 deletions
+4
View File
@@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
## [unreleased][unreleased]
- Changed `lf hitag dump --nrar` - now supports attack 1 from "gone in 360 seconds" paper. Thanks @kevsecurity! (@iceman1001)
- Added `lf hitag selftest` - converted from RFIDLers selftest (@iceman1001)
- Added `lf hitag chk` - dictionary attack against card (@iceman1001)
- Added `lf hitag lookup` - verify collected challenges aginst dictionary (@iceman1001)
- Updated windows workflow to use latest setup-wsl script (@iceman1001)
- Added a micro second clock in the client (@iceman1001)
- Fix `hf mfdes read` - buffer overflow when reading large files (@iceman1001)
+1 -1
View File
@@ -71,7 +71,7 @@ else
endif
ifneq (,$(findstring WITH_HITAG,$(APP_CFLAGS)))
SRC_HITAG = hitag2_crypto.c hitag2.c hitagS.c
SRC_HITAG = hitag2_crypto.c hitag2.c hitagS.c hitag2_crack.c
APP_CFLAGS += -I../common/hitag2
else
SRC_HITAG =
+32 -12
View File
@@ -40,6 +40,7 @@
#include "thinfilm.h"
#include "felica.h"
#include "hitag2.h"
#include "hitag2_crack.h"
#include "hitagS.h"
#include "em4x50.h"
#include "em4x70.h"
@@ -1131,16 +1132,32 @@ static void PacketReceived(PacketCommandNG *packet) {
#ifdef WITH_HITAG
case CMD_LF_HITAG_SNIFF: { // Eavesdrop Hitag tag, args = type
SniffHitag2(true);
// SniffHitag2(packet->oldarg[0]);
//hitag_sniff();
reply_ng(CMD_LF_HITAG_SNIFF, PM3_SUCCESS, NULL, 0);
break;
}
case CMD_LF_HITAG_SIMULATE: { // Simulate Hitag tag, args = memory content
SimulateHitag2(true);
break;
}
case CMD_LF_HITAG2_CRACK: {
lf_hitag_data_t *payload = (lf_hitag_data_t *) packet->data.asBytes;
ht2_crack(payload->NrAr);
break;
}
case CMD_LF_HITAG_READER: { // Reader for Hitag tags, args = type and function
ReaderHitag((hitag_function)packet->oldarg[0], (hitag_data *)packet->data.asBytes, true);
lf_hitag_data_t *payload = (lf_hitag_data_t *) packet->data.asBytes;
switch (payload->cmd) {
case RHT2F_UID_ONLY: {
ht2_read_uid(NULL, true, true, false);
break;
}
default: {
ReaderHitag(payload, true);
break;
}
}
break;
}
case CMD_LF_HITAGS_SIMULATE: { // Simulate Hitag s tag, args = memory content
@@ -1148,25 +1165,28 @@ static void PacketReceived(PacketCommandNG *packet) {
break;
}
case CMD_LF_HITAGS_TEST_TRACES: { // Tests every challenge within the given file
Hitag_check_challenges(packet->data.asBytes, packet->oldarg[0], true);
Hitag_check_challenges(packet->data.asBytes, packet->length, true);
break;
}
case CMD_LF_HITAGS_READ: { //Reader for only Hitag S tags, args = key or challenge
ReadHitagS((hitag_function)packet->oldarg[0], (hitag_data *)packet->data.asBytes, true);
case CMD_LF_HITAGS_READ: { // Reader for only Hitag S tags, args = key or challenge
lf_hitag_data_t *payload = (lf_hitag_data_t *) packet->data.asBytes;
ReadHitagS(payload, true);
break;
}
case CMD_LF_HITAGS_WRITE: { //writer for Hitag tags args=data to write,page and key or challenge
if ((hitag_function)packet->oldarg[0] < 10) {
WritePageHitagS((hitag_function)packet->oldarg[0], (hitag_data *)packet->data.asBytes, packet->oldarg[2], true);
} else {
WriterHitag((hitag_function)packet->oldarg[0], (hitag_data *)packet->data.asBytes, packet->oldarg[2], true);
}
case CMD_LF_HITAGS_WRITE: {
lf_hitag_data_t *payload = (lf_hitag_data_t *) packet->data.asBytes;
WritePageHitagS(payload, true);
break;
}
case CMD_LF_HITAG2_WRITE: {
lf_hitag_data_t *payload = (lf_hitag_data_t *) packet->data.asBytes;
WriterHitag(payload, true);
break;
}
case CMD_LF_HITAG_ELOAD: {
lf_hitag_t *payload = (lf_hitag_t *) packet->data.asBytes;
uint8_t *mem = BigBuf_get_EM_addr();
memcpy((uint8_t *)mem, payload->data, payload->len);
memcpy(mem, payload->data, payload->len);
break;
}
#endif
+641 -220
View File
File diff suppressed because it is too large Load Diff
+7 -3
View File
@@ -23,8 +23,12 @@
#include "hitag.h"
void SniffHitag2(bool ledcontrol);
void hitag_sniff(void);
void SimulateHitag2(bool ledcontrol);
void ReaderHitag(hitag_function htf, const hitag_data *htd, bool ledcontrol);
void WriterHitag(hitag_function htf, const hitag_data *htd, int page, bool ledcontrol);
void EloadHitag(const uint8_t *data, uint16_t len);
void ReaderHitag(const lf_hitag_data_t *payload, bool ledcontrol);
void WriterHitag(const lf_hitag_data_t *payload, bool ledcontrol);
bool ht2_packbits(uint8_t *nrz_samples, size_t nrzs, uint8_t *rx, size_t *rxlen);
int ht2_read_uid(uint8_t *uid, bool ledcontrol, bool send_answer, bool keep_field_up);
int ht2_tx_rx(uint8_t *tx, size_t txlen, uint8_t *rx, size_t *rxlen, bool ledcontrol, bool keep_field_up);
#endif
+309 -159
View File
File diff suppressed because it is too large Load Diff
+2 -3
View File
@@ -22,11 +22,10 @@
#define _HITAGS_H_
#include "common.h"
#include "hitag.h"
void SimulateHitagSTag(bool tag_mem_supplied, const uint8_t *data, bool ledcontrol);
void ReadHitagS(hitag_function htf, const hitag_data *htd, bool ledcontrol);
void WritePageHitagS(hitag_function htf, const hitag_data *htd, int page, bool ledcontrol);
void ReadHitagS(const lf_hitag_data_t *payload, bool ledcontrol);
void WritePageHitagS(const lf_hitag_data_t *payload, bool ledcontrol);
void Hitag_check_challenges(const uint8_t *data, uint32_t datalen, bool ledcontrol);
#endif
+1
View File
@@ -263,6 +263,7 @@ set (TARGET_SOURCES
${PM3_ROOT}/common/cardhelper.c
${PM3_ROOT}/common/generator.c
${PM3_ROOT}/common/bruteforce.c
${PM3_ROOT}/common/hitag2/hitag2_crypto.c
${PM3_ROOT}/client/src/crypto/asn1dump.c
${PM3_ROOT}/client/src/crypto/asn1utils.c
${PM3_ROOT}/client/src/crypto/libpcrypto.c
+18 -6
View File
@@ -1,13 +1,25 @@
#
# Mifare Default Keys
# -- Iceman version --
# -- contribute to this list, sharing is caring --
#
# Lets see how long it takes before other project takes this file
# and claim they created it.
#
# factory HT2 pwd
4D494B52
# factory HT2 crypto key
4F4E4D494B52
#
# GE HT2 reader
#
# TSPL
5453504C
05040202
25293C2F
# Gone in 360 seconds
FFFF814632FF
#
# Paxton HT2
BDF5E846
#
#
# GE HT2 reader
# TSPL
5453504C
05040202
25293C2F
+1107 -173
View File
File diff suppressed because it is too large Load Diff
+5 -2
View File
@@ -22,6 +22,7 @@
#include "common.h"
#define HITAG_NRAR_SIZE 8
#define HITAG_CRYPTOKEY_SIZE 6
#define HITAG_PASSWORD_SIZE 4
#define HITAG_UID_SIZE 4
@@ -37,16 +38,18 @@
#define HITAG2_CONFIG_BLOCK 3
#define HITAG2_CONFIG_OFFSET (HITAG_BLOCK_SIZE * HITAG2_CONFIG_BLOCK)
#define HITAG_DICTIONARY "ht2_default"
int CmdLFHitag(const char *Cmd);
int readHitagUid(void);
void annotateHitag1(char *exp, size_t size, const uint8_t *cmd, uint8_t cmdsize, bool is_response);
void annotateHitag2(char *exp, size_t size, const uint8_t *cmd, uint8_t cmdsize, uint8_t bits, bool is_response);
void annotateHitag2(char *exp, size_t size, const uint8_t *cmd, uint8_t cmdsize, uint8_t bits, bool is_response, const uint64_t *keys, uint32_t keycount, bool isdecrypted);
void annotateHitagS(char *exp, size_t size, const uint8_t *cmd, uint8_t cmdsize, bool is_response);
void annotateHitag2_init(void);
bool hitag2_get_plain(uint8_t *plain, uint8_t *plen);
void hitag2_annotate_plain(char *exp, size_t size, const uint8_t *cmd, uint8_t cmdsize, uint8_t bits);
uint8_t hitag1_CRC_check(uint8_t *d, uint32_t nbit);
#endif
+103 -12
View File
@@ -501,7 +501,7 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
uint32_t end_of_transmission_timestamp = 0;
uint8_t topaz_reader_command[9];
char explanation[40] = {0};
char explanation[60] = {0};
tracelog_hdr_t *first_hdr = (tracelog_hdr_t *)(trace);
tracelog_hdr_t *hdr = (tracelog_hdr_t *)(trace + tracepos);
@@ -736,9 +736,9 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
// mark short bytes (less than 8 Bit + Parity)
if (protocol == ISO_14443A ||
protocol == PROTO_MIFARE ||
protocol == PROTO_MFPLUS ||
protocol == THINFILM) {
protocol == PROTO_MIFARE ||
protocol == PROTO_MFPLUS ||
protocol == THINFILM) {
// approximated with 128 * (9 * data_len);
uint16_t bitime = 1056 + 32;
@@ -774,10 +774,9 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
end_of_transmission_timestamp = hdr->timestamp + duration;
if (prev_eot)
if (prev_eot) {
*prev_eot = end_of_transmission_timestamp;
}
// Always annotate these protocols both reader/tag messages
switch (protocol) {
@@ -793,7 +792,7 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
annotateHitag1(explanation, sizeof(explanation), frame, data_len, hdr->isResponse);
break;
case PROTO_HITAG2:
annotateHitag2(explanation, sizeof(explanation), frame, data_len, parityBytes[0], hdr->isResponse);
annotateHitag2(explanation, sizeof(explanation), frame, data_len, parityBytes[0], hdr->isResponse, mfDicKeys, mfDicKeysCount, false);
break;
case PROTO_HITAGS:
annotateHitagS(explanation, sizeof(explanation), frame, data_len, hdr->isResponse);
@@ -979,6 +978,71 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
}
}
if (protocol == PROTO_HITAG2) {
uint8_t ht2plain[9] = {0};
uint8_t n = 0;
if (hitag2_get_plain(ht2plain, &n)) {
memset(explanation, 0x00, sizeof(explanation));
// handle partial bytes. The parity array[0] is used to store number of left over bits from NBYTES
// This part prints the number of bits in the trace entry for hitag.
uint8_t nbits = parityBytes[0];
annotateHitag2(explanation, sizeof(explanation), ht2plain, n, nbits, hdr->isResponse, NULL, 0, true);
// iceman: colorise crc bytes here will need a refactor of code from above.
for (int j = 0; j < n && (j / TRACE_MAX_HEX_BYTES) < TRACE_MAX_HEX_BYTES; j++) {
if (j == 0) {
// only apply this to lesser than one byte
if (n == 1) {
if (nbits == 5) {
snprintf(line[0], 120, "%2u: %02X ", nbits, ht2plain[0] >> (8 - nbits));
} else {
snprintf(line[0], 120, "%2u: %02X ", nbits, ht2plain[0] >> (8 - nbits));
}
} else {
if (nbits == 0) {
snprintf(line[0], 120, "%2u: %02X ", (n * 8), ht2plain[0]);
} else {
snprintf(line[0], 120, "%2u: %02X ", ((n - 1) * 8) + nbits, ht2plain[0]);
}
}
offset = 4;
} else {
snprintf(line[j / 18] + ((j % 18) * 4) + offset, 120, "%02X ", ht2plain[j]);
}
}
num_lines = MIN((n - 1) / TRACE_MAX_HEX_BYTES + 1, TRACE_MAX_HEX_BYTES);
for (int j = 0; j < num_lines ; j++) {
if (hdr->isResponse) {
PrintAndLogEx(NORMAL, " | | * |%-*s | %-4s| %s",
str_padder,
line[j],
" ",
explanation);
} else {
PrintAndLogEx(NORMAL, " | | * |" _YELLOW_("%-*s")" | " _YELLOW_("%s") "| " _YELLOW_("%s"),
str_padder,
line[j],
" ",
explanation);
}
}
}
}
if (is_last_record(tracepos, traceLen)) {
return traceLen;
}
@@ -1416,7 +1480,7 @@ int CmdTraceList(const char *Cmd) {
if (diclen > 0) {
uint8_t *keyBlock = NULL;
int res = loadFileDICTIONARY_safe(dictionary, (void **) &keyBlock, 6, &dicKeysCount);
if (res != PM3_SUCCESS || dicKeysCount == 0 || keyBlock == NULL) {
if (res != PM3_SUCCESS || dicKeysCount == 0 || keyBlock == NULL) {
PrintAndLogEx(FAILED, "An error occurred while loading the dictionary! (we will use the default keys now)");
} else {
dicKeys = calloc(dicKeysCount, sizeof(uint64_t));
@@ -1436,6 +1500,30 @@ int CmdTraceList(const char *Cmd) {
}
}
if ( protocol == PROTO_HITAG2) {
if (strlen(dictionary) == 0) {
snprintf(dictionary, sizeof(dictionary), HITAG_DICTIONARY);
}
// load keys
uint8_t *keyBlock = NULL;
int res = loadFileDICTIONARY_safe(dictionary, (void **) &keyBlock, HITAG_CRYPTOKEY_SIZE, &dicKeysCount);
if (res != PM3_SUCCESS || dicKeysCount == 0 || keyBlock == NULL) {
PrintAndLogEx(FAILED, "An error occurred while loading the dictionary!");
} else {
dicKeys = calloc(dicKeysCount, sizeof(uint64_t));
for (int i = 0; i < dicKeysCount; i++) {
uint64_t key = bytes_to_num(keyBlock + i * HITAG_CRYPTOKEY_SIZE, HITAG_CRYPTOKEY_SIZE);
memcpy((uint8_t *) &dicKeys[i], &key, sizeof(uint64_t));
}
dictionaryLoad = true;
}
if (keyBlock != NULL) {
free(keyBlock);
}
}
PrintAndLogEx(NORMAL, "");
if (use_relative) {
PrintAndLogEx(NORMAL, " Gap | Duration | Src | Data (! denotes parity error, ' denotes short bytes) | CRC | Annotation");
@@ -1463,16 +1551,19 @@ int CmdTraceList(const char *Cmd) {
while (tracepos < gs_traceLen) {
tracepos = printTraceLine(tracepos, gs_traceLen, gs_trace, protocol, show_wait_cycles, mark_crc, prev_EOT, use_us, dicKeys, dicKeysCount);
if (kbd_enter_pressed())
if (kbd_enter_pressed()) {
break;
}
}
if (dictionaryLoad)
if (dictionaryLoad) {
free((void *) dicKeys);
}
}
if (show_hex)
if (show_hex) {
PrintAndLogEx(HINT, "syntax to use: " _YELLOW_("`text2pcap -t \"%%S.\" -l 264 -n <input-text-file> <output-pcapng-file>`"));
}
return PM3_SUCCESS;
}
+50 -38
View File
@@ -127,34 +127,38 @@ void des3_decrypt(void *out, const void *in, const void *key, uint8_t keycount)
// NIST Special Publication 800-38A — Recommendation for block cipher modes of operation: methods and techniques, 2001.
int aes_encode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length) {
uint8_t iiv[16] = {0};
if (iv)
if (iv) {
memcpy(iiv, iv, 16);
}
mbedtls_aes_context aes;
mbedtls_aes_init(&aes);
if (mbedtls_aes_setkey_enc(&aes, key, 128))
if (mbedtls_aes_setkey_enc(&aes, key, 128)) {
return 1;
if (mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, length, iiv, input, output))
}
if (mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, length, iiv, input, output)) {
return 2;
}
mbedtls_aes_free(&aes);
return 0;
return PM3_SUCCESS;
}
int aes_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length) {
uint8_t iiv[16] = {0};
if (iv)
if (iv) {
memcpy(iiv, iv, 16);
}
mbedtls_aes_context aes;
mbedtls_aes_init(&aes);
if (mbedtls_aes_setkey_dec(&aes, key, 128))
if (mbedtls_aes_setkey_dec(&aes, key, 128)) {
return 1;
if (mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, length, iiv, input, output))
}
if (mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, length, iiv, input, output)) {
return 2;
}
mbedtls_aes_free(&aes);
return 0;
return PM3_SUCCESS;
}
// NIST Special Publication 800-38B — Recommendation for block cipher modes of operation: The CMAC mode for authentication.
@@ -171,13 +175,14 @@ int aes_cmac8(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int lengt
memset(mac, 0x00, 8);
int res = aes_cmac(iv, key, input, cmac_tmp, length);
if (res)
if (res) {
return res;
}
for (int i = 0; i < 8; i++)
for (int i = 0; i < 8; i++) {
mac[i] = cmac_tmp[i * 2 + 1];
return 0;
}
return PM3_SUCCESS;
}
static uint8_t fixed_rand_value[250] = {0};
@@ -188,21 +193,23 @@ static int fixed_rand(void *rng_state, unsigned char *output, size_t len) {
memset(output, 0x00, len);
}
return 0;
return PM3_SUCCESS;
}
int sha1hash(uint8_t *input, int length, uint8_t *hash) {
if (!hash || !input)
if (!hash || !input) {
return 1;
}
mbedtls_sha1(input, length, hash);
return 0;
return PM3_SUCCESS;
}
int sha256hash(uint8_t *input, int length, uint8_t *hash) {
if (!hash || !input)
if (!hash || !input) {
return 1;
}
mbedtls_sha256_context sctx;
mbedtls_sha256_init(&sctx);
@@ -211,12 +218,13 @@ int sha256hash(uint8_t *input, int length, uint8_t *hash) {
mbedtls_sha256_finish(&sctx, hash);
mbedtls_sha256_free(&sctx);
return 0;
return PM3_SUCCESS;
}
int sha512hash(uint8_t *input, int length, uint8_t *hash) {
if (!hash || !input)
if (!hash || !input) {
return 1;
}
mbedtls_sha512_context sctx;
mbedtls_sha512_init(&sctx);
@@ -225,33 +233,35 @@ int sha512hash(uint8_t *input, int length, uint8_t *hash) {
mbedtls_sha512_finish(&sctx, hash);
mbedtls_sha512_free(&sctx);
return 0;
return PM3_SUCCESS;
}
static int ecdsa_init_str(mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id curveid, const char *key_d, const char *key_x, const char *key_y) {
if (!ctx)
if (!ctx) {
return 1;
int res;
}
mbedtls_ecdsa_init(ctx);
res = mbedtls_ecp_group_load(&ctx->grp, curveid);
if (res)
int res = mbedtls_ecp_group_load(&ctx->grp, curveid);
if (res) {
return res;
}
if (key_d) {
res = mbedtls_mpi_read_string(&ctx->d, 16, key_d);
if (res)
if (res) {
return res;
}
}
if (key_x && key_y) {
res = mbedtls_ecp_point_read_string(&ctx->Q, 16, key_x, key_y);
if (res)
if (res) {
return res;
}
}
return 0;
return PM3_SUCCESS;
}
static int ecdsa_init(mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id curveid, uint8_t *key_d, uint8_t *key_xy) {
@@ -278,7 +288,7 @@ static int ecdsa_init(mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id curveid,
return res;
}
return 0;
return PM3_SUCCESS;
}
int ecdsa_key_create(mbedtls_ecp_group_id curveid, uint8_t *key_d, uint8_t *key_xy) {
@@ -519,8 +529,9 @@ int ecdsa_nist_test(bool verbose) {
size_t siglen = 0;
// NIST ecdsa test
if (verbose)
PrintAndLogEx(INFO, " ECDSA NIST test: " NOLF);
if (verbose) {
PrintAndLogEx(INFO, "ECDSA NIST test " NOLF);
}
// make signature
res = ecdsa_signature_create_test(curveid, T_PRIVATE_KEY, T_Q_X, T_Q_Y, T_K, input, length, signature, &siglen);
// PrintAndLogEx(INFO, "res: %x signature[%x]: %s", (res < 0)? -res : res, siglen, sprint_hex(signature, siglen));
@@ -540,15 +551,16 @@ int ecdsa_nist_test(bool verbose) {
uint8_t sval_s[33] = {0};
param_gethex_to_eol(T_S, 0, sval_s, sizeof(sval_s), &slen);
if (strncmp((char *)rval, (char *)rval_s, 32) || strncmp((char *)sval, (char *)sval_s, 32)) {
PrintAndLogEx(INFO, "R or S check error");
PrintAndLogEx(NORMAL, "( " _RED_("R or S check error") " )");
res = 100;
goto exit;
}
// verify signature
res = ecdsa_signature_verify_keystr(curveid, T_Q_X, T_Q_Y, input, length, signature, siglen, true);
if (res)
if (res) {
goto exit;
}
// verify wrong signature
input[0] ^= 0xFF;
@@ -559,8 +571,8 @@ int ecdsa_nist_test(bool verbose) {
}
if (verbose) {
PrintAndLogEx(NORMAL, _GREEN_("passed"));
PrintAndLogEx(INFO, " ECDSA binary signature create/check test: " NOLF);
PrintAndLogEx(NORMAL, "( " _GREEN_("ok") " )");
PrintAndLogEx(INFO, "ECDSA binary signature create/check test " NOLF);
}
// random ecdsa test
@@ -587,12 +599,12 @@ int ecdsa_nist_test(bool verbose) {
goto exit;
if (verbose)
PrintAndLogEx(NORMAL, _GREEN_("passed\n"));
PrintAndLogEx(NORMAL, "( " _GREEN_("ok") " )");
return PM3_SUCCESS;
exit:
if (verbose)
PrintAndLogEx(NORMAL, _RED_("failed\n"));
PrintAndLogEx(NORMAL, "( " _RED_("fail") " )");
return res;
}
+348 -37
View File
@@ -16,10 +16,15 @@
// Hitag2 Crypto
//-----------------------------------------------------------------------------
#include "hitag2_crypto.h"
#include <inttypes.h>
#include "util.h"
#include "string.h"
#include "commonutil.h"
#include "pm3_cmd.h"
#ifndef ON_DEVICE
#include "ui.h"
#endif
/* Following is a modified version of cryptolib.com/ciphers/hitag2/ */
// Software optimized 48-bit Philips/NXP Mifare Hitag2 PCF7936/46/47/52 stream cipher algorithm by I.C. Wiener 2006-2007.
@@ -27,39 +32,337 @@
// No warranties or guarantees of any kind.
// This code is released into the public domain by its author.
// Single bit Hitag2 functions:
#ifndef i4
#define i4(x,a,b,c,d) ((uint32_t)((((x)>>(a))&1)+(((x)>>(b))&1)*2+(((x)>>(c))&1)*4+(((x)>>(d))&1)*8))
#define i4(x,a,b,c,d) ((uint32_t)((((x)>>(a))&1)+(((x)>>(b))&1)*2+(((x)>>(c))&1)*4+(((x)>>(d))&1)*8))
#endif
static const uint32_t ht2_f4a = 0x2C79; // 0010 1100 0111 1001
static const uint32_t ht2_f4b = 0x6671; // 0110 0110 0111 0001
static const uint32_t ht2_f5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011
static uint32_t ht2_f20(const uint64_t x) {
uint32_t i5;
static uint32_t ht2_f20(const uint64_t state) {
i5 = ((ht2_f4a >> i4(x, 1, 2, 4, 5)) & 1) * 1
+ ((ht2_f4b >> i4(x, 7, 11, 13, 14)) & 1) * 2
+ ((ht2_f4b >> i4(x, 16, 20, 22, 25)) & 1) * 4
+ ((ht2_f4b >> i4(x, 27, 28, 30, 32)) & 1) * 8
+ ((ht2_f4a >> i4(x, 33, 42, 43, 45)) & 1) * 16;
uint32_t i5 = ((ht2_f4a >> i4(state, 1, 2, 4, 5)) & 1) * 1
+ ((ht2_f4b >> i4(state, 7, 11, 13, 14)) & 1) * 2
+ ((ht2_f4b >> i4(state, 16, 20, 22, 25)) & 1) * 4
+ ((ht2_f4b >> i4(state, 27, 28, 30, 32)) & 1) * 8
+ ((ht2_f4a >> i4(state, 33, 42, 43, 45)) & 1) * 16;
return (ht2_f5c >> i5) & 1;
}
uint64_t ht2_hitag2_init(const uint64_t key, const uint32_t serial, const uint32_t IV) {
uint32_t i;
// return a single bit from a value
static int ht2_bitn(uint64_t x, int bit) {
const uint64_t bitmask = (uint64_t)(1) << bit;
return (x & bitmask) ? 1 : 0;
}
// the sub-function R that rollback depends upon
int ht2_fnR(uint64_t state) {
// renumbered bits because my state is 0-47, not 1-48
return (
ht2_bitn(state, 1) ^ ht2_bitn(state, 2) ^ ht2_bitn(state, 5) ^
ht2_bitn(state, 6) ^ ht2_bitn(state, 7) ^ ht2_bitn(state, 15) ^
ht2_bitn(state, 21) ^ ht2_bitn(state, 22) ^ ht2_bitn(state, 25) ^
ht2_bitn(state, 29) ^ ht2_bitn(state, 40) ^ ht2_bitn(state, 41) ^
ht2_bitn(state, 42) ^ ht2_bitn(state, 45) ^ ht2_bitn(state, 46) ^
ht2_bitn(state, 47)
);
}
/*
static void ht2_rollback(hitag_state_t *hstate, unsigned int steps) {
for (int i = 0; i < steps; i++) {
hstate->shiftreg = ((hstate->shiftreg << 1) & 0xffffffffffff) | ht2_fnR(hstate->shiftreg);
}
}
*/
// the rollback function that lets us go backwards in time
void ht2_rollback(hitag_state_t *hstate, uint32_t steps) {
for (uint32_t i = 0; i < steps; i++) {
hstate->shiftreg = ((hstate->shiftreg << 1) & 0xffffffffffff) | ht2_fnR(hstate->shiftreg);
hstate->lfsr = LFSR_INV(hstate->lfsr);
}
}
// the three filter sub-functions that feed fnf
#define ht2_fa(x) ht2_bitn(0x2C79, (x))
#define ht2_fb(x) ht2_bitn(0x6671, (x))
#define ht2_fc(x) ht2_bitn(0x7907287B, (x))
// the filter function that generates a bit of output from the prng state
int ht2_fnf(uint64_t state) {
uint32_t x1 = (ht2_bitn(state, 2) << 0) | (ht2_bitn(state, 3) << 1) | (ht2_bitn(state, 5) << 2) | (ht2_bitn(state, 6) << 3);
uint32_t x2 = (ht2_bitn(state, 8) << 0) | (ht2_bitn(state, 12) << 1) | (ht2_bitn(state, 14) << 2) | (ht2_bitn(state, 15) << 3);
uint32_t x3 = (ht2_bitn(state, 17) << 0) | (ht2_bitn(state, 21) << 1) | (ht2_bitn(state, 23) << 2) | (ht2_bitn(state, 26) << 3);
uint32_t x4 = (ht2_bitn(state, 28) << 0) | (ht2_bitn(state, 29) << 1) | (ht2_bitn(state, 31) << 2) | (ht2_bitn(state, 33) << 3);
uint32_t x5 = (ht2_bitn(state, 34) << 0) | (ht2_bitn(state, 43) << 1) | (ht2_bitn(state, 44) << 2) | (ht2_bitn(state, 46) << 3);
uint32_t x6 = (ht2_fa(x1) << 0) | (ht2_fb(x2) << 1) | (ht2_fb(x3) << 2) | (ht2_fb(x4) << 3) | (ht2_fa(x5) << 4);
return ht2_fc(x6);
}
// builds the lfsr for the prng (quick calcs for hitag2_nstep())
/*
static void ht2_buildlfsr(hitag_state_t *hstate) {
if (hstate == NULL) {
return;
}
uint64_t state = hstate->shiftreg;
uint64_t temp = state ^ (state >> 1);
hstate->lfsr = state ^ (state >> 6) ^ (state >> 16)
^ (state >> 26) ^ (state >> 30) ^ (state >> 41)
^ (temp >> 2) ^ (temp >> 7) ^ (temp >> 22)
^ (temp >> 42) ^ (temp >> 46);
}
*/
#ifndef ON_DEVICE
#include <stdio.h>
#endif
uint64_t ht2_recoverkey(hitag_state_t *hstate, uint32_t uid, uint32_t nRenc) {
// hstate->shiftreg = (uint64_t)(((hstate->shiftreg << 1) & 0xffffffffffff) | (uint64_t)ht2_fnR(hstate->shiftreg));
// hstate->shiftreg = (uint64_t)(((hstate->shiftreg << 1) & 0xffffffffffff) | (uint64_t)ht2_fnR(hstate->shiftreg));
#ifndef ON_DEVICE
PrintAndLogEx(INFO, "shiftreg.... %" PRIx64, hstate->shiftreg);
#endif
// key lower 16 bits are lower 16 bits of prng state
uint64_t key = hstate->shiftreg & 0xffff;
uint32_t nRxork = (hstate->shiftreg >> 16) & 0xffffffff;
// rollback and extract bits b
uint32_t b = 0;
for (uint8_t i = 0; i < 32; i++) {
hstate->shiftreg = ((hstate->shiftreg) << 1) | ((uid >> (31 - i)) & 0x1);
b = (b << 1) | (unsigned int) ht2_fnf(hstate->shiftreg);
}
uint32_t nR = nRenc ^ b;
uint64_t keyupper = nRxork ^ nR;
key = key | (keyupper << 16);
#ifndef ON_DEVICE
PrintAndLogEx(INFO, "b..... %08" PRIx32 " %08" PRIx32 " %012" PRIx64, b, nRenc, hstate->shiftreg);
PrintAndLogEx(INFO, "key... %012" PRIx64 " %012" PRIx64 "\n", key, REV64(key));
#endif
return key;
}
/*
* Parameters:
* Hitag_State* pstate - output, internal state after initialisation
* uint64_t sharedkey - 48 bit key shared between reader & tag
* uint32_t serialnum - 32 bit tag serial number
* uint32_t iv - 32 bit random IV from reader, part of tag authentication
*/
void ht2_hitag2_init_ex(hitag_state_t *hstate, uint64_t sharedkey, uint32_t serialnum, uint32_t iv) {
// init state, from serial number and lowest 16 bits of shared key
uint64_t state = ((sharedkey & 0xFFFF) << 32) | serialnum;
// mix the initialisation vector and highest 32 bits of the shared key
iv ^= (uint32_t)(sharedkey >> 16);
// move 16 bits from (IV xor Shared Key) to top of uint64_t state
// these will be XORed in turn with output of the crypto function
state |= (uint64_t) iv << 48;
iv >>= 16;
// unrolled loop is faster on PIC32 (MIPS), do 32 times
// shift register, then calc new bit
state >>= 1;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
// highest 16 bits of IV XOR Shared Key
state |= (uint64_t) iv << 47;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
state ^= (uint64_t) ht2_f20(state) << 47;
// LSFR
hstate->shiftreg = state;
/* naive version for reference, LFSR has 16 taps
pstate->lfsr = state ^ (state >> 2) ^ (state >> 3) ^ (state >> 6)
^ (state >> 7) ^ (state >> 8) ^ (state >> 16) ^ (state >> 22)
^ (state >> 23) ^ (state >> 26) ^ (state >> 30) ^ (state >> 41)
^ (state >> 42) ^ (state >> 43) ^ (state >> 46) ^ (state >> 47);
*/
{
// optimise with one 64-bit intermediate
uint64_t temp = state ^ (state >> 1);
hstate->lfsr = state ^ (state >> 6) ^ (state >> 16)
^ (state >> 26) ^ (state >> 30) ^ (state >> 41)
^ (temp >> 2) ^ (temp >> 7) ^ (temp >> 22)
^ (temp >> 42) ^ (temp >> 46);
}
}
/*
* Return up to 32 crypto bits.
* Last bit is in least significant bit, earlier bits are shifted left.
* Note that the Hitag transmission protocol is least significant bit,
* so we may want to change this, or add a function, that returns the
* crypto output bits in the other order.
*
* Parameters:
* Hitag_State* pstate - in/out, internal cipher state after initialisation
* uint32_t steps - number of bits requested, (capped at 32)
*/
uint32_t ht2_hitag2_nstep(hitag_state_t *hstate, uint32_t steps) {
uint64_t state = hstate->shiftreg;
uint32_t result = 0;
uint64_t lfsr = hstate->lfsr;
if (steps == 0) {
return 0;
}
do {
// update shift registers
if (lfsr & 1) {
state = (state >> 1) | 0x800000000000;
lfsr = (lfsr >> 1) ^ 0xB38083220073;
// accumulate next bit of crypto
result = (result << 1) | ht2_f20(state);
} else {
state >>= 1;
lfsr >>= 1;
result = (result << 1) | ht2_f20(state);
}
} while (--steps);
hstate->shiftreg = state;
hstate->lfsr = lfsr;
return result;
}
uint64_t ht2_hitag2_init(const uint64_t key, const uint32_t serial, const uint32_t iv) {
uint64_t x = ((key & 0xFFFF) << 32) + serial;
for (i = 0; i < 32; i++) {
for (uint32_t i = 0; i < 32; i++) {
x >>= 1;
x += (uint64_t)(ht2_f20(x) ^ (((IV >> i) ^ (key >> (i + 16))) & 1)) << 47;
x += (uint64_t)(ht2_f20(x) ^ (((iv >> i) ^ (key >> (i + 16))) & 1)) << 47;
}
return x;
}
uint64_t ht2_hitag2_round(uint64_t *state) {
int ht2_try_state(uint64_t s, uint32_t uid, uint32_t aR2, uint32_t nR1, uint32_t nR2, uint64_t *key) {
hitag_state_t hstate;
hstate.shiftreg = s;
hstate.lfsr = 0;
hstate.shiftreg = (uint64_t)(((hstate.shiftreg << 1) & 0xffffffffffff) | (uint64_t)ht2_fnR(hstate.shiftreg));
hstate.shiftreg = (uint64_t)(((hstate.shiftreg << 1) & 0xffffffffffff) | (uint64_t)ht2_fnR(hstate.shiftreg));
#ifndef ON_DEVICE
hitag_state_t hs2;
hs2.shiftreg = s;
hs2.lfsr = 0;
ht2_rollback(&hs2, 2);
PrintAndLogEx(INFO, "hstate shiftreg.... %" PRIx64 " lfsr... %" PRIx64, hstate.shiftreg, hstate.lfsr);
PrintAndLogEx(INFO, "hstate shiftreg.... %" PRIx64 " lfsr... %" PRIx64, hs2.shiftreg, hs2.lfsr);
#endif
// recover key
uint64_t keyrev = hstate.shiftreg & 0xffff;
uint64_t nR1xk = (hstate.shiftreg >> 16) & 0xffffffff;
#ifndef ON_DEVICE
PrintAndLogEx(INFO, "keyrev...... %012" PRIx64 " nR1xk... %08" PRIx64, keyrev, nR1xk);
#endif
uint32_t b = 0;
for (uint8_t i = 0; i < 32; i++) {
hstate.shiftreg = ((hstate.shiftreg) << 1) | ((uid >> (31 - i)) & 0x1);
b = (b << 1) | (unsigned int) ht2_fnf(hstate.shiftreg);
}
#ifndef ON_DEVICE
PrintAndLogEx(INFO, "b..... %08" PRIx32 " %08" PRIx32 " %012" PRIx64, b, nR1, hstate.shiftreg);
#endif
keyrev |= (nR1xk ^ nR1 ^ b) << 16;
#ifndef ON_DEVICE
PrintAndLogEx(INFO, "key... %012" PRIx64 " %012" PRIx64, keyrev, REV64(keyrev));
#endif
// test key
ht2_hitag2_init_ex(&hstate, keyrev, uid, nR2);
if ((aR2 ^ ht2_hitag2_nstep(&hstate, 32)) == 0xFFFFFFFF) {
*key = REV64(keyrev);
return PM3_SUCCESS;
}
return PM3_ESOFT;
}
// "MIKRON" = O N M I K R
// Key = 4F 4E 4D 49 4B 52 - Secret 48-bit key
// Serial = 49 43 57 69 - Serial number of the tag, transmitted in clear
// Random = 65 6E 45 72 - Random IV, transmitted in clear
//~28~DC~80~31 = D7 23 7F CE - Authenticator value = inverted first 4 bytes of the keystream
// The code below must print out "D7 23 7F CE 8C D0 37 A9 57 49 C1 E6 48 00 8A B6".
// The inverse of the first 4 bytes is sent to the tag to authenticate.
// The rest is encrypted by XORing it with the subsequent keystream.
/*
* Return 8 crypto bits.
* Last bit is in least significant bit, earlier bits are shifted left.
* Note that the Hitag transmission protocol is least significant bit,
* so we may want to change this, or add a function, that returns the
* crypto output bits in the other order.
*
* Parameters:
* uint64_t *state - in/out, internal cipher state after initialisation
*/
uint64_t ht2_hitag2_bit(uint64_t *state) {
uint64_t x = *state;
x = (x >> 1) +
@@ -72,21 +375,25 @@ uint64_t ht2_hitag2_round(uint64_t *state) {
return ht2_f20(x);
}
// "MIKRON" = O N M I K R
// Key = 4F 4E 4D 49 4B 52 - Secret 48-bit key
// Serial = 49 43 57 69 - Serial number of the tag, transmitted in clear
// Random = 65 6E 45 72 - Random IV, transmitted in clear
//~28~DC~80~31 = D7 23 7F CE - Authenticator value = inverted first 4 bytes of the keystream
// Take a state and create one byte (8bits) of crypto
uint32_t ht2_hitag2_byte(uint64_t *state) {
uint32_t c = 0;
c += (uint32_t) ht2_hitag2_bit(state) << 7; // 7
c += (uint32_t) ht2_hitag2_bit(state) << 6; // 6
c += (uint32_t) ht2_hitag2_bit(state) << 5; // 5
c += (uint32_t) ht2_hitag2_bit(state) << 4;
c += (uint32_t) ht2_hitag2_bit(state) << 3;
c += (uint32_t) ht2_hitag2_bit(state) << 2;
c += (uint32_t) ht2_hitag2_bit(state) << 1;
c += (uint32_t) ht2_hitag2_bit(state) << 0;
return c;
}
// The code below must print out "D7 23 7F CE 8C D0 37 A9 57 49 C1 E6 48 00 8A B6".
// The inverse of the first 4 bytes is sent to the tag to authenticate.
// The rest is encrypted by XORing it with the subsequent keystream.
uint32_t ht2_hitag2_byte(uint64_t *x) {
uint32_t i, c;
for (i = 0, c = 0; i < 8; i++) {
c += (uint32_t) ht2_hitag2_round(x) << (i ^ 7);
}
uint32_t ht2_hitag2_word(uint64_t *state, uint32_t steps) {
uint32_t c = 0;
do {
c += (uint32_t) ht2_hitag2_bit(state) << (steps - 1);
} while (--steps);
return c;
}
@@ -108,19 +415,23 @@ void ht2_hitag2_cipher_reset(hitag2_t *tag, const uint8_t *iv) {
tag->cs = ht2_hitag2_init(REV64(key), REV32(uid), REV32(iv_));
}
int ht2_hitag2_cipher_authenticate(uint64_t *cs, const uint8_t *authenticator_is) {
int ht2_hitag2_cipher_authenticate(uint64_t *state, const uint8_t *authenticator_is) {
uint8_t authenticator_should[4];
authenticator_should[0] = ~ht2_hitag2_byte(cs);
authenticator_should[1] = ~ht2_hitag2_byte(cs);
authenticator_should[2] = ~ht2_hitag2_byte(cs);
authenticator_should[3] = ~ht2_hitag2_byte(cs);
authenticator_should[0] = ~ht2_hitag2_byte(state);
authenticator_should[1] = ~ht2_hitag2_byte(state);
authenticator_should[2] = ~ht2_hitag2_byte(state);
authenticator_should[3] = ~ht2_hitag2_byte(state);
return (memcmp(authenticator_should, authenticator_is, 4) == 0);
}
int ht2_hitag2_cipher_transcrypt(uint64_t *cs, uint8_t *data, uint16_t bytes, uint16_t bits) {
void ht2_hitag2_cipher_transcrypt(uint64_t *state, uint8_t *data, uint16_t bytes, uint16_t bits) {
int i;
for (i = 0; i < bytes; i++) data[i] ^= ht2_hitag2_byte(cs);
for (i = 0; i < bits; i++) data[bytes] ^= ht2_hitag2_round(cs) << (7 - i);
return 0;
for (i = 0; i < bytes; i++) {
data[i] ^= ht2_hitag2_byte(state);
}
for (i = 0; i < bits; i++) {
data[bytes] ^= ht2_hitag2_bit(state) << (7 - i);
}
}
+28 -6
View File
@@ -17,6 +17,12 @@
#define __HITAG2_CRYPTO_H
#include "common.h"
#include <stdbool.h>
#ifndef LFSR_INV
#define LFSR_INV(state) (((state) << 1) | (__builtin_parityll((state) & ((0xce0044c101cd >> 1) | (1ull << 47)))))
#endif
typedef struct {
uint32_t uid;
@@ -32,11 +38,27 @@ typedef struct {
uint8_t sectors[12][4];
} hitag2_t;
uint64_t ht2_hitag2_init(const uint64_t key, const uint32_t serial, const uint32_t IV);
uint64_t ht2_hitag2_round(uint64_t *state);
uint32_t ht2_hitag2_byte(uint64_t *x);
void ht2_hitag2_cipher_reset(hitag2_t *tag, const uint8_t *iv);
int ht2_hitag2_cipher_authenticate(uint64_t *cs, const uint8_t *authenticator_is);
int ht2_hitag2_cipher_transcrypt(uint64_t *cs, uint8_t *data, uint16_t bytes, uint16_t bits) ;
typedef struct {
uint64_t shiftreg; // naive shift register, required for nonlinear fn input
uint64_t lfsr; // fast lfsr, used to make software faster
} hitag_state_t;
void ht2_hitag2_init_ex(hitag_state_t *hstate, uint64_t sharedkey, uint32_t serialnum, const uint32_t iv);
void ht2_rollback(hitag_state_t *hstate, uint32_t steps);
uint64_t ht2_recoverkey(hitag_state_t *hstate, uint32_t uid, uint32_t nRenc);
uint32_t ht2_hitag2_nstep(hitag_state_t *hstate, uint32_t steps);
uint32_t ht2_hitag_acid(hitag_state_t *hstate, uint32_t steps);
int ht2_try_state(uint64_t s, uint32_t uid, uint32_t aR2, uint32_t nR1, uint32_t nR2, uint64_t *key);
uint32_t ht2_hitag2_word(uint64_t *state, uint32_t steps);
uint64_t ht2_hitag2_init(const uint64_t key, const uint32_t serial, const uint32_t iv);
uint64_t ht2_hitag2_bit(uint64_t *state);
uint32_t ht2_hitag2_byte(uint64_t *state);
void ht2_hitag2_cipher_reset(hitag2_t *tag, const uint8_t *iv);
int ht2_hitag2_cipher_authenticate(uint64_t *state, const uint8_t *authenticator_is);
void ht2_hitag2_cipher_transcrypt(uint64_t *state, uint8_t *data, uint16_t bytes, uint16_t bits) ;
int ht2_fnf(uint64_t state);
int ht2_fnR(uint64_t state);
#endif
+5 -7
View File
@@ -42,10 +42,8 @@ static const uint8_t g_odd_byte_parity[256] = {
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
};
//extern const uint8_t OddByteParity[256];
#define ODD_PARITY8(x) { g_odd_byte_parity[x] }
#define EVEN_PARITY8(x) { !g_odd_byte_parity[x] }
#define ODD_PARITY8(x) g_odd_byte_parity[x]
#define EVEN_PARITY8(x) !g_odd_byte_parity[x]
static inline uint8_t oddparity8(const uint8_t x) {
return g_odd_byte_parity[x];
@@ -60,7 +58,7 @@ static inline uint8_t evenparity16(uint16_t x) {
x ^= x >> 8;
return EVEN_PARITY8(x) ;
#else
return (__builtin_parity(x) & 0xFF);
return __builtin_parity(x);
#endif
}
@@ -77,9 +75,9 @@ static inline uint8_t evenparity32(uint32_t x) {
#if !defined __GNUC__
x ^= x >> 16;
x ^= x >> 8;
return EVEN_PARITY8(x);
return EVEN_PARITY8(x) ;
#else
return (__builtin_parity(x) & 0xFF);
return __builtin_parity(x);
#endif
}
+11
View File
@@ -127,6 +127,17 @@ extern bool g_tearoff_enabled;
#endif
#endif
// endian change for 48bit
#ifndef BSWAP_48
#define BSWAP_48(x) \
(((uint64_t)(x) << 40) & 0x0000ff0000000000ULL) | \
(((uint64_t)(x) << 24) & 0x000000ff00000000ULL) | \
(((uint64_t)(x) << 8) & 0x00000000ff000000ULL) | \
(((uint64_t)(x) >> 8) & 0x000000000ff0000ULL) | \
(((uint64_t)(x) >> 24) & 0x00000000000ff00ULL) | \
(((uint64_t)(x) >> 40) & 0x0000000000000ffULL)
#endif
// endian change for 32bit
#ifdef __GNUC__
#ifndef BSWAP_32
+12 -21
View File
@@ -39,37 +39,28 @@ typedef enum {
RHT2F_UID_ONLY = 26,
WHT2F_PASSWORD = 27,
HT2_LAST_CMD = WHT2F_PASSWORD,
} hitag_function;
typedef struct {
uint8_t password[4];
} PACKED rht2d_password;
} PACKED hitag_function;
typedef struct {
hitag_function cmd;
int16_t page;
uint8_t data[4];
uint8_t NrAr[8];
uint8_t data[4];
} PACKED rht2d_authenticate;
typedef struct {
uint8_t key[6];
uint8_t data[4];
} PACKED rht2d_crypto;
uint8_t pwd[4];
typedef struct {
// Hitag 1 section.
// will reuse pwd or key field.
uint8_t key_no;
uint8_t logdata_0[4];
uint8_t logdata_1[4];
uint8_t nonce[4];
uint8_t key[4];
} PACKED rht1d_authenticate;
typedef union {
rht2d_password pwd;
rht1d_authenticate ht1auth;
rht2d_authenticate auth;
rht2d_crypto crypto;
} hitag_data;
} PACKED lf_hitag_data_t;
typedef struct {
int status;
uint8_t data[48];
} PACKED lf_hitag_crack_response_t;
//---------------------------------------------------------
// Hitag S
+18 -8
View File
@@ -67,9 +67,9 @@ def hitag2_init(key, uid, nonce):
#print '%012x' % state
#print '%012x' % (int("{0:048b}".format(state)[::-1],2))
for i in range(0, 32):
nonce_bit = (f20(state) ^ ((nonce >> (31-i)) & 1))
nonce_bit = (f20(state) ^ ((nonce >> (31 - i)) & 1))
#print nonce_bit
state = (state >> 1) | (((nonce_bit ^ (key >> (31-i))) & 1) << 47)
state = (state >> 1) | (((nonce_bit ^ (key >> (31 - i))) & 1) << 47)
#print '%012x' % state
#print '%012x' % (int("{0:048b}".format(state)[::-1],2))
return state
@@ -81,6 +81,7 @@ def lfsr_feedback(state):
^ (state >> 26) ^ (state >> 30) ^ (state >> 41)
^ (state >> 42) ^ (state >> 43) ^ (state >> 46)
^ (state >> 47)) & 1)
def lfsr(state):
return (state >> 1) + (lfsr_feedback(state) << 47)
@@ -93,15 +94,17 @@ def lfsr_feedback_inv(state):
^ (state >> 46)) & 1)
def lfsr_inv(state):
return ((state << 1) + (lfsr_feedback_inv(state))) & ((1<<48)-1)
return ((state << 1) + (lfsr_feedback_inv(state))) & ((1 << 48) - 1)
def hitag2(state, length=48):
c = 0
for i in range(0, length):
c = (c << 1) | f20(state)
#print '%012x' % state
#print '%012x' % (int("{0:048b}".format(state)[::-1],2))
#print ('%012x' % state)
state = lfsr(state)
#print ('%012x' % (int("{0:048b}".format(state)[::-1],2)))
#print('%08X %08X' % (c, state))
#print('final: %08X %08X' % (c, state))
return c
if __name__ == "__main__":
@@ -111,8 +114,15 @@ if __name__ == "__main__":
uid = int(sys.argv[2], 16)
n = int(sys.argv[3])
for i in range(n):
nonce = random.randrange(2**32)
state = hitag2_init(key, uid, nonce)
print('%08X %08X' % (nonce, hitag2(state, 32)^0xffffffff))
nonceA = random.randrange(2**32)
stateA = hitag2_init(key, uid, nonceA)
csA = hitag2(stateA, 32) ^ 0xffffffff
# print('%08X %08X' % (nonceA, csA))
nonceB = random.randrange(2**32)
stateB = hitag2_init(key, uid, nonceB)
csB = hitag2(stateB, 32) ^ 0xffffffff
print('./ht2crack5opencl %08X %08X %08X %08X %08X' % (uid, nonceA, csA, nonceB, csB))
print('lf hitag lookup --uid %08X --nr %08X --ar %08X --key %012X' % (uid, nonceA, csA, key))
else:
print("Usage: python %s <key> <uid> <nr of nRaR to generate>" % sys.argv[0])
+1
View File
@@ -414,6 +414,7 @@ while true; do
if ! CheckExecute "nfc decode test - signature" "$CLIENTBIN -c 'nfc decode -d 03FF010194113870696C65742E65653A656B616172743A3266195F26063132303832325904202020205F28033233335F2701316E1B5A13333038363439303039303030323636343030355304EBF2CE704103000000AC536967010200803A2448FCA7D354A654A81BD021150D1A152D1DF4D7A55D2B771F12F094EAB6E5E10F2617A2F8DAD4FD38AFF8EA39B71C19BD42618CDA86EE7E144636C8E0E7CFC4096E19C3680E09C78A0CDBC05DA2D698E551D5D709717655E56FE3676880B897D2C70DF5F06ECE07C71435255144F8EE41AF110E7B180DA0E6C22FB8FDEF61800025687474703A2F2F70696C65742E65652F6372742F33303836343930302D303030312E637274FE'" "30864900-0001.crt"; then break; fi
echo -e "\n${C_BLUE}Testing LF:${C_NC}"
if ! CheckExecute "lf hitag2 test" "$CLIENTBIN -c 'lf hitag selftest'" "Tests \( ok"; then break; fi
if ! CheckExecute "lf cotag demod test" "$CLIENTBIN -c 'data load -f traces/lf_cotag_220_8331.pm3; data norm; data cthreshold -u 50 -d -20; data envelope; data raw --ar -c 272; lf cotag demod'" \
"COTAG Found: FC 220, CN: 8331 Raw: FFB841170363FFFE00001E7F00000000"; then break; fi
if ! CheckExecute "lf AWID test" "$CLIENTBIN -c 'data load -f traces/lf_AWID-15-259.pm3;lf search -1'" "AWID ID found"; then break; fi