Merge pull request #2593 from Akury83/master
[RRG-proxmark3.git] / tools / mfc / card_only / staticnested_2x1nt_rf08s_1key.c
blob66f0cecab224facec7aaee73501e081fec9a6edd
1 // Faster Backdoored Nested Attack against Fudan FM11RF08S tags, part 2
2 //
3 // Attack conditions:
4 // * Backdoor
5 // * keyA and keyB are different for the targeted sector
6 //
7 // Strategy:
8 // * Use f08s_nested_known_collision to crack keyA
9 // * If keyB not readable, find keyB in its dictionary based on the obscure relationship between keyA, keyB and their nT
11 // Doegox, 2024, cf https://eprint.iacr.org/2024/1275 for more info
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <stdbool.h>
16 #include <string.h>
17 #include <inttypes.h>
19 static uint32_t hex_to_uint32(const char *hex_str) {
20 return (uint32_t)strtoul(hex_str, NULL, 16);
23 uint16_t i_lfsr16[1 << 16] = {0};
24 uint16_t s_lfsr16[1 << 16] = {0};
26 static void init_lfsr16_table(void) {
27 uint16_t x = 1;
28 for (uint16_t i = 1; i; ++i) {
29 i_lfsr16[(x & 0xff) << 8 | x >> 8] = i;
30 s_lfsr16[i] = (x & 0xff) << 8 | x >> 8;
31 x = x >> 1 | (x ^ x >> 2 ^ x >> 3 ^ x >> 5) << 15;
35 // static uint16_t next_lfsr16(uint16_t nonce) {
36 // return s_lfsr16[(i_lfsr16[nonce]+1) % 65535];
37 // }
39 static uint16_t prev_lfsr16(uint16_t nonce) {
40 return s_lfsr16[(i_lfsr16[nonce] - 1) % 65535];
43 static uint16_t compute_seednt16_nt32(uint32_t nt32, uint64_t key) {
44 uint8_t a[] = {0, 8, 9, 4, 6, 11, 1, 15, 12, 5, 2, 13, 10, 14, 3, 7};
45 uint8_t b[] = {0, 13, 1, 14, 4, 10, 15, 7, 5, 3, 8, 6, 9, 2, 12, 11};
46 uint16_t nt = nt32 >> 16;
47 uint8_t prev = 14;
49 for (uint8_t i = 0; i < prev; i++) {
50 nt = prev_lfsr16(nt);
53 uint8_t prevoff = 8;
54 bool odd = 1;
56 for (uint8_t i = 0; i < 6 * 8; i += 8) {
58 if (odd) {
59 nt ^= (a[(key >> i) & 0xF]);
60 nt ^= (b[(key >> i >> 4) & 0xF]) << 4;
61 } else {
62 nt ^= (b[(key >> i) & 0xF]);
63 nt ^= (a[(key >> i >> 4) & 0xF]) << 4;
66 odd ^= 1;
67 prev += prevoff;
69 for (uint8_t j = 0; j < prevoff; j++) {
70 nt = prev_lfsr16(nt);
73 return nt;
76 int main(int argc, char *const argv[]) {
78 if (argc != 4) {
79 printf("Usage:\n %s <nt1:08x> <key1:012x> keys_<uid:08x>_<sector:02>_<nt2:08x>.dic\n"
80 " where dict file is produced by rf08s_nested_known *for the same UID and same sector* as provided nt and key\n",
81 argv[0]);
82 return 1;
85 uint32_t nt1 = hex_to_uint32(argv[1]);
86 uint64_t key1 = 0;
87 if (sscanf(argv[2], "%012" PRIx64, &key1) != 1) {
88 fprintf(stderr, "Failed to parse key: %s", argv[2]);
89 return 1;
92 char *filename = argv[3];
93 uint32_t uid, sector, nt2;
95 int result = sscanf(filename, "keys_%8x_%2u_%8x.dic", &uid, &sector, &nt2);
96 if (result != 3) {
97 fprintf(stderr, "Error: Failed to parse the filename %s.\n", filename);
98 return 1;
101 if (nt1 == nt2) {
102 fprintf(stderr, "Error: File must belong to different nonce.\n");
103 return 1;
106 init_lfsr16_table();
108 uint32_t keycount2 = 0;
109 uint64_t *keys2 = NULL;
111 FILE *fptr = fopen(filename, "r");
112 if (fptr != NULL) {
114 uint64_t buffer;
115 while (fscanf(fptr, "%012" PRIx64, &buffer) == 1) {
116 keycount2++;
119 keys2 = (uint64_t *)calloc(1, keycount2 * sizeof(uint64_t));
120 if (keys2 == NULL) {
121 perror("Failed to allocate memory");
122 fclose(fptr);
123 goto end;
126 rewind(fptr);
128 for (uint32_t i = 0; i < keycount2; i++) {
129 if (fscanf(fptr, "%012" PRIx64, &keys2[i]) != 1) {
130 perror("Failed to read key");
131 fclose(fptr);
132 goto end;
135 fclose(fptr);
137 } else {
138 fprintf(stderr, "Warning: Cannot open %s\n", filename);
139 goto end;
142 printf("%s: %u keys loaded\n", filename, keycount2);
144 uint32_t found = 0;
145 uint16_t seednt1 = compute_seednt16_nt32(nt1, key1);
146 for (uint32_t i = 0; i < keycount2; i++) {
147 if (seednt1 == compute_seednt16_nt32(nt2, keys2[i])) {
148 printf("MATCH: key2=%012" PRIx64 "\n", keys2[i]);
149 found++;
153 if (found == 0) {
154 printf("No key found :(\n");
157 end:
158 if (keys2 != NULL) {
159 free(keys2);
162 return 0;