3 * SecureMemory recovery
5 * Copyright (C) 2010, Flavio D. Garcia, Peter van Rossum, Roel Verdult
6 * and Ronny Wichers Schreur. Radboud University Nijmegen
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 * Modified Iceman, 2020
31 #include <algorithm> // sort, max_element, random_shuffle, remove_if, lower_bound
32 #include <functional> // greater, bind2nd
33 #include "cryptolib.h"
43 // avoid scanf warnings in Visual Studio
44 #define _CRT_SECURE_NO_WARNINGS
45 #define _CRT_SECURE_NO_DEPRECATE
46 #define inline __inline
50 >./sm 4f794a463ff81d81 ffffffffffffffff 1234567812345678
51 SecureMemory simulator - (c) Radboud University Nijmegen
54 Gc: 4f 79 4a 46 3f f8 1d 81
55 Ci: ff ff ff ff ff ff ff ff
56 Q: 12 34 56 78 12 34 56 78
57 Ch: 88 c9 d4 46 6a 50 1a 87
58 Ci+1: de c2 ee 1b 1c 92 76 e9
60 Ks: de 88 c2 c9 ee d4 1b 46 1c 6a 92 50 76 1a e9 87
111 const uint64_t left_candidates[43] = {
112 0x6221539d9ull, 0x1ddeac626ull, 0x7cc847482ull, 0x0337b8b7dull,
113 0x159d1687eull, 0x7bade8a41ull, 0x4c51c6463ull, 0x4e3d88bf9ull,
114 0x4e3d88819ull, 0x31c2777e6ull, 0x31c277406ull, 0x0059ff7d5ull,
115 0x5fb612b96ull, 0x2049ed469ull, 0x0452175beull, 0x00d2ff4edull,
116 0x68918cba9ull, 0x03a6f882aull, 0x7086372b6ull, 0x6c9a11672ull,
117 0x60531191aull, 0x4ba9b653full, 0x4ba9b6520ull, 0x1facee6e5ull,
118 0x0f79c8d49ull, 0x0b29f2a5bull, 0x032df8b12ull, 0x7c90849f8ull,
119 0x48916e84eull, 0x176e73456ull, 0x036f7b607ull, 0x5b2aeb858ull,
120 0x51c8755b5ull, 0x4c9432733ull, 0x0f6c834fbull, 0x03b2ff59bull,
121 0x0f78aac5bull, 0x3770cdaf3ull, 0x205078bbaull, 0x04445c715ull,
122 0x004df8a64ull, 0x6f696e09eull, 0x109691f61ull
145 enum cipher_state_side
{
150 void print_cs(const char *text
, pcs s
) {
154 for (pos
= 6; pos
>= 0; pos
--)
155 printf(" %02x", (uint8_t)(s
->l
>> (pos
* 5)) & 0x1f);
157 for (pos
= 6; pos
>= 0; pos
--)
158 printf(" %02x", (uint8_t)(s
->m
>> (pos
* 7)) & 0x7f);
160 for (pos
= 4; pos
>= 0; pos
--)
161 printf(" %02x", (uint8_t)(s
->r
>> (pos
* 5)) & 0x1f);
166 static inline uint8_t mod(uint8_t a
, uint8_t m
) {
168 return 0; // Actually, divide by zero error
171 // Just return the input when this is less or equal than the modular value
174 // Compute the modular value
177 // Return the funny value, when the output was now zero, return the modular value
178 return (a
== 0) ? m
: a
;
181 static inline uint8_t bit_rotate_l(uint8_t a
, uint8_t n_bits
) {
182 // Rotate value a with the length of n_bits only 1 time
183 uint8_t mask
= (1 << n_bits
) - 1;
184 return ((a
<< 1) | (a
>> (n_bits
- 1))) & mask
;
187 static inline uint8_t bit_rotate_r(uint8_t a
, uint8_t n_bits
) {
188 return ((a
>> 1) | ((a
& 1) << (n_bits
- 1)));
191 static uint8_t lookup_left_subtraction
[0x400];
192 static uint8_t lookup_right_subtraction
[0x400];
193 static lookup_entry lookup_left
[0x100000];
194 static lookup_entry lookup_right
[0x8000];
195 static uint8_t left_addition
[0x100000];
197 static inline void init_lookup_left() {
198 for (int i
= 0; i
< 0x400; i
++) {
200 int b3
= (i
>> 5) & 0x1f;
201 int index
= (b3
<< 15) | b6
;
202 b6
= bit_rotate_l(b6
, 5);
204 int temp
= mod(b3
+ b6
, 0x1f);
205 left_addition
[index
] = temp
;
206 lookup_left
[index
].addition
= temp
;
207 lookup_left
[index
].out
= ((temp
^ b3
) & 0x0f);
211 static inline void init_lookup_right() {
212 for (int i
= 0; i
< 0x400; i
++) {
214 int b16
= (i
>> 5) & 0x1f;
215 int index
= (b16
<< 10) | b18
;
217 int temp
= mod(b18
+ b16
, 0x1f);
218 lookup_right
[index
].addition
= temp
;
219 lookup_right
[index
].out
= ((temp
^ b16
) & 0x0f);
223 static void init_lookup_left_subtraction() {
224 for (int index
= 0; index
< 0x400 ; index
++) {
225 uint8_t b3
= (index
>> 5 & 0x1f);
226 uint8_t bx
= (index
& 0x1f);
227 lookup_left_subtraction
[index
] = bit_rotate_r(mod((bx
+ 0x1f) - b3
, 0x1f), 5);
231 static void init_lookup_right_subtraction() {
232 for (int index
= 0; index
< 0x400 ; index
++) {
233 int b16
= (index
>> 5);
234 uint8_t bx
= (index
& 0x1f);
235 lookup_right_subtraction
[index
] = mod((bx
+ 0x1f) - b16
, 0x1f);
239 static inline void previous_left(uint8_t in
, vector
<cs_t
> *candidate_states
) {
241 size_t size
= candidate_states
->size();
242 for (size_t pos
= 0; pos
< size
; pos
++) {
243 state
= &((*candidate_states
)[pos
]);
245 uint8_t bx
= (uint8_t)((state
->l
>> 30) & 0x1f);
246 unsigned b3
= (unsigned)(state
->l
>> 5) & 0x3e0;
247 state
->l
= (state
->l
<< 5);
249 //Ignore impossible states
251 // Are we dealing with an impossible state?
253 state
->invalid
= true;
255 // We only need to consider b6=0
256 state
->l
&= 0x7ffffffe0ull
;
257 state
->l
^= (((uint64_t)in
& 0x1f) << 20);
260 uint8_t b6
= lookup_left_subtraction
[b3
| bx
];
261 state
->l
= (state
->l
& 0x7ffffffe0ull
) | b6
;
262 state
->l
^= (((uint64_t)in
& 0x1f) << 20);
264 // Check if we have a second candidate
266 cs_t nstate
= *state
;
267 nstate
.l
&= 0x7ffffffe0ull
;
268 candidate_states
->push_back(nstate
);
274 static inline void previous_right(uint8_t in
, vector
<cs_t
> *candidate_states
) {
276 size_t size
= candidate_states
->size();
277 for (size_t pos
= 0; pos
< size
; pos
++) {
278 state
= &((*candidate_states
)[pos
]);
280 uint8_t bx
= (uint8_t)((state
->r
>> 20) & 0x1f);
281 unsigned b16
= (unsigned)(state
->r
& 0x3e0);//(state->buffer_r >> 10) & 0x1f;
283 state
->r
= (state
->r
<< 5);
285 // Ignore impossible states
288 state
->invalid
= true;
290 // We only need to consider b18=0
291 state
->r
&= 0x1ffffe0ull
;
292 state
->r
^= (((uint64_t)in
& 0xf8) << 12);
295 uint8_t b18
= lookup_right_subtraction
[b16
| bx
];
296 state
->r
= (state
->r
& 0x1ffffe0ull
) | b18
;
297 state
->r
^= (((uint64_t)in
& 0xf8) << 12);
298 //state->b_right = ((b14^b17) & 0x0f);
300 // Check if we have a second candidate
302 cs_t nstate
= *state
;
303 nstate
.r
&= 0x1ffffe0ull
;
304 candidate_states
->push_back(nstate
);
310 static inline uint8_t next_left_fast(uint8_t in
, uint64_t *left
) {
311 if (in
) *left
^= ((in
& 0x1f) << 20);
312 lookup_entry
*lookup
= &(lookup_left
[((*left
) & 0xf801f)]);
313 *left
= (((*left
) >> 5) | ((uint64_t)lookup
->addition
<< 30));
318 static inline uint8_t next_left_ksbyte(uint64_t *left) {
319 lookup_entry *lookup;
322 *left = (((*left) >> 5) | ((uint64_t)left_addition[((*left) & 0xf801f)] << 30));
323 lookup = &(lookup_left[((*left) & 0xf801f)]);
324 *left = (((*left) >> 5) | ((uint64_t)lookup->addition << 30));
325 bt = lookup->out << 4;
326 *left = (((*left) >> 5) | ((uint64_t)left_addition[((*left) & 0xf801f)] << 30));
327 lookup = &(lookup_left[((*left) & 0xf801f)]);
328 *left = (((*left) >> 5) | ((uint64_t)lookup->addition << 30));
334 static inline uint8_t next_right_fast(uint8_t in
, uint64_t *right
) {
335 if (in
) *right
^= ((in
& 0xf8) << 12);
336 lookup_entry
*lookup
= &(lookup_right
[((*right
) & 0x7c1f)]);
337 *right
= (((*right
) >> 5) | (lookup
->addition
<< 20));
341 static inline void sm_left_mask(const uint8_t *ks
, uint8_t *mask
, uint64_t rstate
) {
344 for (pos
= 0; pos
< 16; pos
++) {
345 next_right_fast(0, &rstate
);
346 uint8_t bt
= next_right_fast(0, &rstate
) << 4;
347 next_right_fast(0, &rstate
);
348 bt
|= next_right_fast(0, &rstate
);
350 // xor the bits with the keystream and count the "correct" bits
353 // Save the mask for the left produced bits
358 static inline uint32_t sm_right(const uint8_t *ks
, uint8_t *mask
, vector
<uint64_t> *pcrstates
) {
359 uint8_t tmp_mask
[16];
360 size_t pos
, bit
, topbits
;
361 uint64_t rstate
, counter
;
362 map
<uint64_t, uint64_t> bincstates
;
363 map
<uint64_t, uint64_t>::iterator it
;
367 for (counter
= 0; counter
< 0x2000000; counter
++) {
368 // Reset the current bitcount of correct bits
371 // Copy the state we are going to test
374 for (pos
= 0; pos
< 16; pos
++) {
375 next_right_fast(0, &rstate
);
376 bt
= next_right_fast(0, &rstate
) << 4;
377 next_right_fast(0, &rstate
);
378 bt
|= next_right_fast(0, &rstate
);
380 // xor the bits with the keystream and count the "correct" bits
383 // Save the mask for the left produced bits
386 for (bit
= 0; bit
< 8; bit
++) {
387 // When the bit is xored away (=zero), it was the same, so correct ;)
388 if ((bt
& 0x01) == 0) bits
++;
393 if (bits
> topbits
) {
395 // Copy the winning mask
396 memcpy(mask
, tmp_mask
, 16);
399 // Ignore states under 90
401 // Make sure the bits are used for ordering
402 bincstates
[(((uint64_t)bits
) << 56) | counter
] = counter
;
405 if ((counter
& 0xfffff) == 0) {
412 // Clear the candidate state vector
415 // Copy the order the states from lowest-bin to highest-bin
416 for (it
= bincstates
.begin(); it
!= bincstates
.end(); ++it
) {
417 pcrstates
->push_back(it
->second
);
419 // Reverse the vector order (so the highest bin comes first)
420 reverse(pcrstates
->begin(), pcrstates
->end());
425 static inline void previous_all_input(vector
<cs_t
> *pcstates
, uint32_t gc_byte_index
, cipher_state_side css
) {
427 vector
<cs_t
> ncstates
;
428 vector
<cs_t
> prev_ncstates
;
429 vector
<cs_t
>::iterator itnew
;
431 // Loop through the complete entryphy of 5 bits for each candidate
432 // We ignore zero (xor 0x00) to avoid duplicates
433 for (btGc
= 0; btGc
< 0x20; btGc
++) {
434 // Copy the original candidates that are supplied
435 ncstates
= *pcstates
;
437 // Rollback the (candidate) cipher states with this input
438 if (css
== CSS_RIGHT
) {
440 previous_right(in
, &ncstates
);
443 previous_left(in
, &ncstates
);
446 for (itnew
= ncstates
.begin(); itnew
!= ncstates
.end(); ++itnew
) {
447 // Wipe away the invalid states
448 if (itnew
->invalid
== false) {
449 itnew
->Gc
[gc_byte_index
] = in
;
450 prev_ncstates
.push_back(*itnew
);
455 // Copy the previous states into the vector
456 *pcstates
= prev_ncstates
;
459 static inline void search_gc_candidates_right(const uint64_t rstate_before_gc
, const uint64_t rstate_after_gc
, const uint8_t *Q
, vector
<cs_t
> *pcstates
) {
460 vector
<cs_t
>::iterator it
;
461 vector
<cs_t
> csl_cand
;
462 map
<uint64_t, uint64_t> matchbox
;
463 map
<uint64_t, uint64_t>::iterator itmatch
;
468 // Generate 2^20 different (5 bits) values for the first 4 Gc bytes (0,1,2,3)
469 for (counter
= 0; counter
< 0x100000; counter
++) {
470 rstate
= rstate_before_gc
;
471 next_right_fast((counter
>> 12) & 0xf8, &rstate
);
472 next_right_fast((counter
>> 7) & 0xf8, &rstate
);
473 next_right_fast(Q
[4], &rstate
);
474 next_right_fast((counter
>> 2) & 0xf8, &rstate
);
475 next_right_fast((counter
<< 3) & 0xf8, &rstate
);
476 next_right_fast(Q
[5], &rstate
);
477 matchbox
[rstate
] = counter
;
480 // Reset and initialize the cryptostate and vecctor
481 memset(&state
, 0x00, sizeof(cs_t
));
482 state
.invalid
= false;
483 state
.r
= rstate_after_gc
;
485 csl_cand
.push_back(state
);
487 // Generate 2^20(+splitting) different (5 bits) values for the last 4 Gc bytes (4,5,6,7)
488 previous_right(Q
[7], &csl_cand
);
489 previous_all_input(&csl_cand
, 7, CSS_RIGHT
);
490 previous_all_input(&csl_cand
, 6, CSS_RIGHT
);
491 previous_right(Q
[6], &csl_cand
);
492 previous_all_input(&csl_cand
, 5, CSS_RIGHT
);
493 previous_all_input(&csl_cand
, 4, CSS_RIGHT
);
497 // Take the intersection of the corresponding states ~2^15 values (40-25 = 15 bits)
498 for (it
= csl_cand
.begin(); it
!= csl_cand
.end(); ++it
) {
499 itmatch
= matchbox
.find(it
->r
);
500 if (itmatch
!= matchbox
.end()) {
501 it
->Gc
[0] = (itmatch
->second
>> 12) & 0xf8;
502 it
->Gc
[1] = (itmatch
->second
>> 7) & 0xf8;
503 it
->Gc
[2] = (itmatch
->second
>> 2) & 0xf8;
504 it
->Gc
[3] = (itmatch
->second
<< 3) & 0xf8;
506 printf("%07llx ",it->r);
507 printf("(%x)\n",itmatch->second);
510 if (it->r == 0xff459b)
512 print_cs("previous:",&(*it));
513 printf("%07llx\n",it->r);
514 print_bytes(it->Gc,8);
517 pcstates
->push_back(*it
);
522 static inline void sm_left(const uint8_t *ks
, const uint8_t *mask
, vector
<cs_t
> *pcstates
) {
523 map
<uint64_t, cs_t
> bincstates
;
524 map
<uint64_t, cs_t
>::iterator it
;
526 size_t pos
, bits
, bit
;
527 uint8_t correct_bits
[16];
530 lookup_entry
*lookup
;
532 // Reset and initialize the cryptostate and vecctor
533 memset(&state
, 0x00, sizeof(cs_t
));
534 state
.invalid
= false;
536 for (counter
= 0; counter
< 0x800000000ull
; counter
++) {
537 uint64_t lstate
= counter
;
539 for (pos
= 0; pos
< 16; pos
++) {
540 lstate
= (((lstate
) >> 5) | ((uint64_t)left_addition
[((lstate
) & 0xf801f)] << 30));
541 lookup
= &(lookup_left
[((lstate
) & 0xf801f)]);
542 lstate
= (((lstate
) >> 5) | ((uint64_t)lookup
->addition
<< 30));
543 bt
= lookup
->out
<< 4;
544 lstate
= (((lstate
) >> 5) | ((uint64_t)left_addition
[((lstate
) & 0xf801f)] << 30));
545 lookup
= &(lookup_left
[((lstate
) & 0xf801f)]);
546 lstate
= (((lstate
) >> 5) | ((uint64_t)lookup
->addition
<< 30));
549 // xor the bits with the keystream and count the "correct" bits
552 // When the REQUIRED bits are NOT xored away (=zero), ignore this wrong state
553 if ((bt
& mask
[pos
]) != 0) break;
555 // Save the correct bits for statistical information
556 correct_bits
[pos
] = bt
;
559 // If we have parsed all 16 bytes of keystream, we have a valid CANDIDATE!
561 // Count the total correct bits
563 for (pos
= 0; pos
< 16; pos
++) {
564 // Get the next byte-value with correct bits
565 bt
= correct_bits
[pos
];
567 // Count all the (correct) bits
568 for (bit
= 0; bit
< 8; bit
++) {
569 // When the bit is xored away (=zero), it was the same, so correct ;)
570 if ((bt
& 0x01) == 0) bits
++;
575 // Print the left candidate
576 // printf("%09llx (%d)\n",counter,bits);
581 // Make sure the bits are used for ordering
582 bincstates
[(((uint64_t)bits
) << 56) | counter
] = state
;
585 if ((counter
& 0xffffffffull
) == 0) {
586 printf("%02.1f%%.", ((float)100 / 8) * (counter
>> 32));
592 // Clear the candidate state vector
595 // Copy the order the states from lowest-bin to highest-bin
596 for (it
= bincstates
.begin(); it
!= bincstates
.end(); ++it
) {
597 pcstates
->push_back(it
->second
);
599 // Reverse the vector order (so the highest bin comes first)
600 reverse(pcstates
->begin(), pcstates
->end());
603 static inline void search_gc_candidates_left(const uint64_t lstate_before_gc
, const uint8_t *Q
, vector
<cs_t
> *pcstates
) {
604 vector
<cs_t
> csl_cand
, csl_search
;
605 vector
<cs_t
>::iterator itsearch
, itcand
;
606 map
<uint64_t, uint64_t> matchbox
;
607 map
<uint64_t, uint64_t>::iterator itmatch
;
611 // Generate 2^20 different (5 bits) values for the first 4 Gc bytes (0,1,2,3)
612 for (counter
= 0; counter
< 0x100000; counter
++) {
613 lstate
= lstate_before_gc
;
614 next_left_fast((counter
>> 15) & 0x1f, &lstate
);
615 next_left_fast((counter
>> 10) & 0x1f, &lstate
);
616 next_left_fast(Q
[4], &lstate
);
617 next_left_fast((counter
>> 5) & 0x1f, &lstate
);
618 next_left_fast(counter
& 0x1f, &lstate
);
619 next_left_fast(Q
[5], &lstate
);
620 matchbox
[lstate
] = counter
;
623 // Copy the input candidate states and clean the output vector
624 csl_cand
= *pcstates
;
627 for (itcand
= csl_cand
.begin(); itcand
!= csl_cand
.end(); ++itcand
) {
629 csl_search
.push_back(*itcand
);
631 // Generate 2^20(+splitting) different (5 bits) values for the last 4 Gc bytes (4,5,6,7)
632 previous_left(Q
[7], &csl_search
);
633 previous_all_input(&csl_search
, 7, CSS_LEFT
);
634 previous_all_input(&csl_search
, 6, CSS_LEFT
);
635 previous_left(Q
[6], &csl_search
);
636 previous_all_input(&csl_search
, 5, CSS_LEFT
);
637 previous_all_input(&csl_search
, 4, CSS_LEFT
);
639 // Take the intersection of the corresponding states ~2^15 values (40-25 = 15 bits)
640 for (itsearch
= csl_search
.begin(); itsearch
!= csl_search
.end(); ++itsearch
) {
641 itmatch
= matchbox
.find(itsearch
->l
);
642 if (itmatch
!= matchbox
.end()) {
643 itsearch
->Gc
[0] = (itmatch
->second
>> 15) & 0x1f;
644 itsearch
->Gc
[1] = (itmatch
->second
>> 10) & 0x1f;
645 itsearch
->Gc
[2] = (itmatch
->second
>> 5) & 0x1f;
646 itsearch
->Gc
[3] = itmatch
->second
& 0x1f;
649 printf("%07llx ",it->l);
650 printf("(%x) ",itmatch->second);
654 if (itsearch->l == 0x405162420ull)
656 print_cs("previous:",&(*itsearch));
657 printf("%09llx\n",itsearch->l);
658 print_bytes(itsearch->Gc,8);
662 pcstates
->push_back(*itsearch
);
665 // printf("%09llx: ",itcand->l);
666 // printf("%d - %d\n",csl_search.size(),count);
673 void combine_valid_left_right_states(vector
<cs_t
> *plcstates
, vector
<cs_t
> *prcstates
, vector
<uint64_t> *pgc_candidates
) {
674 vector
<cs_t
>::iterator itl
, itr
;
679 // Clean up the candidate list
680 pgc_candidates
->clear();
681 for (itl
= plcstates
->begin(); itl
!= plcstates
->end(); ++itl
) {
682 for (itr
= prcstates
->begin(); itr
!= prcstates
->end(); ++itr
) {
684 // Check for left and right candidates that share the overlapping bits (8 x 2bits of Gc)
685 for (pos
= 0; pos
< 8; pos
++) {
686 if ((itl
->Gc
[pos
] & 0x18) != (itr
->Gc
[pos
] & 0x18)) {
694 for (pos
= 0; pos
< 8; pos
++) {
696 gc
|= (itl
->Gc
[pos
] | itr
->Gc
[pos
]);
698 // printf("%016llx\n",gc);
699 pgc_candidates
->push_back(gc
);
700 // printf("%09llx - ",itl->l);
701 // printf("%07llx\n",itr->r);
705 printf("Found a total of " _YELLOW_("%llu")" combinations, ", ((unsigned long long)plcstates
->size()) * prcstates
->size());
706 printf("but only " _GREEN_("%zu")" were valid!\n", pgc_candidates
->size());
709 int main(int argc
, const char *argv
[]) {
711 crypto_state_t ostate
;
712 uint64_t rstate_before_gc
, lstate_before_gc
;
713 vector
<uint64_t> rstates
, pgc_candidates
;
714 vector
<uint64_t>::iterator itrstates
, itgc
;
715 vector
<cs_t
> crstates
;
716 vector
<cs_t
> clstates
;
719 // uint8_t Gc[ 8] = {0x4f,0x79,0x4a,0x46,0x3f,0xf8,0x1d,0x81};
720 // uint8_t Gc[ 8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
721 // uint8_t Ci[ 8] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
722 // uint8_t Q[ 8] = {0x12,0x34,0x56,0x78,0x12,0x34,0x56,0x78};
731 uint8_t Ci_1_chk
[ 8];
733 // uint8_t ks[16] = {0xde,0x88,0xc2,0xc9,0xee,0xd4,0x1b,0x46,0x1c,0x6a,0x92,0x50,0x76,0x1a,0xe9,0x87};
734 // uint8_t mask[16] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
735 // uint8_t mask[16] = {0x04,0xb0,0xe1,0x10,0xc0,0x33,0x44,0x20,0x20,0x00,0x70,0x8c,0x22,0x04,0x10,0x80};
740 uint64_t nCi
; // Card random
741 uint64_t nQ
; // Reader random
742 uint64_t nCh
; // Reader challenge
743 uint64_t nCi_1
; // Card answer
745 if ((argc
!= 2) && (argc
!= 5)) {
746 printf("SecureMemory recovery - (c) Radboud University Nijmegen\n\n");
747 printf("syntax: sma simulate\n");
748 printf(" sma <Ci> <Q> <Ch> <Ci+1>\n\n");
752 printf(_CYAN_("\nAuthentication info\n\n"));
754 // Check if this is a simulation
756 // Generate random values for the key and randoms
757 srand((uint32_t)time(NULL
));
758 for (pos
= 0; pos
< 8; pos
++) {
763 sm_auth(Gc
, Ci
, Q
, Ch
, Ci_1
, &ostate
);
767 sscanf(argv
[1], "%016" SCNx64
, &nCi
);
768 num_to_bytes(nCi
, 8, Ci
);
769 sscanf(argv
[2], "%016" SCNx64
, &nQ
);
770 num_to_bytes(nQ
, 8, Q
);
771 sscanf(argv
[3], "%016" SCNx64
, &nCh
);
772 num_to_bytes(nCh
, 8, Ch
);
773 sscanf(argv
[4], "%016" SCNx64
, &nCi_1
);
774 num_to_bytes(nCi_1
, 8, Ci_1
);
775 printf(" Gc... unknown\n");
778 for (pos
= 0; pos
< 8; pos
++) {
779 ks
[2 * pos
] = Ci_1
[pos
];
780 ks
[(2 * pos
) + 1] = Ch
[pos
];
790 print_bytes(Ci_1
, 8);
796 printf("Initializing lookup tables for increasing cipher speed\n");
799 init_lookup_left_subtraction();
800 init_lookup_right_subtraction();
802 // Load in the ci (tag-nonce), together with the first half of Q (reader-nonce)
803 rstate_before_gc
= 0;
804 lstate_before_gc
= 0;
805 for (pos
= 0; pos
< 4; pos
++) {
806 next_right_fast(Ci
[2 * pos
], &rstate_before_gc
);
807 next_right_fast(Ci
[2 * pos
+ 1], &rstate_before_gc
);
808 next_right_fast(Q
[pos
], &rstate_before_gc
);
810 next_left_fast(Ci
[2 * pos
], &lstate_before_gc
);
811 next_left_fast(Ci
[2 * pos
+ 1], &lstate_before_gc
);
812 next_left_fast(Q
[pos
], &lstate_before_gc
);
815 printf("Determing the right states that correspond to the keystream\n");
816 rbits
= sm_right(ks
, mask
, &rstates
);
817 printf("Top-bin for the right state contains " _GREEN_("%u")" correct bits\n", rbits
);
818 printf("Total count of right bins: " _YELLOW_("%lu") "\n", (unsigned long)rstates
.size());
821 printf(_RED_("\n WARNING!!! Better find another trace, the right top-bin is < 96 bits\n\n"));
824 for (itrstates
= rstates
.begin(); itrstates
!= rstates
.end(); ++itrstates
) {
825 uint64_t rstate_after_gc
= *itrstates
;
826 sm_left_mask(ks
, mask
, rstate_after_gc
);
827 printf("Using the state from the top-right bin: " _YELLOW_("0x%07" PRIx64
)"\n", rstate_after_gc
);
829 search_gc_candidates_right(rstate_before_gc
, rstate_after_gc
, Q
, &crstates
);
830 printf("Found " _YELLOW_("%zu")" right candidates using the meet-in-the-middle attack\n", crstates
.size());
831 if (crstates
.size() == 0) continue;
833 printf("Calculating left states using the (unknown bits) mask from the top-right state\n");
834 sm_left(ks
, mask
, &clstates
);
835 printf("Found a total of " _YELLOW_("%zu")" left cipher states, recovering left candidates...\n", clstates
.size());
836 if (clstates
.size() == 0) continue;
838 search_gc_candidates_left(lstate_before_gc
, Q
, &clstates
);
839 printf("The meet-in-the-middle attack returned " _YELLOW_("%zu")" left cipher candidates\n", clstates
.size());
840 if (clstates
.size() == 0) continue;
842 printf("Combining left and right states, disposing invalid combinations\n");
843 combine_valid_left_right_states(&clstates
, &crstates
, &pgc_candidates
);
845 printf("Filtering the correct one using the middle part\n");
846 for (itgc
= pgc_candidates
.begin(); itgc
!= pgc_candidates
.end(); ++itgc
) {
847 num_to_bytes(*itgc
, 8, Gc_chk
);
848 sm_auth(Gc_chk
, Ci
, Q
, Ch_chk
, Ci_1_chk
, &ostate
);
849 if ((memcmp(Ch_chk
, Ch
, 8) == 0) && (memcmp(Ci_1_chk
, Ci_1
, 8) == 0)) {
850 printf("\nValid key found [ " _GREEN_("%016" PRIx64
)" ]\n\n", *itgc
);
854 printf(_RED_("Could not find key using this right cipher state.\n\n"));
859 #if defined(__cplusplus)