this commit refactors the signature checks. First we introduce a common pm3 generic private / public key pair in order to allow for users to self sign their own modded device. The verification checks now looks at both hard coded public keys. If a vendor wants to add their own public key thus allowing for a simple way for us to identify their devices they can now do so. The downside is that the firmware mismatch detection becomes a bit dodgy. mem info; mem info -v; mem info -s -p <filename.pem>; mem info -s -p <filename.pem> -w contains the changes. OBS! when -w be careful to not overwrite your genuine RDV4 signature. As always, with great power comes great responsibility

This commit is contained in:
iceman1001
2025-09-25 19:44:36 +02:00
parent 1412b6882b
commit b097e10aa3
11 changed files with 340 additions and 178 deletions
+6 -4
View File
@@ -3,15 +3,17 @@ 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 `mem info` and how the signature handling is done (@iceman1001)
- Added `client/resources/pm3_generic_private_key.pem` in order to self-sign a modded device (@iceman1001)
- Fix `hf mfdes value --op clear` commands for clearing more than 0x80000000 values and getfilesettings mac mode (@merlokk)
- Added ATR fingerprinting to `hf 14a/14b info` (@doegox)
## [Phrack.4.20728][2025-09-11]
- Change `lf t55xx restore` - now skips writing block0 if its all zeros (@iceman1001)
- Changed `lf t55xx restore` - now skips writing block0 if its all zeros (@iceman1001)
- Added `HID Simplex Grinnell 36-bit` - Improved Simplex decoder (@datafx, @henrygab)
- Change `lf search` - also test for chipset even if there was just signal noice (@iceman1001)
- Changed `lf search` - also test for chipset even if there was just signal noice (@iceman1001)
- Added detection of PCF 7961 , thanks progman (@iceman1001)
- Change `reveng -g` - now correctly take 1024 hexstring as input (@iceman1001)
- Changed `reveng -g` - now correctly take 1024 hexstring as input (@iceman1001)
- Added `--override` parameter to NDEF read for overriding MAD CRC check (@iceman1001)
- Added `hf saflok` commands (@stiebeljoshua)
- Added `ntag_clean.lua` script for easier NTAG memory wipe (@trigat)
@@ -19,7 +21,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Added `lf t55xx view` - now viewing of T55XX dump files is possible (@iceman1001)
- Fixed `lf indala cone` - now writing the right bits when using `--fc` and `--cn`
- Changed readline hack logic for async dbg msg to be ready for readline 8.3 (@doegox)
- Improved To avoid conflicts with ModemManager on Linux, is recommended to masking the service (@grugnoymeme)
- Changed documentation to avoid conflicts with ModemManager on Linux, is recommended to masking the service (@grugnoymeme)
- Changed `data crypto` - now also handles AES-256 (@iceman1001)
- Changed `hf mfdes info` - add recognition of Swissbit iShield Key Mifare (@ah01)
- Changed `hf mf info` - add detection for unknown backdoor keys and for some backdoor variants (@doegox)
+9 -2
View File
@@ -2968,7 +2968,7 @@ static void PacketReceived(PacketCommandNG *packet) {
LED_B_OFF();
break;
}
case CMD_FLASHMEM_INFO: {
case CMD_FLASHMEM_GET_SIGNATURE: {
LED_B_ON();
@@ -2983,12 +2983,19 @@ static void PacketReceived(PacketCommandNG *packet) {
FlashStop();
}
reply_ng(CMD_FLASHMEM_INFO, (isok) ? PM3_SUCCESS : PM3_EFLASH, (uint8_t *)info, sizeof(rdv40_validation_t));
reply_ng(CMD_FLASHMEM_GET_SIGNATURE, (isok) ? PM3_SUCCESS : PM3_EFLASH, (uint8_t *)info, sizeof(rdv40_validation_t));
BigBuf_free();
LED_B_OFF();
break;
}
case CMD_FLASHMEM_GET_INFO: {
LED_B_ON();
spi_flash_t *spi = flash_get_info();
reply_ng(CMD_FLASHMEM_GET_INFO, PM3_SUCCESS, (uint8_t *)spi, sizeof(spi_flash_t));
LED_B_OFF();
break;
}
case CMD_FLASHMEM_PAGES64K: {
LED_B_ON();
@@ -0,0 +1,16 @@
-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAPrs5grcEJNNgoTl
KgYSHfAYeGqUVyy7DzGNzpQryLBN3eVIj2+2oQB/BfW4wGpfg35s/R0ohCZOjJ81
oLK1gFx+mvFMmzUP9MzNDxMs/3TumiSQqEQSPQYi8BQWLXbd73pfJP6p40+mCK61
i3wQtL/H85xL/G5GNQOg3bubdz4BAgMBAAECgYB8QTVFKWZX2ykHsAdYTD5g920h
seVdNCA49LTYMLpHe7em44CL3E7r1PrZjCxUQIn33/aTKs4NvhXqfP7fn/s4V0CZ
mjZSvWQ3ts5CYOGa8LWgaU7qYREPJKVDRgmMFiRntbP9woNLOhnQkZEs75KCKgnT
kDndVTtxlxbn2evKVQJBAP8M7RNI1JuiE/gTq9dL9q4ZKo7NpATanFKwgd7gCooN
anlfpMxhN7FgQRcfjHpndmpMQXhe5UE6C+XcziZj2TcCQQD73AqHNjU6hI0/rgiQ
MXiiC+Oe5G7QPxRwvbjTuLghC/lWCDd96LkKSZLZR0pmSj5nldB0/dDXiZUNF/Q+
Ht6HAkEAxGMQnXvD8b6gP7Ht7I6aeD36jhD8DZzDJ8yvg4zhsKFZ7fFedN0axCLI
m+R4B7xo6rqi4uu2/T2T8b/OoLLbiwJAOzSYzPwzOxRZ1/RjUvIuN3mwAnQUkKOj
fHU885hiwHH+JPk9gj2o8gAloyodFTqyvMr8++OGqoRPI4rUAZ5kFQJBANQCGq2g
Qh2cFU6pmgoSDExnzOLWWeeCs1buw1XyVULHGv+n6zFowNmkmjJCTF1lvGehcnyW
MNgnxt2QK7Q+RnI=
-----END PRIVATE KEY-----
@@ -0,0 +1 @@
d99cb37ec1ea04790746a97b439fd3a3dbe5b0eb3de439cdfbf6e7e82ff871d278f11923049fd19e945d90135de112250103850305ed1eca0c82a51a6c5f1682 pm3_generic_private_key.pem
+246 -149
View File
File diff suppressed because it is too large Load Diff
+9 -3
View File
@@ -31,8 +31,14 @@ typedef enum {
DICTIONARY_MIFARE_ULAES,
} Dictionary_t;
typedef enum {
SIGN_RDV4 = 0,
SIGN_GENERIC,
SIGN_UNK = 99
} signature_e;
int CmdFlashMem(const char *Cmd);
int rdv4_get_signature(rdv40_validation_t *out);
int rdv4_validate(rdv40_validation_t *mem);
int rdv4_get_flash_pages64k(uint8_t *pages64k);
int pm3_get_signature(rdv40_validation_t *out);
int pm3_validate(rdv40_validation_t *mem, signature_e *type);
int pm3_get_flash_pages64k(uint8_t *pages64k);
#endif
+29 -11
View File
@@ -1575,16 +1575,25 @@ void pm3_version_short(void) {
if (IfPm3Rdv4Fw()) {
bool is_genuine_rdv4 = false;
// validate signature data
rdv40_validation_t mem;
if (rdv4_get_signature(&mem) == PM3_SUCCESS) {
if (rdv4_validate(&mem) == PM3_SUCCESS) {
is_genuine_rdv4 = true;
signature_e type;
if (pm3_get_signature(&mem) == PM3_SUCCESS) {
if (pm3_validate(&mem, &type) == PM3_SUCCESS) {
if (type == SIGN_RDV4) {
PrintAndLogEx(NORMAL, " Target.... %s", _YELLOW_("RDV4"));
} else if (type == SIGN_GENERIC) {
PrintAndLogEx(NORMAL, " Target.... %s", _YELLOW_("GENERIC"));
} else {
PrintAndLogEx(NORMAL, " Target.... %s", _RED_("device / fw mismatch"));
}
}
}
PrintAndLogEx(NORMAL, " Target.... %s", (is_genuine_rdv4) ? _YELLOW_("RDV4") : _RED_("device / fw mismatch"));
} else {
PrintAndLogEx(NORMAL, " Target.... %s", _YELLOW_("PM3 GENERIC"));
}
@@ -1702,17 +1711,26 @@ void pm3_version(bool verbose, bool oneliner) {
if (WaitForResponseTimeout(CMD_VERSION, &resp, 1000)) {
if (IfPm3Rdv4Fw()) {
bool is_genuine_rdv4 = false;
// validate signature data
rdv40_validation_t mem;
if (rdv4_get_signature(&mem) == PM3_SUCCESS) {
if (rdv4_validate(&mem) == PM3_SUCCESS) {
is_genuine_rdv4 = true;
signature_e type;
if (pm3_get_signature(&mem) == PM3_SUCCESS) {
if (pm3_validate(&mem, &type) == PM3_SUCCESS) {
if (type == SIGN_RDV4) {
PrintAndLogEx(NORMAL, " Device.................... " _GREEN_("RDV4"));
PrintAndLogEx(NORMAL, " Firmware.................. " _GREEN_("RDV4"));
} else if (type == SIGN_GENERIC) {
PrintAndLogEx(NORMAL, " Device.................... ", _GREEN_("GENERIC"));
PrintAndLogEx(NORMAL, " Firmware.................. ", _GREEN_("GENERIC"));
} else {
PrintAndLogEx(NORMAL, " Device.................... " _RED_("Bad signature detected!"));
PrintAndLogEx(NORMAL, " Firmware.................. " _YELLOW_("N/A"));
}
}
}
PrintAndLogEx(NORMAL, " Device.................... %s", (is_genuine_rdv4) ? _GREEN_("RDV4") : _RED_("device / fw mismatch"));
PrintAndLogEx(NORMAL, " Firmware.................. %s", (is_genuine_rdv4) ? _GREEN_("RDV4") : _YELLOW_("RDV4"));
PrintAndLogEx(NORMAL, " External flash............ %s", IfPm3Flash() ? _GREEN_("present") : _YELLOW_("absent"));
PrintAndLogEx(NORMAL, " Smartcard reader.......... %s", IfPm3Smartcard() ? _GREEN_("present") : _YELLOW_("absent"));
PrintAndLogEx(NORMAL, " FPC USART for BT add-on... %s", IfPm3FpcUsartHost() ? _GREEN_("present") : _YELLOW_("absent"));
+8 -3
View File
@@ -43,9 +43,13 @@ static uint32_t FLASHMEM_SPIBAUDRATE = FLASH_BAUD;
#ifndef AS_BOOTROM
spi_flash_t spi_flash_data = {0};
uint8_t spi_flash_pages64k = 4;
static spi_flash_t spi_flash_data = {0};
spi_flash_t *flash_get_info(void) {
return &spi_flash_data;
}
void FlashmemSetSpiBaudrate(uint32_t baudrate) {
FLASHMEM_SPIBAUDRATE = baudrate;
@@ -387,7 +391,7 @@ void Flashmem_print_status(void) {
);
}
Dbprintf(" Memory size............. " _YELLOW_("%d kB (%d pages * 64k)"), spi_flash_pages64k * 64, spi_flash_pages64k);
Dbprintf(" Memory size............. " _YELLOW_("%d Kb") " ( %d pages * 64k )", spi_flash_pages64k * 64, spi_flash_pages64k);
uint8_t uid[8] = {0, 0, 0, 0, 0, 0, 0, 0};
Flash_UniqueID(uid);
@@ -439,6 +443,7 @@ bool FlashDetect(void) {
}
}
spi_flash_data.pages64k = spi_flash_pages64k;
return ret;
}
+3 -5
View File
@@ -21,6 +21,8 @@
#define __FLASHMEM_H
#include "common.h"
#include "pmflash.h"
// Used Command
#define ID 0x90
@@ -135,11 +137,7 @@ uint16_t Flash_WriteData(uint32_t address, uint8_t *in, uint16_t len);
uint16_t Flash_WriteDataCont(uint32_t address, uint8_t *in, uint16_t len);
void Flashmem_print_status(void);
typedef struct {
uint8_t manufacturer_id;
uint8_t device_id;
uint16_t jedec_id;
} spi_flash_t;
spi_flash_t *flash_get_info(void);
extern uint8_t spi_flash_pages64k;
+7 -1
View File
@@ -305,7 +305,7 @@ typedef struct {
typedef struct {
// 64KB SRAM -> 524288 bits(max sample num) < 2^30
uint32_t samples :
uint32_t samples :
LF_SAMPLES_BITS;
bool realtime : 1;
bool verbose : 1;
@@ -473,6 +473,9 @@ typedef struct {
#define CMD_SPIFFS_UNMOUNT 0x0131
#define CMD_SPIFFS_WRITE 0x0132
#define CMD_FLASHMEM_GET_SIGNATURE 0x0147
#define CMD_FLASHMEM_GET_INFO 0x0148
// We take +0x1000 when having a variant of similar function (todo : make it an argument!)
#define CMD_SPIFFS_APPEND 0x1132
@@ -844,11 +847,13 @@ typedef struct {
#define MIFARE_2K_MAX_BYTES 2048
#define MIFARE_1K_MAX_BYTES 1024
#define MIFARE_MINI_MAX_BYTES 320
#define FLAG_MASK_MF_SIZE 0x00C0
#define FLAG_MF_MINI 0x0000
#define FLAG_MF_1K 0x0040
#define FLAG_MF_2K 0x0080
#define FLAG_MF_4K 0x00C0
#define FLAG_SET_MF_SIZE(flags, size) {\
flags = (flags & (~FLAG_MASK_MF_SIZE))|\
(size == MIFARE_MINI_MAX_BYTES ? FLAG_MF_MINI : \
@@ -857,6 +862,7 @@ typedef struct {
(size == MIFARE_4K_MAX_BYTES ? FLAG_MF_4K : \
0))));\
}
// else we tell to take UID from block 0:
#define IS_FLAG_MF_SIZE(flags, size) (\
(flags & FLAG_MASK_MF_SIZE) == \
+6
View File
@@ -93,5 +93,11 @@ typedef struct {
uint8_t signature[FLASH_MEM_SIGNATURE_LEN];
} PACKED rdv40_validation_t;
typedef struct {
uint8_t manufacturer_id;
uint8_t device_id;
uint16_t jedec_id;
uint8_t pages64k;
} PACKED spi_flash_t;
#endif // __PMFLASH_H