Merge pull request #3132 from kormax/google-smart-tap

Add `hf gst` commands
This commit is contained in:
Iceman
2026-03-15 14:06:17 +07:00
committed by GitHub
20 changed files with 3035 additions and 2 deletions
+2
View File
@@ -3,6 +3,8 @@ 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]
- Added `hf gst read` command (@kormax)
- Added `hf gst info` command (@kormax)
- Added `hf 14b tearoff` - interactive ST25TB/SRx monotonic counter tear-off attack (@xNovyz)
- Fixed missing `WDT_HIT()` in `Get14443bAnswerFromTag()` DMA polling loop causing hardware watchdog reboot on SSC clock stall (@xNovyz)
- Added `hf vas info` command (@kormax)
+15
View File
@@ -261,6 +261,8 @@ if (LZ4_INCLUDE_DIRS AND LZ4_LIBRARIES)
set(LZ4_FOUND ON)
endif (LZ4_INCLUDE_DIRS AND LZ4_LIBRARIES)
find_package(ZLIB QUIET)
if (NOT SKIPGD EQUAL 1)
if (EMBED_GD)
cmake_policy(SET CMP0114 NEW)
@@ -386,6 +388,7 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/cmdhffido.c
${PM3_ROOT}/client/src/cmdhffudan.c
${PM3_ROOT}/client/src/cmdhfgallagher.c
${PM3_ROOT}/client/src/cmdhfgst.c
${PM3_ROOT}/client/src/cmdhfcipurse.c
${PM3_ROOT}/client/src/cmdhficlass.c
${PM3_ROOT}/client/src/cmdhfict.c
@@ -584,6 +587,12 @@ if (LZ4_FOUND)
set(ADDITIONAL_LNK ${LZ4_LIBRARIES} ${ADDITIONAL_LNK})
endif (LZ4_FOUND)
if (ZLIB_FOUND)
add_definitions("-DHAVE_ZLIB")
set(ADDITIONAL_DIRS ${ZLIB_INCLUDE_DIRS} ${ADDITIONAL_DIRS})
set(ADDITIONAL_LNK ${ZLIB_LIBRARIES} ${ADDITIONAL_LNK})
endif (ZLIB_FOUND)
if (NOT SKIPGD EQUAL 1 AND GD_FOUND)
set(ADDITIONAL_DIRS ${GD_INCLUDE_DIRS} ${ADDITIONAL_DIRS})
set(ADDITIONAL_LNK ${GD_LIBRARIES} ${ADDITIONAL_LNK})
@@ -651,6 +660,12 @@ else (LZ4_FOUND)
message(SEND_ERROR "LZ4 library: LZ4 not found")
endif (LZ4_FOUND)
if (ZLIB_FOUND)
message(STATUS "Zlib library: system library found (enabled)")
else (ZLIB_FOUND)
message(STATUS "Zlib library: not found, disabled")
endif (ZLIB_FOUND)
if (SKIPGD EQUAL 1)
message(STATUS "GD library: skipped")
elseif (GD_FOUND)
+20
View File
@@ -272,6 +272,15 @@ LDLIBS += -lbz2
## LZ4
LDLIBS += -llz4
## ZLIB
ZLIBINCLUDES = $(shell $(PKG_CONFIG_ENV) pkg-config --cflags zlib 2>/dev/null)
ZLIBLDLIBS = $(shell $(PKG_CONFIG_ENV) pkg-config --libs zlib 2>/dev/null)
ifneq ($(ZLIBLDLIBS),)
LDLIBS += $(ZLIBLDLIBS)
PM3INCLUDES += $(ZLIBINCLUDES)
ZLIB_FOUND = 1
endif
## Bluez (optional)
ifneq ($(SKIPBT),1)
BTINCLUDES = $(shell $(PKG_CONFIG_ENV) pkg-config --cflags bluez 2>/dev/null)
@@ -485,6 +494,10 @@ ifeq ($(GD_FOUND),1)
PM3CFLAGS += -DHAVE_GD
endif
ifeq ($(ZLIB_FOUND),1)
PM3CFLAGS += -DHAVE_ZLIB
endif
ifeq ($(SWIG_LUA_FOUND),1)
PM3CFLAGS += -DHAVE_LUA_SWIG
endif
@@ -597,6 +610,12 @@ else
endif
endif
ifeq ($(ZLIB_FOUND),1)
$(info Zlib library: system library found, enabled)
else
$(info Zlib library: not found, disabled)
endif
ifeq ($(SKIPREADLINE),1)
$(info Readline library: skipped)
else
@@ -674,6 +693,7 @@ SRCS = mifare/aiddesfire.c \
cmdhffido.c \
cmdhffudan.c \
cmdhfgallagher.c \
cmdhfgst.c \
cmdhfksx6924.c \
cmdhfcipurse.c \
cmdhficlass.c \
+15
View File
@@ -181,6 +181,8 @@ if (LZ4_INCLUDE_DIRS AND LZ4_LIBRARIES)
set(LZ4_FOUND ON)
endif (LZ4_INCLUDE_DIRS AND LZ4_LIBRARIES)
find_package(ZLIB QUIET)
if (NOT SKIPGD EQUAL 1)
if (EMBED_GD)
cmake_policy(SET CMP0114 NEW)
@@ -305,6 +307,7 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/cmdhffido.c
${PM3_ROOT}/client/src/cmdhffudan.c
${PM3_ROOT}/client/src/cmdhfgallagher.c
${PM3_ROOT}/client/src/cmdhfgst.c
${PM3_ROOT}/client/src/cmdhfcipurse.c
${PM3_ROOT}/client/src/cmdhficlass.c
${PM3_ROOT}/client/src/cmdhfict.c
@@ -479,6 +482,12 @@ if (LZ4_FOUND)
set(ADDITIONAL_LNK ${LZ4_LIBRARIES} ${ADDITIONAL_LNK})
endif (LZ4_FOUND)
if (ZLIB_FOUND)
add_definitions("-DHAVE_ZLIB")
set(ADDITIONAL_DIRS ${ZLIB_INCLUDE_DIRS} ${ADDITIONAL_DIRS})
set(ADDITIONAL_LNK ${ZLIB_LIBRARIES} ${ADDITIONAL_LNK})
endif (ZLIB_FOUND)
if (NOT SKIPGD EQUAL 1 AND GD_FOUND)
set(ADDITIONAL_DIRS ${GD_INCLUDE_DIRS} ${ADDITIONAL_DIRS})
set(ADDITIONAL_LNK ${GD_LIBRARIES} ${ADDITIONAL_LNK})
@@ -533,6 +542,12 @@ else (LZ4_FOUND)
message(SEND_ERROR "LZ4 library: LZ4 not found")
endif (LZ4_FOUND)
if (ZLIB_FOUND)
message(STATUS "Zlib library: system library found (enabled)")
else (ZLIB_FOUND)
message(STATUS "Zlib library: not found, disabled")
endif (ZLIB_FOUND)
if (SKIPGD EQUAL 1)
message(STATUS "GD library: skipped")
elseif (GD_FOUND)
Binary file not shown.
Binary file not shown.
+2
View File
@@ -34,6 +34,7 @@
#include "cmdhffido.h" // FIDO authenticators
#include "cmdhffudan.h" // Fudan cards
#include "cmdhfgallagher.h" // Gallagher DESFire cards
#include "cmdhfgst.h" // Google Smart Tap
#include "cmdhficlass.h" // ICLASS
#include "cmdhfict.h" // ICT MFC / DESfire cards
#include "cmdhfjooki.h" // MFU based Jooki
@@ -586,6 +587,7 @@ static command_t CommandTable[] = {
{"fido", CmdHFFido, AlwaysAvailable, "{ FIDO and FIDO2 authenticators... }"},
{"fudan", CmdHFFudan, AlwaysAvailable, "{ Fudan RFIDs... }"},
{"gallagher", CmdHFGallagher, AlwaysAvailable, "{ Gallagher DESFire RFIDs... }"},
{"gst", CmdHFGST, AlwaysAvailable, "{ Google Smart Tap passes... }"},
{"iclass", CmdHFiClass, AlwaysAvailable, "{ ICLASS RFIDs... }"},
{"ict", CmdHFICT, AlwaysAvailable, "{ ICT MFC/DESfire RFIDs... }"},
{"jooki", CmdHF_Jooki, AlwaysAvailable, "{ Jooki RFIDs... }"},
+1
View File
@@ -243,6 +243,7 @@ static const hintAIDList_t hintAIDList[] = {
{ "\xA0\x00\x00\x09\x09\xAC\xCE\x55\x01", 9, "Aliro", "hf aliro" },
{ "\xd2\x76\x00\x00\x85\x01\x00", 7, "desfire", "hf mfdes" },
{ "\x4F\x53\x45\x2E\x56\x41\x53\x2E\x30\x31", 10, "OSE.VAS", "hf vas"},
{ "\xA0\x00\x00\x04\x76\xD0\x00\x01\x11", 9, "Google Smart Tap v2", "hf gst" },
};
// iso14a apdu input frame length
File diff suppressed because it is too large Load Diff
+26
View File
@@ -0,0 +1,26 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
// High frequency Google Smart Tap commands
//-----------------------------------------------------------------------------
#ifndef CMDHFGST_H__
#define CMDHFGST_H__
#include "common.h"
int CmdHFGST(const char *Cmd);
#endif
+376
View File
@@ -22,11 +22,13 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <mbedtls/asn1.h>
#include <mbedtls/des.h>
#include <mbedtls/aes.h>
#include <mbedtls/cmac.h>
#include <mbedtls/pk.h>
#include <mbedtls/base64.h>
#include <mbedtls/ecdsa.h>
#include <mbedtls/sha1.h>
#include <mbedtls/sha256.h>
@@ -38,8 +40,382 @@
#include "libpcrypto.h"
#include "util.h"
#include "ui.h"
#include "fileutils.h"
#include "math.h"
#define PCRYPTO_MAX_KEY_INPUT 8192
#define PCRYPTO_MAX_KEY_FILE_BYTES (64 * 1024)
int pcrypto_rng_init(pcrypto_rng_t *rng, const uint8_t *personalization, size_t personalization_len) {
if (rng == NULL || (personalization_len > 0 && personalization == NULL)) {
return PM3_EINVARG;
}
memset(rng, 0, sizeof(*rng));
mbedtls_entropy_init(&rng->entropy);
mbedtls_ctr_drbg_init(&rng->ctr_drbg);
int ret = mbedtls_ctr_drbg_seed(&rng->ctr_drbg, mbedtls_entropy_func, &rng->entropy,
personalization, personalization_len);
if (ret != 0) {
PrintAndLogEx(ERR, "Failed to initialize random generator (mbedtls: %d)", ret);
mbedtls_ctr_drbg_free(&rng->ctr_drbg);
mbedtls_entropy_free(&rng->entropy);
return PM3_ESOFT;
}
rng->seeded = true;
return PM3_SUCCESS;
}
void pcrypto_rng_free(pcrypto_rng_t *rng) {
if (rng == NULL) {
return;
}
mbedtls_ctr_drbg_free(&rng->ctr_drbg);
mbedtls_entropy_free(&rng->entropy);
rng->seeded = false;
}
int pcrypto_rng_fill(pcrypto_rng_t *rng, uint8_t *out, size_t out_len) {
if (rng == NULL || out == NULL || rng->seeded == false) {
return PM3_EINVARG;
}
if (out_len == 0) {
return PM3_SUCCESS;
}
return (mbedtls_ctr_drbg_random(&rng->ctr_drbg, out, out_len) == 0) ? PM3_SUCCESS : PM3_ESOFT;
}
static void pcrypto_trim_ascii_inplace(char *text) {
if (text == NULL) {
return;
}
size_t start = 0;
size_t len = strlen(text);
while (start < len && isspace((unsigned char)text[start])) {
start++;
}
while (len > start && isspace((unsigned char)text[len - 1])) {
len--;
}
if (start > 0) {
memmove(text, text + start, len - start);
}
text[len - start] = '\0';
}
static void pcrypto_unescape_newlines_inplace(char *text) {
if (text == NULL) {
return;
}
size_t read_pos = 0;
size_t write_pos = 0;
size_t len = strlen(text);
while (read_pos < len) {
if (text[read_pos] == '\\' && (read_pos + 1) < len) {
char esc = text[read_pos + 1];
if (esc == 'n') {
text[write_pos++] = '\n';
read_pos += 2;
continue;
}
if (esc == 'r') {
text[write_pos++] = '\r';
read_pos += 2;
continue;
}
if (esc == 't') {
text[write_pos++] = '\t';
read_pos += 2;
continue;
}
}
text[write_pos++] = text[read_pos++];
}
text[write_pos] = '\0';
}
static int pcrypto_copy_without_whitespace(const char *src, char *dst, size_t dst_size, size_t *dst_len) {
if (src == NULL || dst == NULL || dst_len == NULL || dst_size == 0) {
return PM3_EINVARG;
}
size_t out = 0;
for (size_t i = 0; src[i] != '\0'; i++) {
if (isspace((unsigned char)src[i])) {
continue;
}
if ((out + 1) >= dst_size) {
return PM3_EOVFLOW;
}
dst[out++] = src[i];
}
dst[out] = '\0';
*dst_len = out;
return PM3_SUCCESS;
}
static int pcrypto_extract_priv_scalar_from_pk(const mbedtls_pk_context *pkctx,
mbedtls_ecp_group_id curveid,
uint8_t *out_priv, size_t out_priv_len) {
if (pkctx == NULL || out_priv == NULL || out_priv_len == 0) {
return PM3_EINVARG;
}
mbedtls_pk_type_t pk_type = mbedtls_pk_get_type(pkctx);
if (!(pk_type == MBEDTLS_PK_ECKEY || pk_type == MBEDTLS_PK_ECKEY_DH)) {
return PM3_EINVARG;
}
mbedtls_ecp_keypair *ec = mbedtls_pk_ec(*pkctx);
if (ec == NULL || ec->grp.id != curveid) {
return PM3_EINVARG;
}
if (mbedtls_mpi_bitlen(&ec->d) > (out_priv_len * 8U)) {
return PM3_EINVARG;
}
if (mbedtls_ecp_check_privkey(&ec->grp, &ec->d) != 0) {
return PM3_EINVARG;
}
if (mbedtls_mpi_write_binary(&ec->d, out_priv, out_priv_len) != 0) {
return PM3_ESOFT;
}
return PM3_SUCCESS;
}
static int pcrypto_parse_ec_private_blob(const uint8_t *blob, size_t blob_len,
mbedtls_ecp_group_id curveid,
uint8_t *out_priv, size_t out_priv_len) {
if (blob == NULL || out_priv == NULL || blob_len == 0 || out_priv_len == 0) {
return PM3_EINVARG;
}
mbedtls_pk_context pkctx;
mbedtls_pk_init(&pkctx);
int ret = mbedtls_pk_parse_key(&pkctx, blob, blob_len, NULL, 0);
if (ret != 0) {
uint8_t *nul_terminated = calloc(blob_len + 1, sizeof(uint8_t));
if (nul_terminated == NULL) {
mbedtls_pk_free(&pkctx);
return PM3_EMALLOC;
}
memcpy(nul_terminated, blob, blob_len);
ret = mbedtls_pk_parse_key(&pkctx, nul_terminated, blob_len + 1, NULL, 0);
free(nul_terminated);
}
if (ret != 0) {
mbedtls_pk_free(&pkctx);
return PM3_EINVARG;
}
int res = pcrypto_extract_priv_scalar_from_pk(&pkctx, curveid, out_priv, out_priv_len);
mbedtls_pk_free(&pkctx);
return res;
}
static int pcrypto_parse_ec_private_base64(const char *input,
mbedtls_ecp_group_id curveid,
uint8_t *out_priv, size_t out_priv_len) {
if (input == NULL || out_priv == NULL || out_priv_len == 0) {
return PM3_EINVARG;
}
char compact[PCRYPTO_MAX_KEY_INPUT] = {0};
size_t compact_len = 0;
int res = pcrypto_copy_without_whitespace(input, compact, sizeof(compact), &compact_len);
if (res != PM3_SUCCESS || compact_len == 0) {
return PM3_EINVARG;
}
size_t decoded_capacity = ((compact_len * 3) / 4) + 4;
uint8_t *decoded = calloc(decoded_capacity, sizeof(uint8_t));
if (decoded == NULL) {
return PM3_EMALLOC;
}
size_t decoded_len = 0;
int b64_res = mbedtls_base64_decode(decoded, decoded_capacity, &decoded_len,
(const unsigned char *)compact, compact_len);
if (b64_res != 0 || decoded_len == 0) {
free(decoded);
return PM3_EINVARG;
}
res = pcrypto_parse_ec_private_blob(decoded, decoded_len, curveid, out_priv, out_priv_len);
free(decoded);
return res;
}
static int pcrypto_validate_raw_scalar(const uint8_t *scalar, size_t scalar_len, mbedtls_ecp_group_id curveid) {
if (scalar == NULL || scalar_len == 0) {
return PM3_EINVARG;
}
mbedtls_ecp_group grp;
mbedtls_mpi d;
mbedtls_ecp_group_init(&grp);
mbedtls_mpi_init(&d);
int status = PM3_ESOFT;
if (mbedtls_ecp_group_load(&grp, curveid) != 0) {
goto out;
}
if (mbedtls_mpi_read_binary(&d, scalar, scalar_len) != 0) {
status = PM3_EINVARG;
goto out;
}
if (mbedtls_ecp_check_privkey(&grp, &d) != 0) {
status = PM3_EINVARG;
goto out;
}
status = PM3_SUCCESS;
out:
mbedtls_mpi_free(&d);
mbedtls_ecp_group_free(&grp);
return status;
}
static int pcrypto_parse_ec_private_text(const char *input, bool allow_file_path,
mbedtls_ecp_group_id curveid,
uint8_t *out_priv, size_t out_priv_len);
static int pcrypto_parse_ec_private_file(const char *path,
mbedtls_ecp_group_id curveid,
uint8_t *out_priv, size_t out_priv_len) {
if (path == NULL || out_priv == NULL || out_priv_len == 0) {
return PM3_EINVARG;
}
FILE *f = fopen(path, "rb");
if (f == NULL) {
return PM3_EFILE;
}
if (fseek(f, 0, SEEK_END) != 0) {
fclose(f);
return PM3_EFILE;
}
long file_len_l = ftell(f);
if (file_len_l < 0) {
fclose(f);
return PM3_EFILE;
}
if ((size_t)file_len_l > PCRYPTO_MAX_KEY_FILE_BYTES) {
fclose(f);
return PM3_EOVFLOW;
}
if (fseek(f, 0, SEEK_SET) != 0) {
fclose(f);
return PM3_EFILE;
}
size_t file_len = (size_t)file_len_l;
uint8_t *data = calloc(file_len + 1, sizeof(uint8_t));
if (data == NULL) {
fclose(f);
return PM3_EMALLOC;
}
size_t read_len = fread(data, 1, file_len, f);
fclose(f);
if (read_len != file_len) {
free(data);
return PM3_EFILE;
}
int res = pcrypto_parse_ec_private_blob(data, file_len, curveid, out_priv, out_priv_len);
if (res == PM3_SUCCESS) {
free(data);
return PM3_SUCCESS;
}
char *text = calloc(file_len + 1, sizeof(char));
if (text == NULL) {
free(data);
return PM3_EMALLOC;
}
memcpy(text, data, file_len);
text[file_len] = '\0';
free(data);
res = pcrypto_parse_ec_private_text(text, false, curveid, out_priv, out_priv_len);
free(text);
return res;
}
static int pcrypto_parse_ec_private_text(const char *input, bool allow_file_path,
mbedtls_ecp_group_id curveid,
uint8_t *out_priv, size_t out_priv_len) {
if (input == NULL || out_priv == NULL || out_priv_len == 0) {
return PM3_EINVARG;
}
char normalized[PCRYPTO_MAX_KEY_INPUT] = {0};
size_t input_len = strlen(input);
if (input_len >= sizeof(normalized)) {
return PM3_EOVFLOW;
}
memcpy(normalized, input, input_len + 1);
pcrypto_trim_ascii_inplace(normalized);
if (normalized[0] == '\0') {
return PM3_EINVARG;
}
if (allow_file_path) {
char *resolved_path = NULL;
if (searchFile(&resolved_path, RESOURCES_SUBDIR, normalized, "", true) == PM3_SUCCESS) {
int res = pcrypto_parse_ec_private_file(resolved_path, curveid, out_priv, out_priv_len);
free(resolved_path);
return res;
}
}
// Only unescape after path resolution fails, to avoid mutating valid paths
// (for example Windows paths containing '\t', '\n' or '\r').
pcrypto_unescape_newlines_inplace(normalized);
uint8_t decoded[PCRYPTO_MAX_KEY_INPUT] = {0};
int decoded_len = -1;
char compact[PCRYPTO_MAX_KEY_INPUT] = {0};
size_t compact_len = 0;
if (pcrypto_copy_without_whitespace(normalized, compact, sizeof(compact), &compact_len) == PM3_SUCCESS &&
compact_len > 0) {
decoded_len = hex_to_bytes(compact, decoded, sizeof(decoded));
}
if (decoded_len > 0) {
if ((size_t)decoded_len == out_priv_len &&
pcrypto_validate_raw_scalar(decoded, out_priv_len, curveid) == PM3_SUCCESS) {
memcpy(out_priv, decoded, out_priv_len);
return PM3_SUCCESS;
}
int res = pcrypto_parse_ec_private_blob(decoded, (size_t)decoded_len, curveid, out_priv, out_priv_len);
if (res == PM3_SUCCESS) {
return PM3_SUCCESS;
}
}
int res = pcrypto_parse_ec_private_blob((const uint8_t *)normalized, strlen(normalized),
curveid, out_priv, out_priv_len);
if (res == PM3_SUCCESS) {
return PM3_SUCCESS;
}
return pcrypto_parse_ec_private_base64(normalized, curveid, out_priv, out_priv_len);
}
int ensure_ec_private_key(const char *input_or_path, mbedtls_ecp_group_id curveid, uint8_t *out_priv, size_t out_priv_len) {
return pcrypto_parse_ec_private_text(input_or_path, true, curveid, out_priv, out_priv_len);
}
void des_encrypt(void *out, const void *in, const void *key) {
mbedtls_des_context ctx;
mbedtls_des_setkey_enc(&ctx, key);
+13
View File
@@ -22,11 +22,23 @@
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
#include <mbedtls/pk.h>
#define CRYPTO_AES_BLOCK_SIZE 16
#define CRYPTO_AES128_KEY_SIZE 16
typedef struct {
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
bool seeded;
} pcrypto_rng_t;
int pcrypto_rng_init(pcrypto_rng_t *rng, const uint8_t *personalization, size_t personalization_len);
void pcrypto_rng_free(pcrypto_rng_t *rng);
int pcrypto_rng_fill(pcrypto_rng_t *rng, uint8_t *out, size_t out_len);
void des_encrypt(void *out, const void *in, const void *key);
void des_decrypt(void *out, const void *in, const void *key);
void des_encrypt_ecb(void *out, const void *in, const int length, const void *key);
@@ -54,6 +66,7 @@ int ecdsa_public_key_from_pk(mbedtls_pk_context *pk, mbedtls_ecp_group_id curvei
int ecdsa_signature_create(mbedtls_ecp_group_id curveid, uint8_t *key_d, uint8_t *key_xy, uint8_t *input, int length, uint8_t *signature, size_t *signaturelen, bool hash);
int ecdsa_signature_verify(mbedtls_ecp_group_id curveid, uint8_t *key_xy, uint8_t *input, int length, uint8_t *signature, size_t signaturelen, bool hash);
int ecdsa_signature_r_s_verify(mbedtls_ecp_group_id curveid, uint8_t *key_xy, uint8_t *input, int length, uint8_t *r_s, size_t r_s_len, bool hash);
int ensure_ec_private_key(const char *input_or_path, mbedtls_ecp_group_id curveid, uint8_t *out_priv, size_t out_priv_len);
char *ecdsa_get_error(int ret);
+5
View File
@@ -282,6 +282,11 @@ const static vocabulary_t vocabulary[] = {
{ 1, "hf gallagher diversifykey" },
{ 1, "hf gallagher decode" },
{ 1, "hf gallagher encode" },
{ 1, "hf gst help" },
{ 1, "hf gst list" },
{ 1, "hf gst test" },
{ 0, "hf gst info" },
{ 0, "hf gst read" },
{ 1, "hf iclass help" },
{ 1, "hf iclass list" },
{ 0, "hf iclass dump" },
+36
View File
@@ -232,6 +232,42 @@ void PrintAndLogOptions(const char *str[][2], size_t size, size_t space) {
PrintAndLogEx(NORMAL, "%s", buff);
}
void PrintAndLogInfoHeaderWithWidth(const char *title, size_t width) {
if (title == NULL) {
return;
}
const size_t title_len = strlen(title);
if (width > (MAX_PRINT_BUFFER - 1)) {
width = MAX_PRINT_BUFFER - 1;
}
char dashes[MAX_PRINT_BUFFER] = {0};
memset(dashes, '-', sizeof(dashes) - 1);
if (title_len + 2 >= width) {
PrintAndLogEx(INFO, _CYAN_("%s"), title);
return;
}
size_t dash_count = width - (title_len + 2);
size_t left = dash_count / 2;
size_t right = dash_count - left;
if (left > (sizeof(dashes) - 1)) {
left = sizeof(dashes) - 1;
}
if (right > (sizeof(dashes) - 1)) {
right = sizeof(dashes) - 1;
}
PrintAndLogEx(INFO, "%.*s " _CYAN_("%s") " %.*s",
(int)left, dashes, title, (int)right, dashes);
}
void PrintAndLogInfoHeader(const char *title) {
PrintAndLogInfoHeaderWithWidth(title, 82);
}
static uint8_t PrintAndLogEx_spinidx = 0;
void PrintAndLogEx(logLevel_t level, const char *fmt, ...) {
+2
View File
@@ -78,6 +78,8 @@ extern session_arg_t g_session;
#define PROMPT_CLEARLINE PrintAndLogEx(INPLACE, " \r")
void PrintAndLogOptions(const char *str[][2], size_t size, size_t space);
void PrintAndLogEx(logLevel_t level, const char *fmt, ...);
void PrintAndLogInfoHeaderWithWidth(const char *title, size_t width);
void PrintAndLogInfoHeader(const char *title);
void SetFlushAfterWrite(bool value);
bool GetFlushAfterWrite(void);
void memcpy_filter_ansi(void *dest, const void *src, size_t n, bool filter);
+60
View File
@@ -27,6 +27,7 @@
#include <inttypes.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h> // Mingw
@@ -672,6 +673,52 @@ int hex_to_bytes(const char *hexValue, uint8_t *bytesValue, size_t maxBytesValue
return bytesValueLen;
}
int parse_uint32_hex_or_dec(const char *text, uint32_t *out) {
if (text == NULL || out == NULL || text[0] == '\0') {
return PM3_EINVARG;
}
int base = 10;
if (text[0] == '0' && (text[1] == 'x' || text[1] == 'X')) {
base = 16;
} else {
for (const char *p = text; *p; p++) {
if (isalpha((unsigned char)*p)) {
base = 16;
break;
}
}
}
errno = 0;
char *end = NULL;
unsigned long value = strtoul(text, &end, base);
if (errno == ERANGE || end == text || end == NULL || *end != '\0' || value > UINT32_MAX) {
return PM3_EINVARG;
}
*out = (uint32_t)value;
return PM3_SUCCESS;
}
bool bytes_equal_not_null(const void *a, size_t a_len, const void *b, size_t b_len) {
return a_len == b_len && a != NULL && b != NULL && memcmp(a, b, a_len) == 0;
}
int buffer_append_bytes_with_offset(uint8_t *buf, size_t buf_len, size_t *offset, const void *data, size_t data_len) {
if (buf == NULL || offset == NULL || (data_len > 0 && data == NULL)) {
return PM3_EINVARG;
}
if (*offset > buf_len || data_len > (buf_len - *offset)) {
return PM3_EOVFLOW;
}
if (data_len > 0) {
memcpy(buf + *offset, data, data_len);
*offset += data_len;
}
return PM3_SUCCESS;
}
// takes a number (uint64_t) and creates a binarray in dest.
void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest) {
while (len--) {
@@ -1368,6 +1415,19 @@ void clean_ascii(unsigned char *buf, size_t len) {
}
}
bool is_printable_ascii(const uint8_t *data, size_t data_len) {
if (data == NULL || data_len == 0) {
return false;
}
for (size_t i = 0; i < data_len; i++) {
if (data[i] < 0x20 || data[i] > 0x7E) {
return false;
}
}
return true;
}
bool decode_zero_padded_ascii(const uint8_t *data, size_t data_len, char *out, size_t out_len) {
if (data == NULL || out == NULL || out_len == 0) {
return false;
+4
View File
@@ -103,6 +103,9 @@ void print_buffer(const uint8_t *data, const size_t len, int level);
void print_blocks(uint32_t *data, size_t len);
int hex_to_bytes(const char *hexValue, uint8_t *bytesValue, size_t maxBytesValueLen);
int parse_uint32_hex_or_dec(const char *text, uint32_t *out);
bool bytes_equal_not_null(const void *a, size_t a_len, const void *b, size_t b_len);
int buffer_append_bytes_with_offset(uint8_t *buf, size_t buf_len, size_t *offset, const void *data, size_t data_len);
void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest);
void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest);
void bytes_to_bytebits(const void *src, const size_t srclen, void *dest);
@@ -166,6 +169,7 @@ void strn_upper(char *s, size_t n);
bool str_startswith(const char *s, const char *pre); // check for prefix in string
bool str_endswith(const char *s, const char *suffix); // check for suffix in string
void clean_ascii(unsigned char *buf, size_t len);
bool is_printable_ascii(const uint8_t *data, size_t data_len);
bool decode_zero_padded_ascii(const uint8_t *data, size_t data_len, char *out, size_t out_len);
void str_cleanrn(char *buf, size_t len);
void str_creplace(char *buf, size_t len, char from, char to);
@@ -60,7 +60,7 @@ Install the requirements
```sh
sudo apt-get install --no-install-recommends git ca-certificates build-essential pkg-config \
libreadline-dev gcc-arm-none-eabi libnewlib-dev qt6-base-dev \
libbz2-dev liblz4-dev libbluetooth-dev libpython3-dev libssl-dev libgd-dev
libbz2-dev liblz4-dev zlib1g-dev libbluetooth-dev libpython3-dev libssl-dev libgd-dev
```
### If you don't need...
@@ -73,6 +73,9 @@ you can skip the installation of `qt6-base-dev`.
👉 If you don't need support for Python3 scripts in the Proxmark3 client,
you can skip the installation of `libpython3-dev`.
👉 If you don't need support for decompressing compressed Google Smart Tap payloads in the Proxmark3 client,
you can skip the installation of `zlib1g-dev`.
👉 If you don't need support for NFC ePaper devices,
you can skip the installation of `libgd-dev`.
@@ -175,9 +175,13 @@ These instructions will show how to setup the environment on OSX to the point wh
2. Install dependencies:
```
brew install readline qt gd pkgconfig coreutils openssl
brew install readline qt gd pkgconfig coreutils openssl zlib
brew install RfidResearchGroup/proxmark3/arm-none-eabi-gcc
```
If you don't need support for decompressing compressed Google Smart Tap payloads in the Proxmark3 client,
you can skip the installation of `zlib`.
3. (optional) Install makefile dependencies:
```
brew install recode
+1
View File
@@ -626,6 +626,7 @@ while true; do
if ! CheckExecute "emv test" "$CLIENTBIN -c 'emv test'" "Tests \( ok"; then break; fi
if ! CheckExecute "hf cipurse test" "$CLIENTBIN -c 'hf cipurse test'" "Tests \( ok"; then break; fi
if ! CheckExecute "hf mfdes test" "$CLIENTBIN -c 'hf mfdes test'" "Tests \( ok"; then break; fi
if ! CheckExecute "hf gst test" "$CLIENTBIN -c 'hf gst test'" "Tests \( ok"; then break; fi
if ! CheckExecute "hf waveshare load" "$CLIENTBIN -c 'hf waveshare load -m 6 -f tools/lena.bmp -s dither.bmp' && echo '34ff55fe7257876acf30dae00eb0e439 dither.bmp' | md5sum -c -" "dither.bmp: OK"; then break; fi
fi
echo -e "\n------------------------------------------------------------"