mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-05-12 11:18:11 -07:00
Implement Gallagher MIFARE Classic card writing and update MAD sector functionality
This commit is contained in:
@@ -359,6 +359,7 @@ set (TARGET_SOURCES
|
||||
${PM3_ROOT}/client/src/mifare/desfirecore.c
|
||||
${PM3_ROOT}/client/src/mifare/desfiretest.c
|
||||
${PM3_ROOT}/client/src/mifare/gallaghercore.c
|
||||
${PM3_ROOT}/client/src/mifare/gallaghertest.c
|
||||
${PM3_ROOT}/client/src/uart/ringbuffer.c
|
||||
${PM3_ROOT}/client/src/uart/uart_common.c
|
||||
${PM3_ROOT}/client/src/uart/uart_posix.c
|
||||
|
||||
@@ -795,6 +795,7 @@ SRCS = mifare/aiddesfire.c \
|
||||
mifare/desfiresecurechan.c \
|
||||
mifare/desfiretest.c \
|
||||
mifare/gallaghercore.c \
|
||||
mifare/gallaghertest.c \
|
||||
mifare/mad.c \
|
||||
mifare/mfkey.c \
|
||||
mifare/mifare4.c \
|
||||
|
||||
@@ -279,6 +279,7 @@ set (TARGET_SOURCES
|
||||
${PM3_ROOT}/client/src/mifare/desfirecore.c
|
||||
${PM3_ROOT}/client/src/mifare/desfiretest.c
|
||||
${PM3_ROOT}/client/src/mifare/gallaghercore.c
|
||||
${PM3_ROOT}/client/src/mifare/gallaghertest.c
|
||||
${PM3_ROOT}/client/src/uart/ringbuffer.c
|
||||
${PM3_ROOT}/client/src/uart/uart_common.c
|
||||
${PM3_ROOT}/client/src/uart/uart_posix.c
|
||||
|
||||
+484
-63
File diff suppressed because it is too large
Load Diff
@@ -37,8 +37,8 @@ int CmdHFGallagher(const char *cmd);
|
||||
* @param keyOut Buffer to copy the diversified key into (must be 16 bytes).
|
||||
* @return PM3_SUCCESS if successful, PM3_EINVARG if an argument is invalid.
|
||||
*/
|
||||
int hfgal_diversify_key(uint8_t *site_key, uint8_t *uid, uint8_t uid_len,
|
||||
uint8_t key_num, uint32_t aid, uint8_t *key_output);
|
||||
int hfgal_diversify_desfire_key(uint8_t *site_key, uint8_t *uid, uint8_t uid_len,
|
||||
uint8_t key_num, uint32_t aid, uint8_t *key_output);
|
||||
|
||||
// The response code when an invalid key is used for authentication
|
||||
// Returned in /client/src/mifare/desfirecore.c, line 1185 (if DesfireExchangeEx fails)
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
// Common functionality for low/high-frequency GALLAGHER tag encoding & decoding.
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "gallaghercore.h"
|
||||
#include "aes.h"
|
||||
#include "common.h"
|
||||
#include "ui.h"
|
||||
#include <string.h>
|
||||
|
||||
static void scramble(uint8_t *arr, uint8_t len) {
|
||||
const uint8_t lut[] = {
|
||||
@@ -69,6 +71,51 @@ static void descramble(uint8_t *arr, uint8_t len) {
|
||||
}
|
||||
}
|
||||
|
||||
int gallagher_diversify_classic_key(uint8_t *site_key, uint8_t *csn, size_t csn_len, uint8_t *key_output) {
|
||||
memcpy(key_output, site_key, 16);
|
||||
for (int i = 0; i < csn_len; i++) {
|
||||
key_output[i] = site_key[i] ^ csn[i];
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int gallagher_construct_credential(GallagherCredentials_t *creds, uint8_t region, uint16_t facility, uint32_t card, uint8_t issue, bool mes, uint8_t *csn, size_t csn_len, uint8_t *site_key) {
|
||||
creds->region_code = region;
|
||||
creds->facility_code = facility;
|
||||
creds->card_number = card;
|
||||
creds->issue_level = issue;
|
||||
creds->mes = mes;
|
||||
memcpy(creds->csn, csn, csn_len);
|
||||
memcpy(creds->site_key, site_key, 16);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int gallagher_read_cad(uint8_t *cad, uint8_t region, uint16_t facility) {
|
||||
// CAD entries are 3.5 bytes each (28 bits: 4-bit RC, 16-bit FC, 8-bit sector).
|
||||
// Packed in pairs of 7 bytes starting at byte 4, up to 6 pairs (12 entries).
|
||||
for (int pair = 0; pair < 6; pair++) {
|
||||
int base = 4 + pair * 7;
|
||||
|
||||
// Even entry (first 3.5 bytes of pair)
|
||||
uint8_t rc = (cad[base] >> 4) & 0x0F;
|
||||
uint16_t fc = ((cad[base] & 0x0F) << 12) | (cad[base + 1] << 4) | ((cad[base + 2] >> 4) & 0x0F);
|
||||
uint8_t sector = ((cad[base + 2] & 0x0F) << 4) | ((cad[base + 3] >> 4) & 0x0F);
|
||||
if (rc == region && fc == facility) {
|
||||
return sector;
|
||||
}
|
||||
|
||||
// Odd entry (last 3.5 bytes of pair)
|
||||
rc = cad[base + 3] & 0x0F;
|
||||
fc = (cad[base + 4] << 8) | cad[base + 5];
|
||||
sector = cad[base + 6];
|
||||
if (rc == region && fc == facility) {
|
||||
return sector;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void gallagher_decode_creds(uint8_t *eight_bytes, GallagherCredentials_t *creds) {
|
||||
uint8_t *arr = eight_bytes;
|
||||
|
||||
@@ -107,6 +154,112 @@ void gallagher_encode_creds(uint8_t *eight_bytes, GallagherCredentials_t *creds)
|
||||
scramble(eight_bytes, 8);
|
||||
}
|
||||
|
||||
int gallagher_encode_mes(uint8_t *sixteen_bytes, GallagherCredentials_t *creds) {
|
||||
// unknown parameters from the research these might be for UUID's longer than 4 bytes?
|
||||
uint8_t UB = 0x00;
|
||||
uint8_t UC = 0x00;
|
||||
uint8_t UD = 0x00;
|
||||
uint8_t UE = 0x00;
|
||||
uint8_t PO = 0x00; // Pin offset
|
||||
uint8_t UX = 0x00;
|
||||
uint16_t R = 0x0748;
|
||||
|
||||
uint8_t mes[16];
|
||||
uint8_t diversified_site_key[16];
|
||||
|
||||
if (creds->csn_len > 4) {
|
||||
PrintAndLogEx(ERR, "Credential could not be encoded into a Mifare Enhanced Encryption block. only 4 byte UUID's are supported");
|
||||
return PM3_ENOTIMPL;
|
||||
}
|
||||
|
||||
mes[0] = 0x01;
|
||||
mes[1] = (creds->card_number & 0xFF0000) >> 16;
|
||||
mes[2] = (creds->card_number & 0x00FF00) >> 8;
|
||||
mes[3] = creds->card_number & 0x0000FF;
|
||||
mes[4] = (creds->facility_code & 0xFF00) >> 8;
|
||||
mes[5] = creds->facility_code & 0x00FF;
|
||||
mes[6] = ((creds->region_code & 0x0F) << 4) | (creds->issue_level & 0x0F);
|
||||
mes[7] = (PO & 0x0F) | ((UX & 0x0F) << 4);
|
||||
mes[8] = (UB & 0x0F) | ((UC & 0x0F) << 4);
|
||||
mes[9] = (UD & 0x0F) | ((UE & 0x0F) << 4);
|
||||
mes[10] = creds->csn[0];
|
||||
mes[11] = creds->csn[1];
|
||||
mes[12] = creds->csn[2];
|
||||
mes[13] = creds->csn[3];
|
||||
mes[14] = (R & 0xFF00) >> 8;
|
||||
mes[15] = R & 0x00FF;
|
||||
|
||||
PrintAndLogEx(DEBUG, "MES before encryption %s", sprint_hex_ascii(mes, 16));
|
||||
|
||||
gallagher_diversify_classic_key(creds->site_key, creds->csn, creds->csn_len, diversified_site_key);
|
||||
|
||||
mbedtls_aes_context actx;
|
||||
mbedtls_aes_init(&actx);
|
||||
if (mbedtls_aes_setkey_enc(&actx, diversified_site_key, 128) != 0) return PM3_ENOKEY;
|
||||
if (mbedtls_aes_crypt_ecb(&actx, MBEDTLS_AES_ENCRYPT, mes, sixteen_bytes) != 0) return PM3_ENOKEY;;
|
||||
mbedtls_aes_free(&actx);
|
||||
|
||||
PrintAndLogEx(DEBUG, "MES after encryption %s", sprint_hex_ascii(sixteen_bytes, 16));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int gallagher_decode_mes(uint8_t *block, GallagherCredentials_t *creds) {
|
||||
// unknown parameters from the research these might be for UUID's longer than 4 bytes?
|
||||
// uint8_t UB = 0x00;
|
||||
// uint8_t UC = 0x00;
|
||||
// uint8_t UD = 0x00;
|
||||
// uint8_t UE = 0x00;
|
||||
// uint8_t PO = 0x00;
|
||||
// uint8_t UX = 0x00;
|
||||
uint16_t R = 0x0748;
|
||||
uint8_t mes[16];
|
||||
|
||||
uint8_t diversified_site_key[16];
|
||||
gallagher_diversify_classic_key(creds->site_key, creds->csn, creds->csn_len, diversified_site_key);
|
||||
if (creds->csn_len > 4) {
|
||||
PrintAndLogEx(WARNING, "UUID length is > 4, this may not be a valid gallagher credential?");
|
||||
}
|
||||
|
||||
// AES decrypt 16 bytes
|
||||
mbedtls_aes_context actx;
|
||||
mbedtls_aes_init(&actx);
|
||||
if (mbedtls_aes_setkey_dec(&actx, diversified_site_key, 128) != 0) return PM3_ENOKEY;
|
||||
if (mbedtls_aes_crypt_ecb(&actx, MBEDTLS_AES_DECRYPT, block, mes) != 0) return PM3_ENOKEY;;
|
||||
mbedtls_aes_free(&actx);
|
||||
|
||||
PrintAndLogEx(DEBUG, "MES after decryption %s", sprint_hex_ascii(mes, 16));
|
||||
|
||||
if (mes[0] != 0x01) {
|
||||
PrintAndLogEx(ERR, "MES block is not valid");
|
||||
return PM3_EWRONGANSWER;
|
||||
}
|
||||
creds->card_number = mes[1] << 16 | mes[2] << 8 | mes[3];
|
||||
creds->facility_code = mes[4] << 8 | mes[5];
|
||||
creds->region_code = (mes[6] & 0xF0) >> 4;
|
||||
creds->issue_level = mes[6] & 0x0F;
|
||||
// PO = mes[7] & 0x0F;
|
||||
// UX = (mes[7] & 0xF0) >> 4;
|
||||
// UB = mes[8] & 0x0F;
|
||||
// UC = (mes[8] & 0xF0) >> 4;
|
||||
// UD = mes[9] & 0x0F;
|
||||
// UE = (mes[9] & 0xF0) >> 4;
|
||||
// csn is already verified by key diversification
|
||||
// csn[0] = mes[10];
|
||||
// csn[1] = mes[11];
|
||||
// csn[2] = mes[12];
|
||||
// csn[3] = mes[13];
|
||||
R = mes[14] << 8 | mes[15];
|
||||
if (R != 0x0748) {
|
||||
PrintAndLogEx(WARNING, "R value is different from 0x0748, this hasn't been seen in the wild \n https://github.com/megabug/gallagher-research/blob/master/formats/mes.md");
|
||||
}
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
bool gallagher_is_valid_creds_struct(GallagherCredentials_t *creds) {
|
||||
return gallagher_is_valid_creds(creds->region_code, creds->facility_code, creds->card_number, creds->issue_level);
|
||||
}
|
||||
|
||||
bool gallagher_is_valid_creds(uint64_t region_code, uint64_t facility_code, uint64_t card_number, uint64_t issue_level) {
|
||||
bool is_valid = true;
|
||||
|
||||
@@ -129,3 +282,21 @@ bool gallagher_is_valid_creds(uint64_t region_code, uint64_t facility_code, uint
|
||||
}
|
||||
return is_valid;
|
||||
}
|
||||
|
||||
void print_gallagher_creds(GallagherCredentials_t *creds) {
|
||||
|
||||
if (!gallagher_is_valid_creds_struct(creds)) {
|
||||
PrintAndLogEx(ERR, "Invalid Gallagher credential");
|
||||
return;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Gallagher - region: " _GREEN_("%c") " ( " _GREEN_("%u") " )"
|
||||
", facility: " _GREEN_("%u")
|
||||
", card number: " _GREEN_("%u")
|
||||
", issue level: " _GREEN_("%u"),
|
||||
'A' + creds->region_code,
|
||||
creds->region_code,
|
||||
creds->facility_code,
|
||||
creds->card_number,
|
||||
creds->issue_level
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#define MIFARE_GALLAGHERCORE_H__
|
||||
|
||||
#include "common.h"
|
||||
#include "crypto/libpcrypto.h"
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
@@ -24,12 +25,30 @@ typedef struct {
|
||||
uint16_t facility_code;
|
||||
uint32_t card_number;
|
||||
uint8_t issue_level;
|
||||
bool mes;
|
||||
uint8_t csn[10];
|
||||
size_t csn_len;
|
||||
uint8_t site_key[16];
|
||||
} GallagherCredentials_t;
|
||||
|
||||
int gallagher_diversify_classic_key(uint8_t *site_key, uint8_t *csn, size_t csn_len, uint8_t *key_output);
|
||||
|
||||
int gallagher_read_cad(uint8_t *cad, uint8_t region, uint16_t facility);
|
||||
|
||||
void gallagher_encode_creds(uint8_t *eight_bytes, GallagherCredentials_t *creds);
|
||||
|
||||
void gallagher_decode_creds(uint8_t *eight_bytes, GallagherCredentials_t *creds);
|
||||
|
||||
int gallagher_construct_credential(GallagherCredentials_t *creds, uint8_t region, uint16_t facility, uint32_t card, uint8_t issue, bool mes, uint8_t *csn, size_t csn_len, uint8_t *site_key);
|
||||
|
||||
int gallagher_encode_mes(uint8_t *sector, GallagherCredentials_t *creds);
|
||||
|
||||
int gallagher_decode_mes(uint8_t *sector, GallagherCredentials_t *creds);
|
||||
|
||||
bool gallagher_is_valid_creds(uint64_t region_code, uint64_t facility_code, uint64_t card_number, uint64_t issue_level);
|
||||
|
||||
bool gallagher_is_valid_creds_struct(GallagherCredentials_t *creds);
|
||||
|
||||
void print_gallagher_creds(GallagherCredentials_t *creds);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
#include "gallaghertest.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <string.h> // memcpy memset
|
||||
#include "ui.h"
|
||||
#include "crc.h"
|
||||
|
||||
#include "mifare/gallaghercore.h"
|
||||
|
||||
static bool creds_match(GallagherCredentials_t *a, GallagherCredentials_t *b) {
|
||||
return a->region_code == b->region_code &&
|
||||
a->facility_code == b->facility_code &&
|
||||
a->card_number == b->card_number &&
|
||||
a->issue_level == b->issue_level;
|
||||
}
|
||||
|
||||
static bool test_CAD(void) {
|
||||
// Example CAD sector from https://github.com/megabug/gallagher-research/blob/master/formats/card-specific/mifare-classic.md
|
||||
uint8_t cad[] = {0x1B, 0x58, 0x00, 0x01, 0xC1, 0x33, 0x70, 0xFD, 0x13, 0x38, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x77, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
// Entry 0: RC=0xC, FC=0x1337, Sector=0x0F
|
||||
int result = gallagher_read_cad(cad, 0xC, 0x1337);
|
||||
if (result != 0x0F) {
|
||||
PrintAndLogEx(INFO, "Gallagher CAD test 1 failed: expected sector 0x0F, got 0x%02X", result);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Entry 1: RC=0xD, FC=0x1338, Sector=0x0D
|
||||
result = gallagher_read_cad(cad, 0xD, 0x1338);
|
||||
if (result != 0x0D) {
|
||||
PrintAndLogEx(INFO, "Gallagher CAD test 2 failed: expected sector 0x0D, got 0x%02X", result);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Non-existent entry should return -1
|
||||
result = gallagher_read_cad(cad, 0xA, 0x1234);
|
||||
if (result != -1) {
|
||||
PrintAndLogEx(INFO, "Gallagher CAD test 3 failed: expected -1, got %d", result);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool test_creds(void) {
|
||||
GallagherCredentials_t creds1 = {
|
||||
.region_code = 0x0,
|
||||
.facility_code = 0x0,
|
||||
.card_number = 0x0,
|
||||
.issue_level = 0x0,
|
||||
};
|
||||
|
||||
GallagherCredentials_t creds2 = {
|
||||
.region_code = 0x1,
|
||||
.facility_code = 0x2,
|
||||
.card_number = 0x20,
|
||||
.issue_level = 0x1,
|
||||
};
|
||||
|
||||
GallagherCredentials_t cred_result = {0};
|
||||
uint8_t bytes_result[8] = {0};
|
||||
|
||||
gallagher_encode_creds(bytes_result, &creds1);
|
||||
gallagher_decode_creds(bytes_result, &cred_result);
|
||||
if (!creds_match(&cred_result, &creds1)) {
|
||||
PrintAndLogEx(INFO, "Gallagher encode/decode roundtrip test 1 failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
gallagher_encode_creds(bytes_result, &creds2);
|
||||
gallagher_decode_creds(bytes_result, &cred_result);
|
||||
if (!creds_match(&cred_result, &creds2)) {
|
||||
PrintAndLogEx(INFO, "Gallagher encode/decode roundtrip test 2 failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test decode/encode against known real-world data from the documentation
|
||||
static bool test_known_vector_creds(void) {
|
||||
// From doc: 0xA3B4B0C151B0A31B decodes to RC=12, FC=4919(0x1337), CN=61453(0xF00D), IL=1
|
||||
uint8_t known_bytes[] = {0xA3, 0xB4, 0xB0, 0xC1, 0x51, 0xB0, 0xA3, 0x1B};
|
||||
GallagherCredentials_t expected = {
|
||||
.region_code = 12,
|
||||
.facility_code = 4919,
|
||||
.card_number = 61453,
|
||||
.issue_level = 1,
|
||||
};
|
||||
|
||||
// Test decode
|
||||
GallagherCredentials_t result = {0};
|
||||
gallagher_decode_creds(known_bytes, &result);
|
||||
if (!creds_match(&expected, &result)) {
|
||||
PrintAndLogEx(INFO, "Known vector decode failed: RC=%d FC=%d CN=%d IL=%d",
|
||||
result.region_code, result.facility_code, result.card_number, result.issue_level);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Test encode roundtrip
|
||||
uint8_t encoded[8] = {0};
|
||||
gallagher_encode_creds(encoded, &expected);
|
||||
if (memcmp(encoded, known_bytes, 8) != 0) {
|
||||
PrintAndLogEx(INFO, "Known vector encode failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify bitwise inverse (block 0 format: 8-byte creds + 8-byte inverse)
|
||||
uint8_t known_block0[] = {0xA3, 0xB4, 0xB0, 0xC1, 0x51, 0xB0, 0xA3, 0x1B,
|
||||
0x5C, 0x4B, 0x4F, 0x3E, 0xAE, 0x4F, 0x5C, 0xE4
|
||||
};
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if ((uint8_t)(known_block0[i] ^ 0xFF) != known_block0[i + 8]) {
|
||||
PrintAndLogEx(INFO, "Bitwise inverse check failed at byte %d", i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test MAD CRC against known sector 0 data from the documentation
|
||||
static bool test_mad_crc(void) {
|
||||
// Full sector 0 from documentation (blocks 0-2, excluding trailer)
|
||||
uint8_t sector0[64] = {
|
||||
// Block 0 (manufacturer)
|
||||
0xE3, 0x51, 0x54, 0x3C, 0xDA, 0x08, 0x04, 0x00, 0x01, 0x6F, 0x01, 0x6D, 0x45, 0x68, 0xF8, 0x1D,
|
||||
// Block 1 (MAD: CRC, info byte, AIDs 1-7)
|
||||
0xBD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// Block 2 (MAD: AIDs 8-15)
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x48, 0x11, 0x48, 0x12, 0x48,
|
||||
// Block 3 (sector trailer - not part of CRC)
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x77, 0x88, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
// MAD v1 CRC: computed over sector0[17..47] (info byte + 15 AID pairs = 31 bytes)
|
||||
uint8_t expected_crc = sector0[16]; // 0xBD
|
||||
uint8_t computed_crc = CRC8Mad(§or0[16 + 1], 15 + 16);
|
||||
if (computed_crc != expected_crc) {
|
||||
PrintAndLogEx(INFO, "MAD CRC test failed: expected 0x%02X, got 0x%02X", expected_crc, computed_crc);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool test_MES(void) {
|
||||
|
||||
uint8_t csn[] = {0x3C, 0x54, 0x51, 0xE3};
|
||||
uint8_t csn_len = 4;
|
||||
uint8_t site_key[] = {0x13, 0x37, 0xD0, 0x0D, 0x13, 0x37, 0xD0, 0x0D, 0x13, 0x37, 0xD0, 0x0D, 0x13, 0x37, 0xD0, 0x0D};
|
||||
|
||||
GallagherCredentials_t known_cred;
|
||||
gallagher_construct_credential(&known_cred, 12, 0x1337, 0xF00D, 1, true, csn, csn_len, site_key);
|
||||
|
||||
GallagherCredentials_t result_creds = {0};
|
||||
gallagher_construct_credential(&result_creds, 0, 0, 0, 0, true, csn, csn_len, site_key);
|
||||
|
||||
uint8_t sector_result[16] = {0};
|
||||
uint8_t known_sector[16] = {0x4F, 0x36, 0xB7, 0x4E, 0xFF, 0xCD, 0x76, 0xEF, 0xED, 0xA5, 0x74, 0x58, 0xC8, 0xB4, 0xE3, 0x04};
|
||||
|
||||
// Test encode
|
||||
gallagher_encode_mes(sector_result, &known_cred);
|
||||
if (memcmp(sector_result, known_sector, 16) != 0) {
|
||||
PrintAndLogEx(INFO, "Gallagher MES encode test failed");
|
||||
PrintAndLogEx(INFO, "Expected: %s", sprint_hex_ascii(known_sector, 16));
|
||||
PrintAndLogEx(INFO, "Got: %s", sprint_hex_ascii(sector_result, 16));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Test decode
|
||||
if (gallagher_decode_mes(known_sector, &result_creds) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(INFO, "Gallagher MES decode test failed");
|
||||
return false;
|
||||
}
|
||||
if (!creds_match(&known_cred, &result_creds)) {
|
||||
PrintAndLogEx(INFO, "Gallagher MES decoded different creds than expected");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GallagherTest(bool verbose) {
|
||||
bool result = true;
|
||||
result &= test_CAD();
|
||||
result &= test_creds();
|
||||
result &= test_known_vector_creds();
|
||||
result &= test_mad_crc();
|
||||
result &= test_MES();
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// See LICENSE.txt for the text of the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// tests for desfire
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef __GALLAGHERTEST_H__
|
||||
#define __GALLAGHERTEST_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "common.h"
|
||||
|
||||
bool GallagherTest(bool verbose);
|
||||
|
||||
#endif /* __GALLAGHERTEST_H__ */
|
||||
Reference in New Issue
Block a user