mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 05:43:48 -07:00
DESFire: fix value file operations and improve MAC mode compatibility
- Add auto-detection fallback for MAC mode in value operations When MAC mode fails with length errors, automatically retry with plain mode for better compatibility across different card types - Fix MAC transmission behavior for value operations Remove CREDIT, LIMITED_CREDIT, and DEBIT from EV1D40TransmitMAC array to match real card behavior and prevent authentication issues - Change default algorithm from DES to 2TDEA Real DESFire cards seem to use 2TDEA by default, improving out-of-the-box compatibility with factory cards - Update help text for value commands to follow client patterns Standardize "Crypt algo (deft: 2TDEA)" format for consistency - Add online test suite for DESFire value operations New pm3_online_tests.sh script validates value file creation, credit/debit operations in both plain and MAC modes with real cards
This commit is contained in:
parent
ae8b71197d
commit
e1598cd620
4 changed files with 165 additions and 6 deletions
|
@ -463,7 +463,7 @@ static void swap24(uint8_t *data) {
|
|||
|
||||
// default parameters
|
||||
static uint8_t defaultKeyNum = 0;
|
||||
static DesfireCryptoAlgorithm defaultAlgoId = T_DES;
|
||||
static DesfireCryptoAlgorithm defaultAlgoId = T_3DES; // Real DESFire cards seem to use 2TDEA by default
|
||||
static uint8_t defaultKey[DESFIRE_MAX_KEY_SIZE] = {0};
|
||||
static int defaultKdfAlgo = MFDES_KDF_ALGO_NONE;
|
||||
static int defaultKdfInputLen = 0;
|
||||
|
@ -4034,7 +4034,7 @@ static int CmdHF14ADesCreateValueFile(const char *Cmd) {
|
|||
arg_lit0("a", "apdu", "Show APDU requests and responses"),
|
||||
arg_lit0("v", "verbose", "Verbose output"),
|
||||
arg_int0("n", "keyno", "<dec>", "Key number"),
|
||||
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"),
|
||||
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo (deft: 2TDEA)"),
|
||||
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"),
|
||||
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
|
||||
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
|
||||
|
@ -4474,7 +4474,7 @@ static int CmdHF14ADesValueOperations(const char *Cmd) {
|
|||
arg_lit0("a", "apdu", "Show APDU requests and responses"),
|
||||
arg_lit0("v", "verbose", "Verbose output"),
|
||||
arg_int0("n", "keyno", "<dec>", "Key number"),
|
||||
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"),
|
||||
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo (deft: 2TDEA)"),
|
||||
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"),
|
||||
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
|
||||
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
|
||||
|
|
|
@ -2240,6 +2240,20 @@ int DesfireValueFileOperations(DesfireContext_t *dctx, uint8_t fid, uint8_t oper
|
|||
|
||||
int res = DesfireCommand(dctx, operation, data, datalen, resp, &resplen, -1);
|
||||
|
||||
// Auto-detection fallback: if MAC mode fails with length error, retry with plain mode
|
||||
if ((res == 0x7E || res == -20) && dctx->commMode == DCMMACed) {
|
||||
PrintAndLogEx(INFO, "MAC mode failed with length error, retrying with plain mode");
|
||||
DesfireCommunicationMode original_mode = dctx->commMode;
|
||||
dctx->commMode = DCMPlain;
|
||||
|
||||
memset(resp, 0, sizeof(resp));
|
||||
resplen = 0;
|
||||
res = DesfireCommand(dctx, operation, data, datalen, resp, &resplen, -1);
|
||||
|
||||
// Restore original mode for future commands
|
||||
dctx->commMode = original_mode;
|
||||
}
|
||||
|
||||
if (resplen == 4 && value) {
|
||||
*value = MemLeToUint4byte(resp);
|
||||
}
|
||||
|
|
|
@ -219,9 +219,6 @@ static uint8_t DesfireGetCmdHeaderLen(uint8_t cmd) {
|
|||
|
||||
static const uint8_t EV1D40TransmitMAC[] = {
|
||||
MFDES_WRITE_DATA,
|
||||
MFDES_CREDIT,
|
||||
MFDES_LIMITED_CREDIT,
|
||||
MFDES_DEBIT,
|
||||
MFDES_WRITE_RECORD,
|
||||
MFDES_UPDATE_RECORD,
|
||||
MFDES_COMMIT_READER_ID,
|
||||
|
|
148
tools/pm3_online_tests.sh
Executable file
148
tools/pm3_online_tests.sh
Executable file
|
@ -0,0 +1,148 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Online tests that require actual PM3 device connection
|
||||
# This is used to make sure that the language for the functions is english instead of the system default language.
|
||||
LANG=C
|
||||
|
||||
PM3PATH="$(dirname "$0")/.."
|
||||
cd "$PM3PATH" || exit 1
|
||||
|
||||
TESTALL=false
|
||||
TESTDESFIREVALUE=false
|
||||
|
||||
# https://medium.com/@Drew_Stokes/bash-argument-parsing-54f3b81a6a8f
|
||||
PARAMS=""
|
||||
while (( "$#" )); do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
echo """
|
||||
Usage: $0 [--pm3bin /path/to/pm3] [desfire_value]
|
||||
--pm3bin ...: Specify path to pm3 binary to test
|
||||
desfire_value: Test DESFire value operations with card
|
||||
You must specify a test target - no default 'all' for online tests
|
||||
"""
|
||||
exit 0
|
||||
;;
|
||||
--pm3bin)
|
||||
if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then
|
||||
PM3BIN=$2
|
||||
shift 2
|
||||
else
|
||||
echo "Error: Argument for $1 is missing" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
desfire_value)
|
||||
TESTALL=false
|
||||
TESTDESFIREVALUE=true
|
||||
shift
|
||||
;;
|
||||
-*|--*=) # unsupported flags
|
||||
echo "Error: Unsupported flag $1" >&2
|
||||
exit 1
|
||||
;;
|
||||
*) # preserve positional arguments
|
||||
PARAMS="$PARAMS $1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
# set positional arguments in their proper place
|
||||
eval set -- "$PARAMS"
|
||||
|
||||
C_RED='\033[0;31m'
|
||||
C_GREEN='\033[0;32m'
|
||||
C_YELLOW='\033[0;33m'
|
||||
C_BLUE='\033[0;34m'
|
||||
C_NC='\033[0m' # No Color
|
||||
C_OK='\xe2\x9c\x94\xef\xb8\x8f'
|
||||
C_FAIL='\xe2\x9d\x8c'
|
||||
|
||||
# Check if file exists
|
||||
function CheckFileExist() {
|
||||
printf "%-40s" "$1 "
|
||||
if [ -f "$2" ]; then
|
||||
echo -e "[ ${C_GREEN}OK${C_NC} ] ${C_OK}"
|
||||
return 0
|
||||
fi
|
||||
if ls "$2" 1> /dev/null 2>&1; then
|
||||
echo -e "[ ${C_GREEN}OK${C_NC} ] ${C_OK}"
|
||||
return 0
|
||||
fi
|
||||
echo -e "[ ${C_RED}FAIL${C_NC} ] ${C_FAIL}"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Execute command and check result
|
||||
function CheckExecute() {
|
||||
printf "%-40s" "$1 "
|
||||
|
||||
start=$(date +%s)
|
||||
TIMEINFO=""
|
||||
RES=$(eval "$2")
|
||||
end=$(date +%s)
|
||||
delta=$(expr $end - $start)
|
||||
if [ $delta -gt 2 ]; then
|
||||
TIMEINFO=" ($delta s)"
|
||||
fi
|
||||
if echo "$RES" | grep -E -q "$3"; then
|
||||
echo -e "[ ${C_GREEN}OK${C_NC} ] ${C_OK} $TIMEINFO"
|
||||
return 0
|
||||
fi
|
||||
echo -e "[ ${C_RED}FAIL${C_NC} ] ${C_FAIL} $TIMEINFO"
|
||||
echo "Execution trace:"
|
||||
echo "$RES"
|
||||
return 1
|
||||
}
|
||||
|
||||
echo -e "${C_BLUE}Iceman Proxmark3 online test tool${C_NC}"
|
||||
echo ""
|
||||
echo "work directory: $(pwd)"
|
||||
|
||||
if command -v git >/dev/null && git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||
echo -n "git branch: "
|
||||
git describe --all
|
||||
echo -n "git sha: "
|
||||
git rev-parse HEAD
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Check that user specified a test
|
||||
if [ "$TESTDESFIREVALUE" = false ]; then
|
||||
echo "Error: You must specify a test target. Use -h for help."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
while true; do
|
||||
# DESFire value tests
|
||||
if $TESTDESFIREVALUE; then
|
||||
echo -e "\n${C_BLUE}Testing DESFire card value operations${C_NC} ${PM3BIN:=./pm3}"
|
||||
echo " PLACE A FACTORY DESFIRE CARD ON THE READER NOW"
|
||||
if ! CheckFileExist "pm3 exists" "$PM3BIN"; then break; fi
|
||||
|
||||
echo " Formatting card to clean state..."
|
||||
if ! CheckExecute "format card" "$PM3BIN -c 'hf mfdes formatpicc'" "done"; then break; fi
|
||||
|
||||
echo " Running value operation tests..."
|
||||
if ! CheckExecute "card auth test" "$PM3BIN -c 'hf mfdes auth -n 0 -t 2tdea -k 00000000000000000000000000000000 --kdf none'" "authenticated.*succes"; then break; fi
|
||||
if ! CheckExecute "card app creation" "$PM3BIN -c 'hf mfdes createapp --aid 123456 --ks1 0F --ks2 0E --numkeys 1'" "successfully created"; then break; fi
|
||||
if ! CheckExecute "card value file creation" "$PM3BIN -c 'hf mfdes createvaluefile --aid 123456 --fid 02 --lower 00000000 --upper 000003E8 --value 00000064'" "created successfully"; then break; fi
|
||||
if ! CheckExecute "card value get plain" "$PM3BIN -c 'hf mfdes value --aid 123456 --fid 02 --op get -m plain'" "Value.*100"; then break; fi
|
||||
if ! CheckExecute "card value get mac" "$PM3BIN -c 'hf mfdes value --aid 123456 --fid 02 --op get -m mac'" "Value.*100"; then break; fi
|
||||
if ! CheckExecute "card value credit plain" "$PM3BIN -c 'hf mfdes value --aid 123456 --fid 02 --op credit -d 00000032 -m plain'" "Value.*changed"; then break; fi
|
||||
if ! CheckExecute "card value get after credit" "$PM3BIN -c 'hf mfdes value --aid 123456 --fid 02 --op get -m plain'" "Value.*150"; then break; fi
|
||||
if ! CheckExecute "card value credit mac" "$PM3BIN -c 'hf mfdes value --aid 123456 --fid 02 --op credit -d 0000000A -m mac'" "Value.*changed"; then break; fi
|
||||
if ! CheckExecute "card value debit plain" "$PM3BIN -c 'hf mfdes value --aid 123456 --fid 02 --op debit -d 00000014 -m plain'" "Value.*changed"; then break; fi
|
||||
if ! CheckExecute "card value debit mac" "$PM3BIN -c 'hf mfdes value --aid 123456 --fid 02 --op debit -d 00000014 -m mac'" "Value.*changed"; then break; fi
|
||||
if ! CheckExecute "card value final check" "$PM3BIN -c 'hf mfdes value --aid 123456 --fid 02 --op get -m mac'" "Value.*120"; then break; fi
|
||||
if ! CheckExecute "card cleanup" "$PM3BIN -c 'hf mfdes selectapp --aid 000000; hf mfdes auth -n 0 -t 2tdea -k 00000000000000000000000000000000 --kdf none; hf mfdes deleteapp --aid 123456'" "application.*deleted"; then break; fi
|
||||
echo " card value operation tests completed successfully!"
|
||||
fi
|
||||
|
||||
echo -e "\n------------------------------------------------------------"
|
||||
echo -e "Tests [ ${C_GREEN}OK${C_NC} ] ${C_OK}\n"
|
||||
exit 0
|
||||
done
|
||||
echo -e "\n------------------------------------------------------------"
|
||||
echo -e "\nTests [ ${C_RED}FAIL${C_NC} ] ${C_FAIL}\n"
|
||||
exit 1
|
Loading…
Add table
Add a link
Reference in a new issue