3 * SecureMemory recovery Multithread
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
30 #include <algorithm> // sort, max_element, random_shuffle, remove_if, lower_bound
31 #include <functional> // greater, bind2nd
32 #include <thread> // std::thread
35 #include "cryptolib.h"
45 // avoid scanf warnings in Visual Studio
46 #define _CRT_SECURE_NO_WARNINGS
47 #define _CRT_SECURE_NO_DEPRECATE
48 #define inline __inline
52 >./sm 4f794a463ff81d81 ffffffffffffffff 1234567812345678
53 SecureMemory simulator - (c) Radboud University Nijmegen
56 Gc: 4f 79 4a 46 3f f8 1d 81
57 Ci: ff ff ff ff ff ff ff ff
58 Q: 12 34 56 78 12 34 56 78
59 Ch: 88 c9 d4 46 6a 50 1a 87
60 Ci+1: de c2 ee 1b 1c 92 76 e9
62 Ks: de 88 c2 c9 ee d4 1b 46 1c 6a 92 50 76 1a e9 87
112 const uint64_t left_candidates[43] = {
113 0x6221539d9ull, 0x1ddeac626ull, 0x7cc847482ull, 0x0337b8b7dull,
114 0x159d1687eull, 0x7bade8a41ull, 0x4c51c6463ull, 0x4e3d88bf9ull,
115 0x4e3d88819ull, 0x31c2777e6ull, 0x31c277406ull, 0x0059ff7d5ull,
116 0x5fb612b96ull, 0x2049ed469ull, 0x0452175beull, 0x00d2ff4edull,
117 0x68918cba9ull, 0x03a6f882aull, 0x7086372b6ull, 0x6c9a11672ull,
118 0x60531191aull, 0x4ba9b653full, 0x4ba9b6520ull, 0x1facee6e5ull,
119 0x0f79c8d49ull, 0x0b29f2a5bull, 0x032df8b12ull, 0x7c90849f8ull,
120 0x48916e84eull, 0x176e73456ull, 0x036f7b607ull, 0x5b2aeb858ull,
121 0x51c8755b5ull, 0x4c9432733ull, 0x0f6c834fbull, 0x03b2ff59bull,
122 0x0f78aac5bull, 0x3770cdaf3ull, 0x205078bbaull, 0x04445c715ull,
123 0x004df8a64ull, 0x6f696e09eull, 0x109691f61ull
146 enum cipher_state_side
{
151 void print_cs(const char *text
, pcs s
) {
156 for (pos
= 6; pos
>= 0; pos
--)
157 printf(" %02x", (uint8_t)(s
->l
>> (pos
* 5)) & 0x1f);
160 for (pos
= 6; pos
>= 0; pos
--)
161 printf(" %02x", (uint8_t)(s
->m
>> (pos
* 7)) & 0x7f);
165 for (pos
= 4; pos
>= 0; pos
--)
166 printf(" %02x", (uint8_t)(s
->r
>> (pos
* 5)) & 0x1f);
171 static inline uint8_t mod(uint8_t a
, uint8_t m
) {
173 return 0; // Actually, divide by zero error
176 // Just return the input when this is less or equal than the modular value
179 // Compute the modular value
182 // Return the funny value, when the output was now zero, return the modular value
183 return (a
== 0) ? m
: a
;
187 static inline uint8_t bit_rotate_l(uint8_t a, uint8_t n_bits) {
188 // Rotate value a with the length of n_bits only 1 time
189 uint8_t mask = (1 << n_bits) - 1;
190 return ((a << 1) | (a >> (n_bits - 1))) & mask;
193 static inline uint8_t bit_rotate_r(uint8_t a, uint8_t n_bits) {
194 return ((a >> 1) | ((a&1) << (n_bits - 1)));
198 #define BIT_ROL_MASK ((1 << 5) - 1)
199 #define BIT_ROL(a) ((((a) << 1) | ((a) >> 4)) & BIT_ROL_MASK)
200 #define BIT_ROR(a) (((a) >> 1) | (((a) & 1) << 4))
203 static uint8_t lookup_left_subtraction
[0x400];
204 static uint8_t lookup_right_subtraction
[0x400];
205 static lookup_entry lookup_left
[0x100000];
206 static lookup_entry lookup_right
[0x8000];
207 static uint8_t left_addition
[0x100000];
209 static inline void init_lookup_left() {
210 for (int i
= 0; i
< 0x400; i
++) {
211 uint8_t b6
= i
& 0x1f;
212 uint8_t b3
= (i
>> 5) & 0x1f;
213 int index
= (b3
<< 15) | b6
;
215 // b6 = bit_rotate_l(b6, 5);
218 uint8_t temp
= mod(b3
+ b6
, 0x1f);
219 left_addition
[index
] = temp
;
220 lookup_left
[index
].addition
= temp
;
221 lookup_left
[index
].out
= ((temp
^ b3
) & 0x0f);
225 static inline void init_lookup_right() {
226 for (int i
= 0; i
< 0x400; i
++) {
227 uint8_t b18
= i
& 0x1f;
228 uint8_t b16
= (i
>> 5) & 0x1f;
229 int index
= (b16
<< 10) | b18
;
231 uint8_t temp
= mod(b18
+ b16
, 0x1f);
232 lookup_right
[index
].addition
= temp
;
233 lookup_right
[index
].out
= ((temp
^ b16
) & 0x0f);
237 static void init_lookup_left_subtraction() {
238 for (int index
= 0; index
< 0x400 ; index
++) {
239 uint8_t b3
= (index
>> 5 & 0x1f);
240 uint8_t bx
= (index
& 0x1f);
242 //lookup_left_subtraction[index] = bit_rotate_r(mod((bx+0x1f)-b3,0x1f),5);
243 lookup_left_subtraction
[index
] = BIT_ROR(mod((bx
+ 0x1F) - b3
, 0x1F));
247 static void init_lookup_right_subtraction() {
248 for (int index
= 0; index
< 0x400 ; index
++) {
249 int b16
= (index
>> 5);
250 uint8_t bx
= (index
& 0x1f);
251 lookup_right_subtraction
[index
] = mod((bx
+ 0x1F) - b16
, 0x1F);
255 static inline void previous_left(uint8_t in
, vector
<cs_t
> *candidate_states
) {
257 size_t size
= candidate_states
->size();
258 for (size_t pos
= 0; pos
< size
; pos
++) {
259 state
= &((*candidate_states
)[pos
]);
261 uint8_t bx
= (uint8_t)((state
->l
>> 30) & 0x1f);
262 unsigned b3
= (unsigned)(state
->l
>> 5) & 0x3e0;
263 state
->l
= (state
->l
<< 5);
265 //Ignore impossible states
267 // Are we dealing with an impossible state?
269 state
->invalid
= true;
271 // We only need to consider b6=0
272 state
->l
&= 0x7ffffffe0ull
;
273 state
->l
^= (((uint64_t)in
& 0x1f) << 20);
276 uint8_t b6
= lookup_left_subtraction
[b3
| bx
];
277 state
->l
= (state
->l
& 0x7ffffffe0ull
) | b6
;
278 state
->l
^= (((uint64_t)in
& 0x1f) << 20);
280 // Check if we have a second candidate
282 cs_t nstate
= *state
;
283 nstate
.l
&= 0x7ffffffe0ull
;
284 candidate_states
->push_back(nstate
);
290 static inline void previous_right(uint8_t in
, vector
<cs_t
> *candidate_states
) {
292 size_t size
= candidate_states
->size();
293 for (size_t pos
= 0; pos
< size
; pos
++) {
294 state
= &((*candidate_states
)[pos
]);
296 uint8_t bx
= (uint8_t)((state
->r
>> 20) & 0x1f);
297 unsigned b16
= (unsigned)(state
->r
& 0x3e0);//(state->buffer_r >> 10) & 0x1f;
299 state
->r
= (state
->r
<< 5);
301 // Ignore impossible states
304 state
->invalid
= true;
306 // We only need to consider b18=0
307 state
->r
&= 0x1ffffe0ull
;
308 state
->r
^= (((uint64_t)in
& 0xf8) << 12);
311 uint8_t b18
= lookup_right_subtraction
[b16
| bx
];
312 state
->r
= (state
->r
& 0x1ffffe0ull
) | b18
;
313 state
->r
^= (((uint64_t)in
& 0xf8) << 12);
314 //state->b_right = ((b14^b17) & 0x0f);
316 // Check if we have a second candidate
318 cs_t nstate
= *state
;
319 nstate
.r
&= 0x1ffffe0ull
;
320 candidate_states
->push_back(nstate
);
326 static inline uint8_t next_left_fast(uint8_t in
, uint64_t *left
) {
328 *left
^= ((in
& 0x1f) << 20);
330 lookup_entry
*lookup
= &(lookup_left
[((*left
) & 0xf801f)]);
331 *left
= (((*left
) >> 5) | ((uint64_t)lookup
->addition
<< 30));
335 static inline uint8_t next_right_fast(uint8_t in
, uint64_t *right
) {
336 if (in
) *right
^= ((in
& 0xf8) << 12);
337 lookup_entry
*lookup
= &(lookup_right
[((*right
) & 0x7c1f)]);
338 *right
= (((*right
) >> 5) | (lookup
->addition
<< 20));
342 static inline void sm_left_mask(const uint8_t *ks
, uint8_t *mask
, uint64_t rstate
) {
343 for (uint8_t pos
= 0; pos
< 16; pos
++) {
344 next_right_fast(0, &rstate
);
345 uint8_t bt
= next_right_fast(0, &rstate
) << 4;
346 next_right_fast(0, &rstate
);
347 bt
|= next_right_fast(0, &rstate
);
349 // xor the bits with the keystream and count the "correct" bits
352 // Save the mask for the left produced bits
358 std::atomic
<bool> key_found
{0};
359 std::atomic
<uint64_t> key
{0};
360 std::atomic
<size_t> g_topbits
{0};
361 std::mutex g_ice_mtx
;
362 static uint32_t g_num_cpus
= std::thread::hardware_concurrency();
364 static void ice_sm_right_thread(
368 map
<uint64_t, uint64_t> *bincstates
,
372 uint8_t tmp_mask
[16];
375 for (uint64_t counter
= offset
; counter
< 0x2000000; counter
+= skips
) {
376 // Reset the current bitcount of correct bits
379 // Copy the state we are going to test
380 uint64_t rstate
= counter
;
382 for (uint8_t pos
= 0; pos
< 16; pos
++) {
384 next_right_fast(0, &rstate
);
386 bt
= next_right_fast(0, &rstate
) << 4;
388 next_right_fast(0, &rstate
);
390 bt
|= next_right_fast(0, &rstate
);
392 // xor the bits with the keystream and count the "correct" bits
395 // Save the mask for the left produced bits
398 // When the bit is xored away (=zero), it was the same, so correct ;)
399 if ((bt
& 0x01) == 0) bits
++;
400 if (((bt
>> 1) & 0x01) == 0) bits
++;
401 if (((bt
>> 2) & 0x01) == 0) bits
++;
402 if (((bt
>> 3) & 0x01) == 0) bits
++;
403 if (((bt
>> 4) & 0x01) == 0) bits
++;
404 if (((bt
>> 5) & 0x01) == 0) bits
++;
405 if (((bt
>> 6) & 0x01) == 0) bits
++;
406 if (((bt
>> 7) & 0x01) == 0) bits
++;
410 if (bits
> g_topbits
.load(std::memory_order_relaxed
)) {
411 // Copy the winning mask
413 memcpy(mask
, tmp_mask
, 16);
417 // Ignore states under 90
419 // Make sure the bits are used for ordering
421 if (bincstates
->find((((uint64_t)bits
) << 56) | counter
) != bincstates
->end())
422 bincstates
->at((((uint64_t)bits
) << 56) | counter
) = counter
;
424 bincstates
->insert(std::pair
<uint64_t, uint64_t>((((uint64_t)bits
) << 56) | counter
, counter
));
428 if ((counter
& 0xfffff) == 0) {
436 static uint32_t ice_sm_right(const uint8_t *ks
, uint8_t *mask
, vector
<uint64_t> *pcrstates
) {
438 map
<uint64_t, uint64_t> bincstates
;
441 std::vector
<std::thread
> threads(g_num_cpus
);
442 for (uint32_t m
= 0; m
< g_num_cpus
; m
++) {
443 threads
[m
] = std::thread(ice_sm_right_thread
, m
, g_num_cpus
, ks
, &bincstates
, mask
);
445 for (auto &t
: threads
) {
451 // Clear the candidate state vector
454 // Copy the order the states from lowest-bin to highest-bin
455 map
<uint64_t, uint64_t>::iterator it
;
456 for (it
= bincstates
.begin(); it
!= bincstates
.end(); ++it
) {
457 pcrstates
->push_back(it
->second
);
460 // Reverse the vector order (so the highest bin comes first)
461 reverse(pcrstates
->begin(), pcrstates
->end());
466 static void ice_sm_left_thread(
470 map
<uint64_t, cs_t
> *bincstates
,
475 uint8_t correct_bits
[16];
477 lookup_entry
*lookup
;
479 // Reset and initialize the cryptostate and vector
481 memset(&state
, 0x00, sizeof(cs_t
));
482 state
.invalid
= false;
484 for (uint64_t counter
= offset
; counter
< 0x800000000ull
; counter
+= skips
) {
485 uint64_t lstate
= counter
;
487 for (pos
= 0; pos
< 16; pos
++) {
489 lstate
= (((lstate
) >> 5) | ((uint64_t)left_addition
[((lstate
) & 0xf801f)] << 30));
490 lookup
= &(lookup_left
[((lstate
) & 0xf801f)]);
491 lstate
= (((lstate
) >> 5) | ((uint64_t)lookup
->addition
<< 30));
492 bt
= lookup
->out
<< 4;
493 lstate
= (((lstate
) >> 5) | ((uint64_t)left_addition
[((lstate
) & 0xf801f)] << 30));
494 lookup
= &(lookup_left
[((lstate
) & 0xf801f)]);
495 lstate
= (((lstate
) >> 5) | ((uint64_t)lookup
->addition
<< 30));
498 // xor the bits with the keystream and count the "correct" bits
501 // When the REQUIRED bits are NOT xored away (=zero), ignore this wrong state
502 if ((bt
& mask
[pos
]) != 0) break;
504 // Save the correct bits for statistical information
505 correct_bits
[pos
] = bt
;
508 // If we have parsed all 16 bytes of keystream, we have a valid CANDIDATE!
510 // Count the total correct bits
512 for (pos
= 0; pos
< 16; pos
++) {
513 // Get the next byte-value with correct bits
514 bt
= correct_bits
[pos
];
516 // Count all the (correct) bits
517 // When the bit is xored away (=zero), it was the same, so correct ;)
518 if ((bt
& 0x01) == 0) bits
++;
519 if (((bt
>> 1) & 0x01) == 0) bits
++;
520 if (((bt
>> 2) & 0x01) == 0) bits
++;
521 if (((bt
>> 3) & 0x01) == 0) bits
++;
522 if (((bt
>> 4) & 0x01) == 0) bits
++;
523 if (((bt
>> 5) & 0x01) == 0) bits
++;
524 if (((bt
>> 6) & 0x01) == 0) bits
++;
525 if (((bt
>> 7) & 0x01) == 0) bits
++;
530 // Make sure the bits are used for ordering
534 if (bincstates
->find((((uint64_t)bits
) << 56) | counter
) != bincstates
->end())
535 bincstates
->at((((uint64_t)bits
) << 56) | counter
) = state
;
537 bincstates
->insert(std::pair
<uint64_t, cs_t
>((((uint64_t)bits
) << 56) | counter
, state
));
542 if ((counter
& 0xffffffffull
) == 0) {
544 printf("%02.1f%%.", ((float)100 / 8) * (counter
>> 32));
551 static void ice_sm_left(const uint8_t *ks
, uint8_t *mask
, vector
<cs_t
> *pcstates
) {
553 map
<uint64_t, cs_t
> bincstates
;
554 std::vector
<std::thread
> threads(g_num_cpus
);
555 for (uint32_t m
= 0; m
< g_num_cpus
; m
++) {
556 threads
[m
] = std::thread(ice_sm_left_thread
, m
, g_num_cpus
, ks
, &bincstates
, mask
);
559 for (auto &t
: threads
) {
565 // Clear the candidate state vector
568 // Copy the order the states from lowest-bin to highest-bin
569 map
<uint64_t, cs_t
>::iterator it
;
570 for (it
= bincstates
.begin(); it
!= bincstates
.end(); ++it
) {
571 pcstates
->push_back(it
->second
);
573 // Reverse the vector order (so the highest bin comes first)
574 reverse(pcstates
->begin(), pcstates
->end());
577 static inline void previous_all_input(vector
<cs_t
> *pcstates
, uint32_t gc_byte_index
, cipher_state_side css
) {
579 vector
<cs_t
> ncstates
;
580 vector
<cs_t
> prev_ncstates
;
581 vector
<cs_t
>::iterator itnew
;
583 // Loop through the complete entryphy of 5 bits for each candidate
584 // We ignore zero (xor 0x00) to avoid duplicates
585 for (btGc
= 0; btGc
< 0x20; btGc
++) {
586 // Copy the original candidates that are supplied
587 ncstates
= *pcstates
;
589 // Rollback the (candidate) cipher states with this input
590 if (css
== CSS_RIGHT
) {
592 previous_right(in
, &ncstates
);
595 previous_left(in
, &ncstates
);
598 for (itnew
= ncstates
.begin(); itnew
!= ncstates
.end(); ++itnew
) {
599 // Wipe away the invalid states
600 if (itnew
->invalid
== false) {
601 itnew
->Gc
[gc_byte_index
] = in
;
602 prev_ncstates
.push_back(*itnew
);
607 // Copy the previous states into the vector
608 *pcstates
= prev_ncstates
;
611 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
) {
612 vector
<cs_t
>::iterator it
;
613 vector
<cs_t
> csl_cand
;
614 map
<uint64_t, uint64_t> matchbox
;
615 map
<uint64_t, uint64_t>::iterator itmatch
;
620 // Generate 2^20 different (5 bits) values for the first 4 Gc bytes (0,1,2,3)
621 for (counter
= 0; counter
< 0x100000; counter
++) {
622 rstate
= rstate_before_gc
;
623 next_right_fast((counter
>> 12) & 0xf8, &rstate
);
624 next_right_fast((counter
>> 7) & 0xf8, &rstate
);
625 next_right_fast(Q
[4], &rstate
);
626 next_right_fast((counter
>> 2) & 0xf8, &rstate
);
627 next_right_fast((counter
<< 3) & 0xf8, &rstate
);
628 next_right_fast(Q
[5], &rstate
);
629 matchbox
[rstate
] = counter
;
632 // Reset and initialize the cryptostate and vecctor
633 memset(&state
, 0x00, sizeof(cs_t
));
634 state
.invalid
= false;
635 state
.r
= rstate_after_gc
;
637 csl_cand
.push_back(state
);
639 // Generate 2^20(+splitting) different (5 bits) values for the last 4 Gc bytes (4,5,6,7)
640 previous_right(Q
[7], &csl_cand
);
641 previous_all_input(&csl_cand
, 7, CSS_RIGHT
);
642 previous_all_input(&csl_cand
, 6, CSS_RIGHT
);
643 previous_right(Q
[6], &csl_cand
);
644 previous_all_input(&csl_cand
, 5, CSS_RIGHT
);
645 previous_all_input(&csl_cand
, 4, CSS_RIGHT
);
649 // Take the intersection of the corresponding states ~2^15 values (40-25 = 15 bits)
650 for (it
= csl_cand
.begin(); it
!= csl_cand
.end(); ++it
) {
651 itmatch
= matchbox
.find(it
->r
);
652 if (itmatch
!= matchbox
.end()) {
653 it
->Gc
[0] = (itmatch
->second
>> 12) & 0xf8;
654 it
->Gc
[1] = (itmatch
->second
>> 7) & 0xf8;
655 it
->Gc
[2] = (itmatch
->second
>> 2) & 0xf8;
656 it
->Gc
[3] = (itmatch
->second
<< 3) & 0xf8;
658 pcstates
->push_back(*it
);
663 static inline void search_gc_candidates_left(const uint64_t lstate_before_gc
, const uint8_t *Q
, vector
<cs_t
> *pcstates
) {
664 vector
<cs_t
> csl_cand
, csl_search
;
665 vector
<cs_t
>::iterator itsearch
, itcand
;
666 map
<uint64_t, uint64_t> matchbox
;
667 map
<uint64_t, uint64_t>::iterator itmatch
;
671 // Generate 2^20 different (5 bits) values for the first 4 Gc bytes (0,1,2,3)
672 for (counter
= 0; counter
< 0x100000; counter
++) {
673 lstate
= lstate_before_gc
;
674 next_left_fast((counter
>> 15) & 0x1f, &lstate
);
675 next_left_fast((counter
>> 10) & 0x1f, &lstate
);
676 next_left_fast(Q
[4], &lstate
);
677 next_left_fast((counter
>> 5) & 0x1f, &lstate
);
678 next_left_fast(counter
& 0x1f, &lstate
);
679 next_left_fast(Q
[5], &lstate
);
680 matchbox
[lstate
] = counter
;
683 // Copy the input candidate states and clean the output vector
684 csl_cand
= *pcstates
;
687 for (itcand
= csl_cand
.begin(); itcand
!= csl_cand
.end(); ++itcand
) {
689 csl_search
.push_back(*itcand
);
691 // Generate 2^20(+splitting) different (5 bits) values for the last 4 Gc bytes (4,5,6,7)
692 previous_left(Q
[7], &csl_search
);
693 previous_all_input(&csl_search
, 7, CSS_LEFT
);
694 previous_all_input(&csl_search
, 6, CSS_LEFT
);
695 previous_left(Q
[6], &csl_search
);
696 previous_all_input(&csl_search
, 5, CSS_LEFT
);
697 previous_all_input(&csl_search
, 4, CSS_LEFT
);
699 // Take the intersection of the corresponding states ~2^15 values (40-25 = 15 bits)
700 for (itsearch
= csl_search
.begin(); itsearch
!= csl_search
.end(); ++itsearch
) {
701 itmatch
= matchbox
.find(itsearch
->l
);
702 if (itmatch
!= matchbox
.end()) {
703 itsearch
->Gc
[0] = (itmatch
->second
>> 15) & 0x1f;
704 itsearch
->Gc
[1] = (itmatch
->second
>> 10) & 0x1f;
705 itsearch
->Gc
[2] = (itmatch
->second
>> 5) & 0x1f;
706 itsearch
->Gc
[3] = itmatch
->second
& 0x1f;
708 pcstates
->push_back(*itsearch
);
717 void combine_valid_left_right_states(vector
<cs_t
> *plcstates
, vector
<cs_t
> *prcstates
, vector
<uint64_t> *pgc_candidates
) {
718 vector
<cs_t
>::iterator itl
, itr
;
723 vector
<cs_t
> outer
, inner
;
724 if (plcstates
->size() > prcstates
->size()) {
732 printf("Outer " _YELLOW_("%zu")" , inner " _YELLOW_("%zu") "\n", outer
.size(), inner
.size());
734 // Clean up the candidate list
735 pgc_candidates
->clear();
736 for (itl
= outer
.begin(); itl
!= outer
.end(); ++itl
) {
737 for (itr
= inner
.begin(); itr
!= inner
.end(); ++itr
) {
739 // Check for left and right candidates that share the overlapping bits (8 x 2bits of Gc)
740 for (pos
= 0; pos
< 8; pos
++) {
741 if ((itl
->Gc
[pos
] & 0x18) != (itr
->Gc
[pos
] & 0x18)) {
749 for (pos
= 0; pos
< 8; pos
++) {
751 gc
|= (itl
->Gc
[pos
] | itr
->Gc
[pos
]);
754 pgc_candidates
->push_back(gc
);
758 printf("Found a total of " _YELLOW_("%llu")" combinations, ", ((unsigned long long)plcstates
->size()) * prcstates
->size());
759 printf("but only " _GREEN_("%zu")" were valid!\n", pgc_candidates
->size());
762 static void ice_compare(
765 vector
<uint64_t> *candidates
,
766 crypto_state_t
*ostate
,
772 uint8_t Gc_chk
[8] = {0};
773 uint8_t Ch_chk
[8] = {0};
774 uint8_t Ci_1_chk
[8] = {0};
779 ls
.b1l
= ostate
->b1l
;
780 ls
.b1r
= ostate
->b1r
;
781 ls
.b1s
= ostate
->b1s
;
786 for (std::size_t i
= offset
; i
< candidates
->size(); i
+= skips
) {
787 if (key_found
.load(std::memory_order_relaxed
))
790 uint64_t tkey
= candidates
->at(i
);
791 num_to_bytes(tkey
, 8, Gc_chk
);
793 sm_auth(Gc_chk
, Ci
, Q
, Ch_chk
, Ci_1_chk
, &ls
);
794 if ((memcmp(Ch_chk
, Ch
, 8) == 0) && (memcmp(Ci_1_chk
, Ci_1
, 8) == 0)) {
805 int main(int argc
, const char *argv
[]) {
807 crypto_state_t ostate
;
808 uint64_t rstate_before_gc
, lstate_before_gc
;
809 vector
<uint64_t> rstates
, pgc_candidates
;
810 vector
<uint64_t>::iterator itrstates
;
811 vector
<cs_t
> crstates
, clstates
;
814 // uint8_t Gc[ 8] = {0x4f,0x79,0x4a,0x46,0x3f,0xf8,0x1d,0x81};
815 // uint8_t Gc[ 8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
816 // uint8_t Ci[ 8] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
817 // uint8_t Q[ 8] = {0x12,0x34,0x56,0x78,0x12,0x34,0x56,0x78};
824 // uint8_t ks[16] = {0xde,0x88,0xc2,0xc9,0xee,0xd4,0x1b,0x46,0x1c,0x6a,0x92,0x50,0x76,0x1a,0xe9,0x87};
825 // uint8_t mask[16] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
826 // uint8_t mask[16] = {0x04,0xb0,0xe1,0x10,0xc0,0x33,0x44,0x20,0x20,0x00,0x70,0x8c,0x22,0x04,0x10,0x80};
831 uint64_t nCi
; // Card random
832 uint64_t nQ
; // Reader random
833 uint64_t nCh
; // Reader challenge
834 uint64_t nCi_1
; // Card answer
836 if ((argc
!= 2) && (argc
!= 5)) {
837 printf("SecureMemory recovery - (c) Radboud University Nijmegen\n\n");
838 printf("syntax: sma_multi simulate\n");
839 printf(" sma_multi <Ci> <Q> <Ch> <Ci+1>\n\n");
843 printf(_CYAN_("\nAuthentication info\n\n"));
845 // Check if this is a simulation
847 // Generate random values for the key and randoms
848 srand((uint32_t)time(NULL
));
849 for (pos
= 0; pos
< 8; pos
++) {
854 sm_auth(Gc
, Ci
, Q
, Ch
, Ci_1
, &ostate
);
858 sscanf(argv
[1], "%016" SCNx64
, &nCi
);
859 num_to_bytes(nCi
, 8, Ci
);
860 sscanf(argv
[2], "%016" SCNx64
, &nQ
);
861 num_to_bytes(nQ
, 8, Q
);
862 sscanf(argv
[3], "%016" SCNx64
, &nCh
);
863 num_to_bytes(nCh
, 8, Ch
);
864 sscanf(argv
[4], "%016" SCNx64
, &nCi_1
);
865 num_to_bytes(nCi_1
, 8, Ci_1
);
866 printf(" Gc... unknown\n");
869 for (pos
= 0; pos
< 8; pos
++) {
870 ks
[2 * pos
] = Ci_1
[pos
];
871 ks
[(2 * pos
) + 1] = Ch
[pos
];
881 print_bytes(Ci_1
, 8);
887 printf("\nMultithreaded, will use " _YELLOW_("%u") " threads\n", g_num_cpus
);
888 printf("Initializing lookup tables for increasing cipher speed\n");
890 std::thread
foo_left(init_lookup_left
);
891 std::thread
foo_right(init_lookup_right
);
892 std::thread
foo_leftsub(init_lookup_left_subtraction
);
893 std::thread
foo_rightsub(init_lookup_right_subtraction
);
900 // Load in the ci (tag-nonce), together with the first half of Q (reader-nonce)
901 rstate_before_gc
= 0;
902 lstate_before_gc
= 0;
904 for (pos
= 0; pos
< 4; pos
++) {
905 next_right_fast(Ci
[2 * pos
], &rstate_before_gc
);
906 next_right_fast(Ci
[2 * pos
+ 1], &rstate_before_gc
);
907 next_right_fast(Q
[pos
], &rstate_before_gc
);
909 next_left_fast(Ci
[2 * pos
], &lstate_before_gc
);
910 next_left_fast(Ci
[2 * pos
+ 1], &lstate_before_gc
);
911 next_left_fast(Q
[pos
], &lstate_before_gc
);
914 printf("Determing the right states that correspond to the keystream\n");
915 //rbits = sm_right(ks, mask, &rstates);
916 rbits
= ice_sm_right(ks
, mask
, &rstates
);
918 printf("Top-bin for the right state contains " _GREEN_("%u")" correct bits\n", rbits
);
919 printf("Total count of right bins: " _YELLOW_("%zu") "\n", rstates
.size());
922 printf("\n" _RED_("WARNING!!!") ", better find another trace, the right top-bin is smaller than 96 bits\n\n");
925 for (itrstates
= rstates
.begin(); itrstates
!= rstates
.end(); ++itrstates
) {
926 uint64_t rstate_after_gc
= *itrstates
;
927 sm_left_mask(ks
, mask
, rstate_after_gc
);
928 printf("Using the state from the top-right bin: " _YELLOW_("0x%07" PRIx64
)"\n", rstate_after_gc
);
930 search_gc_candidates_right(rstate_before_gc
, rstate_after_gc
, Q
, &crstates
);
931 printf("Found " _YELLOW_("%zu")" right candidates using the meet-in-the-middle attack\n", crstates
.size());
932 if (crstates
.size() == 0) continue;
934 printf("Calculating left states using the (unknown bits) mask from the top-right state\n");
935 //sm_left(ks, mask, &clstates);
936 ice_sm_left(ks
, mask
, &clstates
);
938 printf("Found a total of " _YELLOW_("%zu")" left cipher states, recovering left candidates...\n", clstates
.size());
939 if (clstates
.size() == 0) continue;
940 search_gc_candidates_left(lstate_before_gc
, Q
, &clstates
);
943 printf("The meet-in-the-middle attack returned " _YELLOW_("%zu")" left cipher candidates\n", clstates
.size());
944 if (clstates
.size() == 0) continue;
946 printf("Combining left and right states, disposing invalid combinations\n");
947 combine_valid_left_right_states(&clstates
, &crstates
, &pgc_candidates
);
949 printf("Filtering the correct one using the middle part\n");
954 std::vector
<std::thread
> threads(g_num_cpus
);
955 for (uint32_t m
= 0; m
< g_num_cpus
; m
++) {
956 threads
[m
] = std::thread(ice_compare
, m
, g_num_cpus
, &pgc_candidates
, &ostate
, ref(Ci
), ref(Q
), ref(Ch
), ref(Ci_1
));
959 for (auto &t
: threads
) {
964 printf("\nValid key found [ " _GREEN_("%016" PRIx64
)" ]\n\n", key
.load());
968 printf(_RED_("\nCould not find key using this right cipher state.\n\n"));
973 #if defined(__cplusplus)