textual
[RRG-proxmark3.git] / client / src / mifare / mfkey.c
blob710bba449ba36629f01404263f725713b8238df7
1 //-----------------------------------------------------------------------------
2 // Merlok - June 2011
3 // Roel - Dec 2009
4 // Unknown author
5 //
6 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
7 // at your option, any later version. See the LICENSE.txt file for the text of
8 // the license.
9 //-----------------------------------------------------------------------------
10 // MIFARE Darkside hack
11 //-----------------------------------------------------------------------------
12 #include "mfkey.h"
14 #include "crapto1/crapto1.h"
16 // MIFARE
17 int inline compare_uint64(const void *a, const void *b) {
18 if (*(uint64_t *)b == *(uint64_t *)a) return 0;
19 if (*(uint64_t *)b < * (uint64_t *)a) return 1;
20 return -1;
23 // create the intersection (common members) of two sorted lists. Lists are terminated by -1. Result will be in list1. Number of elements is returned.
24 uint32_t intersection(uint64_t *listA, uint64_t *listB) {
25 if (listA == NULL || listB == NULL)
26 return 0;
28 uint64_t *p1, *p2, *p3;
29 p1 = p3 = listA;
30 p2 = listB;
32 while (*p1 != UINT64_C(-1) && *p2 != UINT64_C(-1)) {
33 if (compare_uint64(p1, p2) == 0) {
34 *p3++ = *p1++;
35 p2++;
36 } else {
37 while (compare_uint64(p1, p2) < 0) ++p1;
38 while (compare_uint64(p1, p2) > 0) ++p2;
41 *p3 = UINT64_C(-1);
42 return p3 - listA;
45 // Darkside attack (hf mf mifare)
46 // if successful it will return a list of keys, not just one.
47 uint32_t nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint32_t ar, uint64_t par_info, uint64_t ks_info, uint64_t **keys) {
48 union {
49 struct Crypto1State *states;
50 uint64_t *keylist;
51 } unionstate;
53 uint32_t i, pos;
54 uint8_t ks3x[8], par[8][8];
55 uint64_t key_recovered;
57 // Reset the last three significant bits of the reader nonce
58 nr &= 0xFFFFFF1F;
60 for (pos = 0; pos < 8; pos++) {
61 ks3x[7 - pos] = (ks_info >> (pos * 8)) & 0x0F;
62 uint8_t bt = (par_info >> (pos * 8)) & 0xFF;
64 par[7 - pos][0] = (bt >> 0) & 1;
65 par[7 - pos][1] = (bt >> 1) & 1;
66 par[7 - pos][2] = (bt >> 2) & 1;
67 par[7 - pos][3] = (bt >> 3) & 1;
68 par[7 - pos][4] = (bt >> 4) & 1;
69 par[7 - pos][5] = (bt >> 5) & 1;
70 par[7 - pos][6] = (bt >> 6) & 1;
71 par[7 - pos][7] = (bt >> 7) & 1;
74 unionstate.states = lfsr_common_prefix(nr, ar, ks3x, par, (par_info == 0));
76 if (!unionstate.states) {
77 *keys = NULL;
78 return 0;
81 for (i = 0; unionstate.keylist[i]; i++) {
82 lfsr_rollback_word(unionstate.states + i, uid ^ nt, 0);
83 crypto1_get_lfsr(unionstate.states + i, &key_recovered);
84 unionstate.keylist[i] = key_recovered;
86 unionstate.keylist[i] = -1;
88 *keys = unionstate.keylist;
89 return i;
92 // recover key from 2 different reader responses on same tag challenge
93 bool mfkey32(nonces_t *data, uint64_t *outputkey) {
94 struct Crypto1State *s, *t;
95 uint64_t outkey = 0;
96 uint64_t key = 0; // recovered key
97 bool isSuccess = false;
98 uint8_t counter = 0;
100 uint32_t p640 = prng_successor(data->nonce, 64);
102 s = lfsr_recovery32(data->ar ^ p640, 0);
104 for (t = s; t->odd | t->even; ++t) {
105 lfsr_rollback_word(t, 0, 0);
106 lfsr_rollback_word(t, data->nr, 1);
107 lfsr_rollback_word(t, data->cuid ^ data->nonce, 0);
108 crypto1_get_lfsr(t, &key);
109 crypto1_word(t, data->cuid ^ data->nonce, 0);
110 crypto1_word(t, data->nr2, 1);
111 if (data->ar2 == (crypto1_word(t, 0, 0) ^ p640)) {
112 outkey = key;
113 counter++;
114 if (counter == 20) break;
117 isSuccess = (counter == 1);
118 *outputkey = (isSuccess) ? outkey : 0;
119 crypto1_destroy(s);
120 return isSuccess;
123 // recover key from 2 reader responses on 2 different tag challenges
124 // skip "several found keys". Only return true if ONE key is found
125 bool mfkey32_moebius(nonces_t *data, uint64_t *outputkey) {
126 struct Crypto1State *s, *t;
127 uint64_t outkey = 0;
128 uint64_t key = 0; // recovered key
129 bool isSuccess = false;
130 int counter = 0;
131 uint32_t p640 = prng_successor(data->nonce, 64);
132 uint32_t p641 = prng_successor(data->nonce2, 64);
134 s = lfsr_recovery32(data->ar ^ p640, 0);
136 for (t = s; t->odd | t->even; ++t) {
137 lfsr_rollback_word(t, 0, 0);
138 lfsr_rollback_word(t, data->nr, 1);
139 lfsr_rollback_word(t, data->cuid ^ data->nonce, 0);
140 crypto1_get_lfsr(t, &key);
142 crypto1_word(t, data->cuid ^ data->nonce2, 0);
143 crypto1_word(t, data->nr2, 1);
144 if (data->ar2 == (crypto1_word(t, 0, 0) ^ p641)) {
145 outkey = key;
146 ++counter;
147 if (counter == 20) break;
150 isSuccess = (counter == 1);
151 *outputkey = (isSuccess) ? outkey : 0;
152 crypto1_destroy(s);
153 return isSuccess;
156 // recover key from reader response and tag response of one authentication sequence
157 int mfkey64(nonces_t *data, uint64_t *outputkey) {
158 uint64_t key = 0; // recovered key
159 uint32_t ks2; // keystream used to encrypt reader response
160 uint32_t ks3; // keystream used to encrypt tag response
161 struct Crypto1State *revstate;
163 // Extract the keystream from the messages
164 ks2 = data->ar ^ prng_successor(data->nonce, 64);
165 ks3 = data->at ^ prng_successor(data->nonce, 96);
166 revstate = lfsr_recovery64(ks2, ks3);
167 lfsr_rollback_word(revstate, 0, 0);
168 lfsr_rollback_word(revstate, 0, 0);
169 lfsr_rollback_word(revstate, data->nr, 1);
170 lfsr_rollback_word(revstate, data->cuid ^ data->nonce, 0);
171 crypto1_get_lfsr(revstate, &key);
172 crypto1_destroy(revstate);
173 *outputkey = key;
174 return 0;