mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-04-28 04:05:10 +00:00
Merge pull request #3132 from kormax/google-smart-tap
Add `hf gst` commands
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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.
@@ -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... }"},
|
||||
|
||||
@@ -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
@@ -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
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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" },
|
||||
|
||||
@@ -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, ...) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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------------------------------------------------------------"
|
||||
|
||||
Reference in New Issue
Block a user