Merge pull request #2726 from n-hutton/emv_sim_cleanup_squash
[RRG-proxmark3.git] / tools / mfc / card_only / staticnested_2nt.c
blob484c5cdf7497eac856ead3040377de91b8924e7b
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <inttypes.h>
5 #include <pthread.h>
6 #include "common.h"
7 #include "nested_util.h"
8 #include "crapto1/crapto1.h"
11 #define AEND "\x1b[0m"
12 #define _RED_(s) "\x1b[31m" s AEND
13 #define _GREEN_(s) "\x1b[32m" s AEND
14 #define _YELLOW_(s) "\x1b[33m" s AEND
15 #define _CYAN_(s) "\x1b[36m" s AEND
17 typedef struct {
18 union {
19 struct Crypto1State *slhead;
20 uint64_t *keyhead;
21 } head;
22 union {
23 struct Crypto1State *sltail;
24 uint64_t *keytail;
25 } tail;
26 uint32_t len;
27 uint32_t uid;
28 uint32_t blockNo;
29 uint32_t keyType;
30 uint32_t nt_enc;
31 uint32_t ks1;
32 } StateList_t;
35 inline static int compare_uint64(const void *a, const void *b) {
36 if (*(uint64_t *)b == *(uint64_t *)a) return 0;
37 if (*(uint64_t *)b < * (uint64_t *)a) return 1;
38 return -1;
41 // Compare 16 Bits out of cryptostate
42 inline static int compare16Bits(const void *a, const void *b) {
43 if ((*(uint64_t *)b & 0x00ff000000ff0000) == (*(uint64_t *)a & 0x00ff000000ff0000)) return 0;
44 if ((*(uint64_t *)b & 0x00ff000000ff0000) > (*(uint64_t *)a & 0x00ff000000ff0000)) return 1;
45 return -1;
48 // create the intersection (common members) of two sorted lists. Lists are terminated by -1. Result will be in list1. Number of elements is returned.
49 static uint32_t intersection(uint64_t *listA, uint64_t *listB) {
50 if (listA == NULL || listB == NULL)
51 return 0;
53 uint64_t *p1, *p2, *p3;
54 p1 = p3 = listA;
55 p2 = listB;
57 while (*p1 != UINT64_C(-1) && *p2 != UINT64_C(-1)) {
58 if (compare_uint64(p1, p2) == 0) {
59 *p3++ = *p1++;
60 p2++;
61 } else {
62 while (compare_uint64(p1, p2) < 0) ++p1;
63 while (compare_uint64(p1, p2) > 0) ++p2;
66 *p3 = UINT64_C(-1);
67 return p3 - listA;
70 // wrapper function for multi-threaded lfsr_recovery32
71 static void
72 #ifdef __has_attribute
73 #if __has_attribute(force_align_arg_pointer)
74 __attribute__((force_align_arg_pointer))
75 #endif
76 #endif
77 *nested_worker_thread(void *arg) {
78 struct Crypto1State *p1;
79 StateList_t *statelist = arg;
80 statelist->head.slhead = lfsr_recovery32(statelist->ks1, statelist->nt_enc ^ statelist->uid);
82 for (p1 = statelist->head.slhead; p1->odd | p1->even; p1++) {};
84 statelist->len = p1 - statelist->head.slhead;
85 statelist->tail.sltail = --p1;
87 qsort(statelist->head.slhead, statelist->len, sizeof(uint64_t), compare16Bits);
89 return statelist->head.slhead;
92 static void pm3_staticnested(uint32_t uid, uint32_t nt1, uint32_t ks1, uint32_t nt2, uint32_t ks2) {
94 StateList_t statelists[2];
95 struct Crypto1State *p1, * p2, * p3, * p4;
97 for (uint8_t i = 0; i < 2; i++) {
98 statelists[i].uid = uid;
101 statelists[0].nt_enc = nt1;
102 statelists[0].ks1 = ks1;
103 statelists[1].nt_enc = nt2;
104 statelists[1].ks1 = ks2;
106 // calc keys
107 pthread_t thread_id[2];
109 // create and run worker threads
110 for (uint8_t i = 0; i < 2; i++) {
111 pthread_create(thread_id + i, NULL, nested_worker_thread, &statelists[i]);
114 // wait for threads to terminate:
115 for (uint8_t i = 0; i < 2; i++) {
116 pthread_join(thread_id[i], (void *)&statelists[i].head.slhead);
119 // the first 16 Bits of the cryptostate already contain part of our key.
120 // Create the intersection of the two lists based on these 16 Bits and
121 // roll back the cryptostate
122 p1 = p3 = statelists[0].head.slhead;
123 p2 = p4 = statelists[1].head.slhead;
125 while (p1 <= statelists[0].tail.sltail && p2 <= statelists[1].tail.sltail) {
126 if (compare16Bits(p1, p2) == 0) {
128 struct Crypto1State savestate;
129 savestate = *p1;
131 while (compare16Bits(p1, &savestate) == 0 && p1 <= statelists[0].tail.sltail) {
132 *p3 = *p1;
133 lfsr_rollback_word(p3, statelists[0].nt_enc ^ statelists[0].uid, 0);
134 p3++;
135 p1++;
137 savestate = *p2;
139 while (compare16Bits(p2, &savestate) == 0 && p2 <= statelists[1].tail.sltail) {
140 *p4 = *p2;
141 lfsr_rollback_word(p4, statelists[1].nt_enc ^ statelists[1].uid, 0);
142 p4++;
143 p2++;
145 } else {
146 while (compare16Bits(p1, p2) == -1) p1++;
147 while (compare16Bits(p1, p2) == 1) p2++;
151 p3->odd = -1;
152 p3->even = -1;
153 p4->odd = -1;
154 p4->even = -1;
155 statelists[0].len = p3 - statelists[0].head.slhead;
156 statelists[1].len = p4 - statelists[1].head.slhead;
157 statelists[0].tail.sltail = --p3;
158 statelists[1].tail.sltail = --p4;
160 // the statelists now contain possible keys. The key we are searching for must be in the
161 // intersection of both lists
162 qsort(statelists[0].head.keyhead, statelists[0].len, sizeof(uint64_t), compare_uint64);
163 qsort(statelists[1].head.keyhead, statelists[1].len, sizeof(uint64_t), compare_uint64);
164 // Create the intersection
165 statelists[0].len = intersection(statelists[0].head.keyhead, statelists[1].head.keyhead);
167 uint32_t keycnt = statelists[0].len;
168 if (keycnt) {
169 printf("PM3 Static nested --> Found " _YELLOW_("%u") " key candidates\n", keycnt);
170 for (uint32_t k = 0; k < keycnt; k++) {
171 uint64_t key64 = 0;
172 crypto1_get_lfsr(statelists[0].head.slhead + k, &key64);
173 printf("[ %u ] " _GREEN_("%012" PRIx64) "\n", k + 1, key64);
178 static int usage(void) {
179 printf("\n");
180 printf("\nProgram tries to recover keys from static encrypted nested MFC cards\n");
181 printf("using two different implementations, Chameleon Ultra (CU) and Proxmark3.\n");
182 printf("It uses the nonce, keystream sent from pm3 device to client.\n");
183 printf("ie: NOT the CU data which is data in the trace.\n");
184 printf("\n");
185 printf("syntax: staticnested <uid> <nt1> <ks1> <nt2> <ks2>\n\n");
186 printf("samples:\n");
187 printf("\n");
188 printf(" ./staticnested 461dce03 7eef3586 ffb02eda 322bc14d ffc875ca\n");
189 printf(" ./staticnested 461dce03 7eef3586 1fb6b496 322bc14d 1f4eebdd\n");
190 printf(" ./staticnested 461dce03 7eef3586 7fa28c7e 322bc14d 7f62b3d6\n");
191 printf("\n");
192 return 1;
195 int main(int argc, char *const argv[]) {
197 printf("\nMIFARE Classic static nested key recovery\n\n");
199 if (argc < 5) return usage();
201 printf("Init...\n");
202 NtpKs1 *pNK = calloc(2, sizeof(NtpKs1));
203 if (pNK == NULL) {
204 goto error;
207 uint32_t uid = 0;
209 sscanf(argv[1], "%x", &uid);
210 sscanf(argv[2], "%x", &pNK[0].ntp);
211 sscanf(argv[3], "%x", &pNK[0].ks1);
212 sscanf(argv[4], "%x", &pNK[1].ntp);
213 sscanf(argv[5], "%x", &pNK[1].ks1);
215 printf("uid... %08x\n", uid);
216 printf("nt1... %08x\n", pNK[0].ntp);
217 printf("ks1... %08x\n", pNK[0].ks1);
218 printf("nt2... %08x\n", pNK[1].ntp);
219 printf("ks2... %08x\n", pNK[1].ks1);
221 // process all args.
222 printf("Recovery...\n");
224 uint32_t key_count = 0;
225 uint64_t *keys = nested(pNK, 2, uid, &key_count);
227 if (key_count) {
228 printf("Ultra Static nested --> Found " _YELLOW_("%u") " key candidates\n", key_count);
229 for (uint32_t k = 0; k < key_count; k++) {
230 printf("[ %u ] " _GREEN_("%012" PRIx64) "\n", k + 1, keys[k]);
234 pm3_staticnested(uid, pNK[0].ntp, pNK[0].ks1, pNK[1].ntp, pNK[1].ks1);
236 fflush(stdout);
237 free(keys);
238 exit(EXIT_SUCCESS);
239 error:
240 exit(EXIT_FAILURE);