1
0
mirror of https://github.com/Proxmark/proxmark3.git synced 2025-03-12 04:35:36 -07:00

Deduplicate mfkey32 and mfkey64

- rename client/nonce2key.[ch] to mfkey.[ch]
- leave only main() wrapper in tools/mfkey
- add mfkey32 and mfkey64 to .gitignore
This commit is contained in:
pwpiwi 2017-03-23 18:06:14 +01:00
parent bd2797de15
commit 4cb4b588c2
11 changed files with 193 additions and 170 deletions

8
.gitignore vendored

@ -14,14 +14,16 @@
*.dll
*.moc.cpp
*.z
version.c
*.exe
proxmark
proxmark3
flasher
version.c
lua
luac
fpga_compress
mfkey32
mfkey64
fpga/*
!fpga/tests
@ -34,5 +36,3 @@ fpga/*
!fpga/xst_hf.scr
!fpga/go.bat
!fpga/sim.tcl

@ -58,7 +58,7 @@ CORESRCS = uart.c \
CMDSRCS = crapto1/crapto1.c\
crapto1/crypto1.c\
nonce2key.c\
mfkey.c\
loclass/cipher.c \
loclass/cipherutils.c \
loclass/des.c \

@ -19,7 +19,7 @@
#include "ui.h"
#include "mifarehost.h"
#include "mifare.h"
#include "nonce2key.h"
#include "mfkey.h"
#define NESTED_SECTOR_RETRY 10 // how often we try mfested() until we give up

@ -10,15 +10,11 @@
// MIFARE Darkside hack
//-----------------------------------------------------------------------------
#include "nonce2key.h"
#include "mfkey.h"
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include "mifarehost.h"
#include "util.h"
#include "crapto1/crapto1.h"
// recover key from 2 different reader responses on same tag challenge
bool mfkey32(nonces_t data, uint64_t *outputkey) {
struct Crypto1State *s,*t;
@ -27,8 +23,6 @@ bool mfkey32(nonces_t data, uint64_t *outputkey) {
bool isSuccess = false;
uint8_t counter = 0;
uint64_t t1 = msclock();
s = lfsr_recovery32(data.ar ^ prng_successor(data.nonce, 64), 0);
for(t = s; t->odd | t->even; ++t) {
@ -46,8 +40,6 @@ bool mfkey32(nonces_t data, uint64_t *outputkey) {
}
}
isSuccess = (counter == 1);
t1 = msclock() - t1;
//if ( t1 > 0 ) PrintAndLog("Time in mfkey32: %.1f seconds \nFound %d possible keys", (float)t1/1000.0, counter);
*outputkey = ( isSuccess ) ? outkey : 0;
crypto1_destroy(s);
/* //un-comment to save all keys to a stats.txt file
@ -70,9 +62,6 @@ bool mfkey32_moebius(nonces_t data, uint64_t *outputkey) {
bool isSuccess = false;
int counter = 0;
//PrintAndLog("Enter mfkey32_moebius");
uint64_t t1 = msclock();
s = lfsr_recovery32(data.ar ^ prng_successor(data.nonce, 64), 0);
for(t = s; t->odd | t->even; ++t) {
@ -92,8 +81,6 @@ bool mfkey32_moebius(nonces_t data, uint64_t *outputkey) {
}
}
isSuccess = (counter == 1);
t1 = msclock() - t1;
// PrintAndLog("Time in mfkey32_moebius: %.1f seconds \nFound %d possible keys", (float)t1/1000.0, counter);
*outputkey = ( isSuccess ) ? outkey : 0;
crypto1_destroy(s);
/* // un-comment to output all keys to stats.txt
@ -115,9 +102,6 @@ int mfkey64(nonces_t data, uint64_t *outputkey){
uint32_t ks3; // keystream used to encrypt tag response
struct Crypto1State *revstate;
// PrintAndLog("Enter mfkey64");
uint64_t t1 = msclock();
// Extract the keystream from the messages
ks2 = data.ar ^ prng_successor(data.nonce, 64);
ks3 = data.at ^ prng_successor(data.nonce, 96);
@ -131,7 +115,7 @@ int mfkey64(nonces_t data, uint64_t *outputkey){
crypto1_destroy(revstate);
*outputkey = key;
t1 = msclock() - t1;
// PrintAndLog("Time in mfkey64: %.1f seconds \n", (float)t1/1000.0);
return 0;
}

@ -10,8 +10,8 @@
// MIFARE Darkside hack
//-----------------------------------------------------------------------------
#ifndef __NONCE2KEY_H
#define __NONCE2KEY_H
#ifndef MFKEY_H
#define MFKEY_H
#include <stdint.h>
#include <stdbool.h>
@ -29,8 +29,8 @@ typedef struct {
uint32_t nr2;
} nonces_t;
bool mfkey32(nonces_t data, uint64_t *outputkey);
bool mfkey32_moebius(nonces_t data, uint64_t *outputkey);
int mfkey64(nonces_t data, uint64_t *outputkey);
extern bool mfkey32(nonces_t data, uint64_t *outputkey);
extern bool mfkey32_moebius(nonces_t data, uint64_t *outputkey);
extern int mfkey64(nonces_t data, uint64_t *outputkey);
#endif

@ -8,6 +8,8 @@
// mifare commands
//-----------------------------------------------------------------------------
#include "mifarehost.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -20,7 +22,6 @@
#include "ui.h"
#include "util.h"
#include "iso14443crc.h"
#include "mifarehost.h"
// mifare tracer flags used in mfTraceDecode()
#define TRACE_IDLE 0x00

@ -8,6 +8,9 @@
// High frequency ISO14443A commands
//-----------------------------------------------------------------------------
#ifndef MIFAREHOST_H
#define MIFAREHOST_H
#include <stdint.h>
#include <stdbool.h>
#include "data.h"
@ -42,3 +45,5 @@ extern int isBlockTrailer(int blockN);
extern int loadTraceCard(uint8_t *tuid);
extern int saveTraceCard(void);
extern int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len);
#endif

27
common/crapto1/readme Normal file

@ -0,0 +1,27 @@
CRAPTO1
-------
Provides a set of library functions which aid the verification
of crypto1 weaknesses.
In short a partial implementation of:
Dismantling MIFARE Classic
URL: http://www.sos.cs.ru.nl/applications/rfid/2008-esorics.pdf
Flavio D. Garcia, Gerhard de Koning Gans, Ruben Muijrers,
Peter van Rossum, Roel Verdult, Ronny Wichers Schreur, Bart Jacobs
Institute for Computing and Information Sciences,
Radboud University Nijmegen, The Netherlands
{{flaviog,petervr,ronny,bart}@cs, {gkoningg,rmuijrer,rverdult}@sci}.ru.nl
and
Wirelessly Pickpocketing a Mifare Classic Card
URL: http://www.cs.ru.nl/~flaviog/publications/Pickpocketing.Mifare.pdf
Flavio D. Garcia, Peter van Rossum, Roel Verdult, Ronny Wichers Schreur
Radboud University Nijmegen, The Netherlands
{flaviog,petervr,rverdult,ronny}@cs.ru.nl
and
THE DARK SIDE OF SECURITY BY OBSCURITY
URL: http://eprint.iacr.org/2009/137
and Cloning MiFare Classic Rail and Building Passes, Anywhere, Anytime
Nicolas T. Courtois
University College London, Computer Science,
Gower street, WC1E 6BT, London, UK

@ -1,10 +1,10 @@
VPATH = ../../common/crapto1
VPATH = ../../common/crapto1 ../../client
CC = gcc
LD = gcc
CFLAGS = -I../../common -Wall -O4
CFLAGS = -I../../common -I../../client -Wall -O4
LDFLAGS =
OBJS = crypto1.o crapto1.o
OBJS = crypto1.o crapto1.o util.o mfkey.o
EXES = mfkey32 mfkey64
WINEXES = $(patsubst %, %.exe, $(EXES))
@ -13,7 +13,7 @@ all: $(OBJS) $(EXES)
%.o : %.c
$(CC) $(CFLAGS) -c -o $@ $<
% : %.c
% : %.c $(OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $<
clean:

@ -1,67 +1,77 @@
#include <inttypes.h>
#include "crapto1/crapto1.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include "crapto1/crapto1.h"
#include "mfkey.h"
#include "util.h"
// 32 bit recover key from 2 nonces
#include <stdio.h>
int main (int argc, char *argv[]) {
struct Crypto1State *s,*t;
uint64_t key; // recovered key
uint32_t uid; // serial number
uint32_t nt; // tag challenge
uint32_t nr0_enc; // first encrypted reader challenge
uint32_t ar0_enc; // first encrypted reader response
uint32_t nr1_enc; // second encrypted reader challenge
uint32_t ar1_enc; // second encrypted reader response
uint32_t ks2; // keystream used to encrypt reader response
printf("MIFARE Classic key recovery - based 32 bits of keystream\n");
nonces_t data;
uint32_t ks2; // keystream used to encrypt reader response
uint64_t key; // recovered key
printf("MIFARE Classic key recovery - based on 32 bits of keystream\n");
printf("Recover key from two 32-bit reader authentication answers only!\n\n");
if (argc < 7) {
printf(" syntax: %s <uid> <nt> <{nr_0}> <{ar_0}> <{nr_1}> <{ar_1}>\n\n",argv[0]);
if (argc != 7 && argc != 8) {
printf(" syntax: %s <uid> <nt0> <{nr_0}> <{ar_0}> [<nt1>] <{nr_1}> <{ar_1}>\n", argv[0]);
printf(" (you may omit nt1 if it is equal to nt0)\n\n");
return 1;
}
sscanf(argv[1],"%x",&uid);
sscanf(argv[2],"%x",&nt);
sscanf(argv[3],"%x",&nr0_enc);
sscanf(argv[4],"%x",&ar0_enc);
sscanf(argv[5],"%x",&nr1_enc);
sscanf(argv[6],"%x",&ar1_enc);
bool moebius_attack = (argc == 8);
sscanf(argv[1],"%x",&data.cuid);
sscanf(argv[2],"%x",&data.nonce);
data.nonce2 = data.nonce;
sscanf(argv[3],"%x",&data.nr);
sscanf(argv[4],"%x",&data.ar);
if (moebius_attack) {
sscanf(argv[5],"%x",&data.nonce2);
sscanf(argv[6],"%x",&data.nr2);
sscanf(argv[7],"%x",&data.ar2);
} else {
sscanf(argv[5],"%x",&data.nr2);
sscanf(argv[6],"%x",&data.ar2);
}
printf("Recovering key for:\n");
printf(" uid: %08x\n",uid);
printf(" nt: %08x\n",nt);
printf(" {nr_0}: %08x\n",nr0_enc);
printf(" {ar_0}: %08x\n",ar0_enc);
printf(" {nr_1}: %08x\n",nr1_enc);
printf(" {ar_1}: %08x\n",ar1_enc);
printf(" uid: %08x\n",data.cuid);
printf(" nt0: %08x\n",data.nonce);
printf(" {nr_0}: %08x\n",data.nr);
printf(" {ar_0}: %08x\n",data.ar);
printf(" nt1: %08x\n",data.nonce2);
printf(" {nr_1}: %08x\n",data.nr2);
printf(" {ar_1}: %08x\n",data.ar2);
uint64_t start_time = msclock();
// Generate lfsr succesors of the tag challenge
printf("\nLFSR succesors of the tag challenge:\n");
printf(" nt': %08x\n",prng_successor(nt, 64));
printf(" nt'': %08x\n",prng_successor(nt, 96));
printf(" nt': %08x\n",prng_successor(data.nonce, 64));
printf(" nt'': %08x\n",prng_successor(data.nonce, 96));
// Extract the keystream from the messages
printf("\nKeystream used to generate {ar} and {at}:\n");
ks2 = ar0_enc ^ prng_successor(nt, 64);
ks2 = data.ar ^ prng_successor(data.nonce, 64);
printf(" ks2: %08x\n",ks2);
s = lfsr_recovery32(ar0_enc ^ prng_successor(nt, 64), 0);
for(t = s; t->odd | t->even; ++t) {
lfsr_rollback_word(t, 0, 0);
lfsr_rollback_word(t, nr0_enc, 1);
lfsr_rollback_word(t, uid ^ nt, 0);
crypto1_get_lfsr(t, &key);
crypto1_word(t, uid ^ nt, 0);
crypto1_word(t, nr1_enc, 1);
if (ar1_enc == (crypto1_word(t, 0, 0) ^ prng_successor(nt, 64))) {
printf("\nFound Key: [%012" PRIx64 "]\n\n",key);
break;
}
bool success;
if (moebius_attack) {
success = mfkey32_moebius(data, &key);
} else {
success = mfkey32(data, &key);
}
if (success) {
printf("Recovered key: %012" PRIx64 "\n", key);
} else {
printf("Couldn't recover key.\n");
}
free(s);
return 0;
printf("Time spent: %1.2f seconds\n", (float)(msclock() - start_time)/1000.0);
}

@ -1,105 +1,101 @@
#include <stdio.h>
#include <strings.h>
#include <inttypes.h>
#include "crapto1/crapto1.h"
#include <stdio.h>
#include <string.h>
#include "util.h"
int main (int argc, char *argv[]) {
struct Crypto1State *revstate;
uint64_t key; // recovered key
uint32_t uid; // serial number
uint32_t nt; // tag challenge
uint32_t nr_enc; // encrypted reader challenge
uint32_t ar_enc; // encrypted reader response
uint32_t at_enc; // encrypted tag response
uint32_t ks2; // keystream used to encrypt reader response
uint32_t ks3; // keystream used to encrypt tag response
int main (int argc, char *argv[])
{
uint32_t uid; // serial numDber
uint32_t nt; // tag challenge
uint32_t nr_enc; // encrypted reader challenge
uint32_t ar_enc; // encrypted reader response
uint32_t at_enc; // encrypted tag response
uint64_t key = 0; // recovered key
struct Crypto1State *revstate;
uint32_t ks2; // keystream used to encrypt reader response
uint32_t ks3; // keystream used to encrypt tag response
printf("MIFARE Classic key recovery - based 64 bits of keystream\n");
printf("Recover key from only one complete authentication!\n\n");
printf("MIFARE Classic key recovery - based on 64 bits of keystream\n");
printf("Recover key from only one complete authentication!\n\n");
if (argc < 6 ) {
printf(" syntax: %s <uid> <nt> <{nr}> <{ar}> <{at}> [enc] [enc...]\n\n", argv[0]);
return 1;
}
if (argc < 6 ) {
printf(" syntax: %s <uid> <nt> <{nr}> <{ar}> <{at}> [enc] [enc...]\n\n", argv[0]);
return 1;
}
int encc = argc - 6;
int enclen[encc];
uint8_t enc[encc][120];
int encc = argc - 6;
int enclen[encc];
uint8_t enc[encc][120];
sscanf(argv[1], "%x", &uid);
sscanf(argv[2], "%x", &nt);
sscanf(argv[3], "%x", &nr_enc);
sscanf(argv[4], "%x", &ar_enc);
sscanf(argv[5], "%x", &at_enc);
for (int i = 0; i < encc; i++) {
enclen[i] = strlen(argv[i + 6]) / 2;
for (int i2 = 0; i2 < enclen[i]; i2++) {
sscanf(argv[i+6] + i2*2,"%2x", (unsigned int *)&enc[i][i2]);
}
}
printf("Recovering key for:\n");
sscanf(argv[1], "%x", &uid);
sscanf(argv[2], "%x", &nt);
sscanf(argv[3], "%x", &nr_enc);
sscanf(argv[4], "%x", &ar_enc);
sscanf(argv[5], "%x", &at_enc);
for (int i = 0; i < encc; i++) {
enclen[i] = strlen(argv[i + 6]) / 2;
for (int i2 = 0; i2 < enclen[i]; i2++) {
sscanf(argv[i+6] + i2*2,"%2x", (unsigned int*)&enc[i][i2]);
}
}
printf(" uid: %08x\n", uid);
printf(" nt: %08x\n", nt);
printf(" {nr}: %08x\n", nr_enc);
printf(" {ar}: %08x\n", ar_enc);
printf(" {at}: %08x\n", at_enc);
for (int i = 0; i < encc; i++) {
printf("{enc%d}: ", i);
for (int i2 = 0; i2 < enclen[i]; i2++) {
printf("%02x", enc[i][i2]);
}
printf("\n");
}
printf("Recovering key for:\n");
printf(" uid: %08x\n", uid);
printf(" nt: %08x\n", nt);
printf(" {nr}: %08x\n", nr_enc);
printf(" {ar}: %08x\n", ar_enc);
printf(" {at}: %08x\n", at_enc);
for (int i = 0; i < encc; i++) {
printf("{enc%d}: ", i);
for (int i2 = 0; i2 < enclen[i]; i2++) {
printf("%02x", enc[i][i2]);
}
printf("\n");
}
printf("\nLFSR successors of the tag challenge:\n");
printf(" nt' : %08x\n",prng_successor(nt, 64));
printf(" nt'': %08x\n",prng_successor(nt, 96));
/*
uint32_t uid = 0x9c599b32;
uint32_t tag_challenge = 0x82a4166c;
uint32_t nr_enc = 0xa1e458ce;
uint32_t reader_response = 0x6eea41e0;
uint32_t tag_response = 0x5cadf439;
*/
// Generate lfsr succesors of the tag challenge
printf("\nLFSR succesors of the tag challenge:\n");
printf(" nt': %08x\n",prng_successor(nt, 64));
printf(" nt'': %08x\n",prng_successor(nt, 96));
// Extract the keystream from the messages
ks2 = ar_enc ^ prng_successor(nt, 64);
ks3 = at_enc ^ prng_successor(nt, 96);
uint64_t start_time = msclock();
revstate = lfsr_recovery64(ks2, ks3);
uint64_t time_spent = msclock() - start_time;
printf("Time spent in lfsr_recovery64(): %1.2f seconds\n", (float)time_spent/1000.0);
printf("\nKeystream used to generate {ar} and {at}:\n");
printf(" ks2: %08x\n",ks2);
printf(" ks3: %08x\n",ks3);
// Extract the keystream from the messages
printf("\nKeystream used to generate {ar} and {at}:\n");
ks2 = ar_enc ^ prng_successor(nt, 64);
ks3 = at_enc ^ prng_successor(nt, 96);
printf(" ks2: %08x\n",ks2);
printf(" ks3: %08x\n",ks3);
// Decrypting communication using keystream if presented
if (argc > 6 ) {
printf("\nDecrypted communication:\n");
uint8_t ks4;
int rollb = 0;
for (int i = 0; i < encc; i++) {
printf("{dec%d}: ", i);
for (int i2 = 0; i2 < enclen[i]; i2++) {
ks4 = crypto1_byte(revstate, 0, 0);
printf("%02x", ks4 ^ enc[i][i2]);
rollb += 1;
}
printf("\n");
}
for (int i = 0; i < rollb; i++) {
lfsr_rollback_byte(revstate, 0, 0);
}
}
revstate = lfsr_recovery64(ks2, ks3);
lfsr_rollback_word(revstate, 0, 0);
lfsr_rollback_word(revstate, 0, 0);
lfsr_rollback_word(revstate, nr_enc, 1);
lfsr_rollback_word(revstate, uid ^ nt, 0);
crypto1_get_lfsr(revstate, &key);
crypto1_destroy(revstate);
// Decrypting communication using keystream if presented
if (argc > 6 ) {
printf("\nDecrypted communication:\n");
uint8_t ks4;
int rollb = 0;
for (int i = 0; i < encc; i++) {
printf("{dec%d}: ", i);
for (int i2 = 0; i2 < enclen[i]; i2++) {
ks4 = crypto1_byte(revstate, 0, 0);
printf("%02x", ks4 ^ enc[i][i2]);
rollb += 1;
}
printf("\n");
}
for (int i = 0; i < rollb; i++) {
lfsr_rollback_byte(revstate, 0, 0);
}
}
lfsr_rollback_word(revstate, 0, 0);
lfsr_rollback_word(revstate, 0, 0);
lfsr_rollback_word(revstate, nr_enc, 1);
lfsr_rollback_word(revstate, uid ^ nt, 0);
crypto1_get_lfsr(revstate, &key);
printf("\nFound Key: [%012" PRIx64"]\n\n",key);
crypto1_destroy(revstate);
return 0;
printf("\nFound Key: [%012" PRIx64"]\n\n",key);
}