Merge pull request #3156 from cindersocket/fix-3041

Fixes RfidResearchGroup/proxmark3#3041
This commit is contained in:
Iceman
2026-03-25 07:40:53 +07:00
committed by GitHub
4 changed files with 113 additions and 12 deletions

View File

@@ -3982,24 +3982,71 @@ static int CmdQRcode(const char *Cmd) {
CLIParserInit(&ctx, "data qrcode",
"Generate a QR code with the input data",
"data qrcode -f <filename>\n"
"data qrcode -d 123456789\n"
"data qrcode -d 0123456789\n"
"data qrcode -d AABBCCDD --ascii\n"
);
void *argtable[] = {
arg_param_begin,
arg_lit0("a", "ascii", "Render with ASCII-safe characters"),
arg_str0("f", "file", "<fn>", "Specify a filename"),
arg_str0("d", "data", "<hex>", "message as hex bytes"),
arg_str0("d", "data", "<hex>", "message as a single hex byte string"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
bool ascii = arg_get_lit(ctx, 1);
int fnlen = 0;
char filename[FILE_PATH_SIZE] = { 0 };
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
int dlen = 0;
char data[1024] = { 0 };
CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)data, sizeof(data), &dlen);
uint8_t data[512] = { 0 };
int data_arg_len = 0;
char data_arg[1024] = { 0 };
struct arg_str *data_arg_str = arg_get_str(ctx, 3);
int data_count = data_arg_str->count;
if (data_count > 1) {
CLIParserFree(ctx);
PrintAndLogEx(ERR, "QR data accepts exactly one -d value. Use a single contiguous hex string and encode spaces as 20.");
return PM3_EINVARG;
}
if (data_count == 1) {
if (CLIParamStrToBuf(data_arg_str, (uint8_t *)data_arg, sizeof(data_arg), &data_arg_len) != 0) {
CLIParserFree(ctx);
return PM3_EINVARG;
}
if (strpbrk(data_arg, " \t") != NULL) {
CLIParserFree(ctx);
PrintAndLogEx(ERR, "QR data must be one contiguous hex string. Spaces are not supported; encode a space byte as 20.");
return PM3_EINVARG;
}
for (int i = 0; i < data_arg_len; i++) {
if (isxdigit((unsigned char)data_arg[i]) == 0) {
CLIParserFree(ctx);
PrintAndLogEx(ERR, "QR data must contain only hex characters 0-9, a-f, or A-F.");
return PM3_EINVARG;
}
}
if (data_arg_len & 1) {
CLIParserFree(ctx);
PrintAndLogEx(ERR, "QR data must contain an even number of hex digits.");
return PM3_EINVARG;
}
dlen = hex_to_bytes(data_arg, data, sizeof(data));
if (dlen < 0) {
CLIParserFree(ctx);
PrintAndLogEx(ERR, "QR data must be valid hex bytes.");
return PM3_EINVARG;
}
}
CLIParserFree(ctx);
if (fnlen && dlen) {
@@ -4028,17 +4075,27 @@ static int CmdQRcode(const char *Cmd) {
}
if (dlen) {
int8_t smallest_version = qrcode_getMinVersionForBytes(dlen, ECC_LOW);
if (smallest_version < 1) {
PrintAndLogEx(ERR, "QR data is too large to fit in a supported QR code.");
return PM3_EINVARG;
}
// calc size of input data to get the correct
int smallest_version = (dlen + 17) / 20;
uint8_t qr_arr[qrcode_getBufferSize(smallest_version)];
qrcode_initText(&qrcode, qr_arr, smallest_version, ECC_LOW, (char *) data);
if (qrcode_initBytes(&qrcode, qr_arr, smallest_version, ECC_LOW, data, dlen) < 0) {
PrintAndLogEx(ERR, "Failed to encode QR data.");
return PM3_ESOFT;
}
PrintAndLogEx(NORMAL, "");
qrcode_print_matrix_utf8(&qrcode);
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "");
qrcode_print_matrix_utf8_2x2(&qrcode);
if (ascii) {
qrcode_print_matrix_ascii(&qrcode);
} else {
qrcode_print_matrix_utf8(&qrcode);
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "");
qrcode_print_matrix_utf8_2x2(&qrcode);
}
PrintAndLogEx(NORMAL, "");
}

View File

