1 // Backdoored Nested Attack
4 // * Backdoor, or a way to know the clear static nested nT
7 // * Use backdoor on the targeted sector to get the clear static nested nT
8 // * Enumerate key candidates based on clear and encrypted nT
9 // * Use the resulting dictionary to bruteforce the key
11 // Doegox, 2024, cf https://eprint.iacr.org/2024/1275 for more info
18 #include "crapto1/crapto1.h"
21 #define KEY_SPACE_SIZE (1 << 18)
30 static uint32_t hex_to_uint32(const char *hex_str
) {
31 return (uint32_t)strtoul(hex_str
, NULL
, 16);
34 static int bin_to_uint8_arr(const char *bin_str
, uint8_t bit_arr
[], uint8_t arr_size
) {
35 if (strlen(bin_str
) != arr_size
) {
36 fprintf(stderr
, "Error: Binary string (%s) length does not match array size (%i).\n", bin_str
, arr_size
);
40 for (uint8_t i
= 0; i
< arr_size
; i
++) {
41 if (bin_str
[i
] == '0') {
43 } else if (bin_str
[i
] == '1') {
46 fprintf(stderr
, "Error: Invalid character '%c' in binary string.\n", bin_str
[i
]);
53 static uint64_t *generate_keys(uint64_t authuid
, uint32_t nt
, uint32_t nt_enc
, uint32_t nt_par_enc
, uint32_t *keyCount
) {
54 uint64_t *result_keys
= (uint64_t *)malloc(KEY_SPACE_SIZE
* sizeof(uint64_t));
55 if (result_keys
== NULL
) {
56 fprintf(stderr
, "\nMalloc error in generate_and_intersect_keys!\n");
60 struct Crypto1State
*revstate
, *revstate_start
= NULL
, *s
= NULL
;
62 uint32_t ks1
= nt
^ nt_enc
;
64 revstate
= lfsr_recovery32(ks1
, nt
^ authuid
);
65 if (revstate
== NULL
) {
66 fprintf(stderr
, "\nMalloc error in generate_keys!\n");
70 if (revstate_start
== NULL
) {
71 revstate_start
= revstate
;
73 s
= crypto1_create(0);
75 fprintf(stderr
, "\nMalloc error in generate_keys!\n");
77 crypto1_destroy(revstate_start
);
80 while ((revstate
->odd
!= 0x0) || (revstate
->even
!= 0x0)) {
81 lfsr_rollback_word(revstate
, nt
^ authuid
, 0);
82 crypto1_get_lfsr(revstate
, &lfsr
);
84 // only filtering possibility: last parity bit ks in ks2
86 uint8_t lastpar1
, lastpar2
, kslastp
;
87 crypto1_init(s
, lfsr
);
88 crypto1_word(s
, nt
^ authuid
, 0);
89 ks2
= crypto1_word(s
, 0, 0);
90 lastpar1
= oddparity8(nt
& 0xFF);
91 kslastp
= (ks2
>> 24) & 1;
92 lastpar2
= (nt_par_enc
& 1) ^ kslastp
;
93 if (lastpar1
== lastpar2
) {
94 result_keys
[(*keyCount
)++] = lfsr
;
95 if (*keyCount
== KEY_SPACE_SIZE
) {
96 fprintf(stderr
, "No space left on result_keys, abort! Increase KEY_SPACE_SIZE\n");
103 crypto1_destroy(revstate_start
);
104 revstate_start
= NULL
;
108 int main(int argc
, char *const argv
[]) {
110 int cmdlen
= strlen(argv
[0]);
111 printf("Usage:\n %s <uid:hex> <sector:dec> <nt:hex> <nt_enc:hex> <nt_par_err:bin>\n"
112 " parity example: if for block 63 == sector 15, nt in trace is 7b! fc! 7a! 5b\n"
113 " then nt_enc is 7bfc7a5b and nt_par_err is 1110\n"
115 " %*s a13e4902 15 d14191b3 2e9e49fc 1111\n"
116 " %*s +uid +s +nt +nt_enc +nt_par_err\n",
117 argv
[0], cmdlen
, argv
[0], cmdlen
, "");
120 uint64_t *keys
= NULL
;
121 uint32_t keyCount
= 0;
123 uint32_t authuid
= hex_to_uint32(argv
[1]);
124 uint32_t sector
= atoi(argv
[2]);
125 uint32_t nt
= hex_to_uint32(argv
[3]);
126 uint32_t nt_enc
= hex_to_uint32(argv
[4]);
127 uint8_t nt_par_err_arr
[4];
128 if (bin_to_uint8_arr(argv
[5], nt_par_err_arr
, 4)) {
131 uint8_t nt_par_enc
= ((nt_par_err_arr
[0] ^ oddparity8((nt_enc
>> 24) & 0xFF)) << 3) |
132 ((nt_par_err_arr
[1] ^ oddparity8((nt_enc
>> 16) & 0xFF)) << 2) |
133 ((nt_par_err_arr
[2] ^ oddparity8((nt_enc
>> 8) & 0xFF)) << 1) |
134 ((nt_par_err_arr
[3] ^ oddparity8((nt_enc
>> 0) & 0xFF)) << 0);
135 printf("uid=%08x nt=%08x nt_enc=%08x nt_par_err=%i%i%i%i nt_par_enc=%i%i%i%i ks1=%08x\n", authuid
, nt
, nt_enc
,
136 nt_par_err_arr
[0], nt_par_err_arr
[1], nt_par_err_arr
[2], nt_par_err_arr
[3],
137 (nt_par_enc
>> 3) & 1, (nt_par_enc
>> 2) & 1, (nt_par_enc
>> 1) & 1, nt_par_enc
& 1,
141 printf("Finding key candidates...\n");
142 keys
= generate_keys(authuid
, nt
, nt_enc
, nt_par_enc
, &keyCount
);
143 printf("Finding phase complete, found %i keys\n", keyCount
);
147 snprintf(filename
, sizeof(filename
), "keys_%08x_%02i_%08x.dic", authuid
, sector
, nt
);
149 fptr
= fopen(filename
, "w");
152 for (uint32_t j
= 0; j
< keyCount
; j
++) {
153 fprintf(fptr
, "%012" PRIx64
"\n", keys
[j
]);
158 fprintf(stderr
, "Warning: Cannot save keys in %s\n", filename
);