]>
cvs.zerfleddert.de Git - proxmark3-svn/blob - armsrc/mifareutil.c
53e785f5b6f8e0570f20be590bd06ff04770f2fd
1 //-----------------------------------------------------------------------------
3 // Many authors, that makes it possible
5 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
6 // at your option, any later version. See the LICENSE.txt file for the text of
8 //-----------------------------------------------------------------------------
9 // code for work with mifare cards.
10 //-----------------------------------------------------------------------------
12 #include "proxmark3.h"
17 #include "iso14443crc.h"
18 #include "iso14443a.h"
20 #include "mifareutil.h"
22 int MF_DBGLEVEL
= MF_DBG_ALL
;
24 uint8_t* mifare_get_bigbufptr(void) {
25 return (((uint8_t *)BigBuf
) + 3560); // was 3560 - tied to other size changes
28 int mifare_sendcmd_short(struct Crypto1State
*pcs
, uint8_t crypted
, uint8_t cmd
, uint8_t data
, uint8_t* answer
)
30 return mifare_sendcmd_shortex(pcs
, crypted
, cmd
, data
, answer
, NULL
);
33 int mifare_sendcmd_shortex(struct Crypto1State
*pcs
, uint8_t crypted
, uint8_t cmd
, uint8_t data
, uint8_t* answer
, uint32_t * parptr
)
35 uint8_t dcmd
[4], ecmd
[4];
36 uint32_t pos
, par
, res
;
40 AppendCrc14443a(dcmd
, 2);
42 memcpy(ecmd
, dcmd
, sizeof(dcmd
));
46 for (pos
= 0; pos
< 4; pos
++)
48 ecmd
[pos
] = crypto1_byte(pcs
, 0x00, 0) ^ dcmd
[pos
];
49 par
= (par
>> 1) | ( ((filter(pcs
->odd
) ^ oddparity(dcmd
[pos
])) & 0x01) * 0x08 );
52 ReaderTransmitPar(ecmd
, sizeof(ecmd
), par
);
55 ReaderTransmit(dcmd
, sizeof(dcmd
));
58 int len
= ReaderReceivePar(answer
, &par
);
60 if (parptr
) *parptr
= par
;
62 if (crypted
== CRYPT_ALL
) {
65 for (pos
= 0; pos
< 4; pos
++)
66 res
|= (crypto1_bit(pcs
, 0, 0) ^ BIT(answer
[0], pos
)) << pos
;
71 for (pos
= 0; pos
< len
; pos
++)
73 answer
[pos
] = crypto1_byte(pcs
, 0x00, 0) ^ answer
[pos
];
81 int mifare_classic_auth(struct Crypto1State
*pcs
, uint32_t uid
, uint8_t blockNo
, uint8_t keyType
, uint64_t ui64Key
, uint64_t isNested
)
83 return mifare_classic_authex(pcs
, uid
, blockNo
, keyType
, ui64Key
, isNested
, NULL
);
86 int mifare_classic_authex(struct Crypto1State
*pcs
, uint32_t uid
, uint8_t blockNo
, uint8_t keyType
, uint64_t ui64Key
, uint64_t isNested
, uint32_t * ntptr
)
94 uint32_t nt
, ntpp
; // Supplied tag nonce
96 uint8_t mf_nr_ar
[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
97 uint8_t* receivedAnswer
= mifare_get_bigbufptr();
99 // Transmit MIFARE_CLASSIC_AUTH
100 len
= mifare_sendcmd_short(pcs
, isNested
, 0x60 + (keyType
& 0x01), blockNo
, receivedAnswer
);
101 if (MF_DBGLEVEL
>= 4) Dbprintf("rand nonce len: %x", len
);
102 if (len
!= 4) return 1;
109 // Save the tag nonce (nt)
110 nt
= bytes_to_num(receivedAnswer
, 4);
112 // ----------------------------- crypto1 create
114 crypto1_destroy(pcs
);
116 // Init cipher with key
117 crypto1_create(pcs
, ui64Key
);
119 if (isNested
== AUTH_NESTED
) {
120 // decrypt nt with help of new key
121 nt
= crypto1_word(pcs
, nt
^ uid
, 1) ^ nt
;
123 // Load (plain) uid^nt into the cipher
124 crypto1_word(pcs
, nt
^ uid
, 0);
128 if (!ntptr
&& (MF_DBGLEVEL
>= 3))
129 Dbprintf("auth uid: %08x nt: %08x", uid
, nt
);
136 // Generate (encrypted) nr+parity by loading it into the cipher (Nr)
137 for (pos
= 0; pos
< 4; pos
++)
139 mf_nr_ar
[pos
] = crypto1_byte(pcs
, ar
[pos
], 0) ^ ar
[pos
];
140 par
= (par
>> 1) | ( ((filter(pcs
->odd
) ^ oddparity(ar
[pos
])) & 0x01) * 0x80 );
143 // Skip 32 bits in pseudo random generator
144 nt
= prng_successor(nt
,32);
147 for (pos
= 4; pos
< 8; pos
++)
149 nt
= prng_successor(nt
,8);
150 mf_nr_ar
[pos
] = crypto1_byte(pcs
,0x00,0) ^ (nt
& 0xff);
151 par
= (par
>> 1)| ( ((filter(pcs
->odd
) ^ oddparity(nt
& 0xff)) & 0x01) * 0x80 );
154 // Transmit reader nonce and reader answer
155 ReaderTransmitPar(mf_nr_ar
, sizeof(mf_nr_ar
), par
);
157 // Receive 4 bit answer
158 len
= ReaderReceive(receivedAnswer
);
161 if (MF_DBGLEVEL
>= 1) Dbprintf("Authentication failed. Card timeout.");
165 memcpy(tmp4
, receivedAnswer
, 4);
166 ntpp
= prng_successor(nt
, 32) ^ crypto1_word(pcs
, 0,0);
168 if (ntpp
!= bytes_to_num(tmp4
, 4)) {
169 if (MF_DBGLEVEL
>= 1) Dbprintf("Authentication failed. Error card response.");
176 int mifare_classic_readblock(struct Crypto1State
*pcs
, uint32_t uid
, uint8_t blockNo
, uint8_t *blockData
)
182 uint8_t* receivedAnswer
= mifare_get_bigbufptr();
184 // command MIFARE_CLASSIC_READBLOCK
185 len
= mifare_sendcmd_short(pcs
, 1, 0x30, blockNo
, receivedAnswer
);
187 if (MF_DBGLEVEL
>= 1) Dbprintf("Cmd Error: %02x", receivedAnswer
[0]);
191 if (MF_DBGLEVEL
>= 1) Dbprintf("Cmd Error: card timeout. len: %x", len
);
195 memcpy(bt
, receivedAnswer
+ 16, 2);
196 AppendCrc14443a(receivedAnswer
, 16);
197 if (bt
[0] != receivedAnswer
[16] || bt
[1] != receivedAnswer
[17]) {
198 if (MF_DBGLEVEL
>= 1) Dbprintf("Cmd CRC response error.");
202 memcpy(blockData
, receivedAnswer
, 16);
206 int mifare_classic_writeblock(struct Crypto1State
*pcs
, uint32_t uid
, uint8_t blockNo
, uint8_t *blockData
)
214 uint8_t d_block
[18], d_block_enc
[18];
215 uint8_t* receivedAnswer
= mifare_get_bigbufptr();
217 // command MIFARE_CLASSIC_WRITEBLOCK
218 len
= mifare_sendcmd_short(pcs
, 1, 0xA0, blockNo
, receivedAnswer
);
220 if ((len
!= 1) || (receivedAnswer
[0] != 0x0A)) { // 0x0a - ACK
221 if (MF_DBGLEVEL
>= 1) Dbprintf("Cmd Error: %02x", receivedAnswer
[0]);
225 memcpy(d_block
, blockData
, 16);
226 AppendCrc14443a(d_block
, 16);
230 for (pos
= 0; pos
< 18; pos
++)
232 d_block_enc
[pos
] = crypto1_byte(pcs
, 0x00, 0) ^ d_block
[pos
];
233 par
= (par
>> 1) | ( ((filter(pcs
->odd
) ^ oddparity(d_block
[pos
])) & 0x01) * 0x20000 );
236 ReaderTransmitPar(d_block_enc
, sizeof(d_block_enc
), par
);
238 // Receive the response
239 len
= ReaderReceive(receivedAnswer
);
242 for (i
= 0; i
< 4; i
++)
243 res
|= (crypto1_bit(pcs
, 0, 0) ^ BIT(receivedAnswer
[0], i
)) << i
;
245 if ((len
!= 1) || (res
!= 0x0A)) {
246 if (MF_DBGLEVEL
>= 1) Dbprintf("Cmd send data2 Error: %02x", res
);
253 int mifare_classic_halt(struct Crypto1State
*pcs
, uint32_t uid
)
259 uint8_t* receivedAnswer
= mifare_get_bigbufptr();
261 len
= mifare_sendcmd_short(pcs
, 1, 0x50, 0x00, receivedAnswer
);
263 if (MF_DBGLEVEL
>= 1) Dbprintf("halt error. response len: %x", len
);