@@ -793,6 +793,34 @@ uint16_t qrcode_getBufferSize(uint8_t version) {
return bb_getGridSizeBytes(4 * version + 17);
}
int8_t qrcode_getMinVersionForBytes(uint16_t length, uint8_t ecc) {
if (ecc > ECC_HIGH) {
return -1;
}
uint8_t eccFormatBits = (ECC_FORMAT_BITS >> (2 * ecc)) & 0x03;
#if LOCK_VERSION == 0
for (uint8_t version = 1; version <= 40; version++) {
uint16_t moduleCount = NUM_RAW_DATA_MODULES[version - 1];
uint16_t dataCapacity = moduleCount / 8 - NUM_ERROR_CORRECTION_CODEWORDS[eccFormatBits][version - 1];
uint32_t requiredBits = 4 + getModeBits(version, MODE_BYTE) + ((uint32_t)length * 8);
if (requiredBits <= ((uint32_t)dataCapacity * 8)) {
return version;
}
}
return -1;
#else
uint8_t version = LOCK_VERSION;
uint16_t moduleCount = NUM_RAW_DATA_MODULES;
uint16_t dataCapacity = moduleCount / 8 - NUM_ERROR_CORRECTION_CODEWORDS[eccFormatBits];
uint32_t requiredBits = 4 + getModeBits(version, MODE_BYTE) + ((uint32_t)length * 8);
return (requiredBits <= ((uint32_t)dataCapacity * 8)) ? version : -1;
#endif
}
// @TODO: Return error if data is too big.
int8_t qrcode_initBytes(QRCode *qrcode, uint8_t *modules, uint8_t version, uint8_t ecc, uint8_t *data, uint16_t length) {
uint8_t size = version * 4 + 17;
@@ -885,6 +913,15 @@ bool qrcode_getModule(QRCode *qrcode, uint8_t x, uint8_t y) {
return (qrcode->modules[offset >> 3] & (1 << (7 - (offset & 0x07)))) != 0;
}
void qrcode_print_matrix_ascii(QRCode *q) {
for (uint8_t y = 0; y < q->size; y++) {
for (uint8_t x = 0; x < q->size; x++) {
PrintAndLogEx(NORMAL, "%s" NOLF, qrcode_getModule(q, x, y) ? "##" : " ");
}
PrintAndLogEx(NORMAL, "");
}
}
void qrcode_print_matrix_utf8(QRCode *q) {
// UTF-8 block characters for better resolution

View File

@@ -73,11 +73,13 @@ extern "C" {
uint16_t qrcode_getBufferSize(uint8_t version);
int8_t qrcode_getMinVersionForBytes(uint16_t length, uint8_t ecc);
int8_t qrcode_initText(QRCode *qrcode, uint8_t *modules, uint8_t version, uint8_t ecc, const char *data);
int8_t qrcode_initBytes(QRCode *qrcode, uint8_t *modules, uint8_t version, uint8_t ecc, uint8_t *data, uint16_t length);
bool qrcode_getModule(QRCode *qrcode, uint8_t x, uint8_t y);
void qrcode_print_matrix_ascii(QRCode *q);
void qrcode_print_matrix_utf8(QRCode *q);
void qrcode_print_matrix_utf8_2x2(QRCode *q);

View File

@@ -462,6 +462,11 @@ while true; do
if ! CheckExecute "reveng readline test" "$CLIENTBIN -c 'reveng -h;reveng -D'" "CRC-64/GO-ISO"; then break; fi
if ! CheckExecute "reveng -g test" "$CLIENTBIN -c 'reveng -g abda202c'" "CRC-16/ISO-IEC-14443-3-A"; then break; fi
if ! CheckExecute "reveng -w test" "$CLIENTBIN -c 'reveng -w 8 -s 01020304e3 010204039d'" "CRC-8/SMBUS"; then break; fi
if ! CheckExecute "data qrcode ascii test" "$CLIENTBIN -c 'data qrcode -d aa --ascii'" "##"; then break; fi
if ! CheckExecute "data qrcode repeated -d" "$CLIENTBIN -c 'data qrcode -d aa -d bb' 2>&1" "excess option -d\\|--data"; then break; fi
if ! CheckExecute "data qrcode invalid hex" "$CLIENTBIN -c 'data qrcode -d zz' 2>&1" "QR data must contain only hex characters"; then break; fi
if ! CheckExecute "data qrcode odd hex" "$CLIENTBIN -c 'data qrcode -d a' 2>&1" "QR data must contain an even number of hex digits"; then break; fi
if ! CheckExecute "data qrcode spaced hex" "$CLIENTBIN -c 'data qrcode -d \"aa bb\"' 2>&1" "Spaces are not supported; encode a space byte as 20"; then break; fi
if ! CheckExecute "mfu pwdgen test" "$CLIENTBIN -c 'hf mfu pwdgen --test'" "Selftest ok"; then break; fi
if ! CheckExecute "mfu keygen test" "$CLIENTBIN -c 'hf mfu keygen --uid 11223344556677'" "80 B1 C2 71 D8 A0"; then break; fi
if ! CheckExecute "jooki encode test" "$CLIENTBIN -c 'hf jooki encode --test'" "04 28 F4 DA F0 4A 81 \( ok \)"; then break; fi