├── README.md ├── aesni.h ├── build_and_test.sh └── hulk.cpp /README.md: -------------------------------------------------------------------------------- 1 | # Hulk 2 | 3 | Hulk is able to bruteforce missing bytes after a DCA attack on AES with his special ability of AES-NI 4 | 5 | Hulk makes use of the AES-NI extension to bruteforce up to 6 missing bytes of AES. 6 | 7 | # Numbers for AES Decryption - Round 10 Key (average) 8 | 9 | #### Threadripper 1950x (2 AES NI Units per Core) 10 | 11 | 4 Byte - 32 bit - aes ni 16 threads : ~0m0,459s 12 | 5 Byte - 40 bit - aes ni 16 threads : ~1m56,989s 13 | 6 Byte - 48 bit - aes ni 16 threads : ~7h 14 | 7 Byte - 56 bit - aes ni 16 threads : ~74 days 15 | 16 | #### Core i7-6700k @ 4ghz (1 AES NI Unit per Core) 17 | 18 | 4 Byte - 32 bit - aes ni 4 threads : real 0m12.053s 19 | 4 Byte - 32 bit - aes ni 8 threads : real 0m15.999s 20 | 21 | 22 | # Installation 23 | 24 | Compile and test with the given script ./build_and_test.sh or by using clang: 25 | 26 | clang++-7 hulk.cpp -O3 -march=native -fms-extensions -o hulk -lpthread -g 27 | 28 | 29 | # Usage 30 | 31 | #### ./hulk e|d input output key 10:Optional 32 | 33 | e|d - Attack (e) encryption or (d) decryption 34 | input - The to input to the AES whitebox 35 | output - The output of the AES whitebox 36 | key - The partial key retrieved by the DCA attack 37 | 38 | Mark the missing bytes with '??' 39 | 40 | 10:Optional - Handle the key as a round 10 key 41 | 42 | Hulk will calculate the round 0 key and test it against the given test vector 43 | 44 | 45 | 46 | # Example 47 | 48 | #### time ./hulk d 00000000000000000000000000000000 ac589cfe8a7ae5dd875d9786e5832400 462f8e8e6ec0fe2b1d63????9f7f???? 10 49 | 50 | Hulk v1.2 (Peter Garba 2018) 51 | [*] AES-NI is supported by this CPU! 52 | [*] Round : 10 53 | [*] Mode : Decryption 54 | [*] Key : 462F8E8E6EC0FE2B1D63??A59F?????? 55 | [*] Input : 00000000000000000000000000000000 56 | [*] Expected : ac589cfe8a7ae5dd875d9786e5832400 57 | [!] Bruteforce : 4 missing bytes 58 | [*] Byte 0 Index 10 59 | [*] Byte 1 Index 13 60 | [*] Byte 2 Index 14 61 | [*] Byte 3 Index 15 62 | [*] AES-NI Units : 32 63 | [*] Range : 00000000 - FFFFFFFF 64 | [*] Step : 07FFFFFF 65 | [*] T00 Range : 00000000 - 07FFFFFF 66 | [*] T01 Range : 08000000 - 0FFFFFFF 67 | [*] T02 Range : 10000000 - 17FFFFFF 68 | [*] T03 Range : 18000000 - 1FFFFFFF 69 | [*] T04 Range : 20000000 - 27FFFFFF 70 | [*] T05 Range : 28000000 - 2FFFFFFF 71 | [*] T06 Range : 30000000 - 37FFFFFF 72 | [*] T07 Range : 38000000 - 3FFFFFFF 73 | [*] T08 Range : 40000000 - 47FFFFFF 74 | [*] T09 Range : 48000000 - 4FFFFFFF 75 | [*] T10 Range : 50000000 - 57FFFFFF 76 | [*] T11 Range : 58000000 - 5FFFFFFF 77 | [*] T12 Range : 60000000 - 67FFFFFF 78 | [*] T13 Range : 68000000 - 6FFFFFFF 79 | [*] T14 Range : 70000000 - 77FFFFFF 80 | [*] T15 Range : 78000000 - 7FFFFFFF 81 | [*] T16 Range : 80000000 - 87FFFFFF 82 | [*] T17 Range : 88000000 - 8FFFFFFF 83 | [*] T18 Range : 90000000 - 97FFFFFF 84 | [*] T19 Range : 98000000 - 9FFFFFFF 85 | [*] T20 Range : A0000000 - A7FFFFFF 86 | [*] T21 Range : A8000000 - AFFFFFFF 87 | [*] T22 Range : B0000000 - B7FFFFFF 88 | [*] T23 Range : B8000000 - BFFFFFFF 89 | [*] T24 Range : C0000000 - C7FFFFFF 90 | [*] T25 Range : C8000000 - CFFFFFFF 91 | [*] T26 Range : D0000000 - D7FFFFFF 92 | [*] T27 Range : D8000000 - DFFFFFFF 93 | [*] T28 Range : E0000000 - E7FFFFFF 94 | [*] T29 Range : E8000000 - EFFFFFFF 95 | [*] T30 Range : F0000000 - F7FFFFFF 96 | [*] T31 Range : F8000000 - FFFFFFFF 97 | [!] T26 Key found : 3525ac10bb391d8d5f3914fe94341985 98 | [!] Round 10 Key : 462f8e8e6ec0fe2b1d63b2a59f7fcdd0 99 | [*] Output : ac589cfe8a7ae5dd875d9786e5832400 100 | [!] Valid key! 101 | 102 | 103 | real 0m0,564s 104 | user 0m17,642s 105 | sys 0m0,008s 106 | -------------------------------------------------------------------------------- /aesni.h: -------------------------------------------------------------------------------- 1 | #ifndef AESNI_H 2 | #define AESNI_H 3 | 4 | #include 5 | #include 6 | 7 | #define DO_ENC_BLOCK(m,k) \ 8 | m = _mm_xor_si128 (m, k[ 0]); \ 9 | m = _mm_aesenc_si128 (m, k[ 1]); \ 10 | m = _mm_aesenc_si128 (m, k[ 2]); \ 11 | m = _mm_aesenc_si128 (m, k[ 3]); \ 12 | m = _mm_aesenc_si128 (m, k[ 4]); \ 13 | m = _mm_aesenc_si128 (m, k[ 5]); \ 14 | m = _mm_aesenc_si128 (m, k[ 6]); \ 15 | m = _mm_aesenc_si128 (m, k[ 7]); \ 16 | m = _mm_aesenc_si128 (m, k[ 8]); \ 17 | m = _mm_aesenc_si128 (m, k[ 9]); \ 18 | m = _mm_aesenclast_si128(m, k[10]); 19 | 20 | #define DO_DEC_BLOCK(m,k) \ 21 | m = _mm_xor_si128 (m, k[10+0]); \ 22 | m = _mm_aesdec_si128 (m, k[10+1]); \ 23 | m = _mm_aesdec_si128 (m, k[10+2]); \ 24 | m = _mm_aesdec_si128 (m, k[10+3]); \ 25 | m = _mm_aesdec_si128 (m, k[10+4]); \ 26 | m = _mm_aesdec_si128 (m, k[10+5]); \ 27 | m = _mm_aesdec_si128 (m, k[10+6]); \ 28 | m = _mm_aesdec_si128 (m, k[10+7]); \ 29 | m = _mm_aesdec_si128 (m, k[10+8]); \ 30 | m = _mm_aesdec_si128 (m, k[10+9]); \ 31 | m = _mm_aesdeclast_si128(m, k[0]); 32 | 33 | #define AES_128_key_exp(k, rcon) aes_128_key_expansion(k, _mm_aeskeygenassist_si128(k, rcon)) 34 | 35 | __attribute__((always_inline)) static __m128i aes_128_key_expansion(__m128i key, __m128i keygened){ 36 | keygened = _mm_shuffle_epi32(keygened, _MM_SHUFFLE(3,3,3,3)); 37 | key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); 38 | key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); 39 | key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); 40 | return _mm_xor_si128(key, keygened); 41 | } 42 | 43 | 44 | #define AES_128_key_exp_inv(r, k, rcon) { \ 45 | __m128i k0 = _mm_xor_si128(k, _mm_slli_si128(k, 4)); \ 46 | r = _mm_xor_si128(_mm_srli_si128(_mm_aeskeygenassist_si128(k0, rcon), 12), k0); \ 47 | } 48 | 49 | __attribute__((always_inline)) static void KeyExpansionINV_Fast(__m128i key_schedule[20]) { 50 | AES_128_key_exp_inv(key_schedule[9], key_schedule[10], 0x36); 51 | AES_128_key_exp_inv(key_schedule[8], key_schedule[9] , 0x1B); 52 | AES_128_key_exp_inv(key_schedule[7], key_schedule[8] , 0x80); 53 | AES_128_key_exp_inv(key_schedule[6], key_schedule[7] , 0x40); 54 | AES_128_key_exp_inv(key_schedule[5], key_schedule[6] , 0x20); 55 | AES_128_key_exp_inv(key_schedule[4], key_schedule[5] , 0x10); 56 | AES_128_key_exp_inv(key_schedule[3], key_schedule[4] , 0x08); 57 | AES_128_key_exp_inv(key_schedule[2], key_schedule[3] , 0x04); 58 | AES_128_key_exp_inv(key_schedule[1], key_schedule[2] , 0x02); 59 | AES_128_key_exp_inv(key_schedule[0], key_schedule[1] , 0x01); 60 | } 61 | 62 | __attribute__((always_inline)) static void aes128_load_key_enc_only(const uint8_t *enc_key, __m128i *key_schedule){ 63 | key_schedule[0] = _mm_loadu_si128((const __m128i*) enc_key); 64 | key_schedule[1] = AES_128_key_exp(key_schedule[0], 0x01); 65 | key_schedule[2] = AES_128_key_exp(key_schedule[1], 0x02); 66 | key_schedule[3] = AES_128_key_exp(key_schedule[2], 0x04); 67 | key_schedule[4] = AES_128_key_exp(key_schedule[3], 0x08); 68 | key_schedule[5] = AES_128_key_exp(key_schedule[4], 0x10); 69 | key_schedule[6] = AES_128_key_exp(key_schedule[5], 0x20); 70 | key_schedule[7] = AES_128_key_exp(key_schedule[6], 0x40); 71 | key_schedule[8] = AES_128_key_exp(key_schedule[7], 0x80); 72 | key_schedule[9] = AES_128_key_exp(key_schedule[8], 0x1B); 73 | key_schedule[10] = AES_128_key_exp(key_schedule[9], 0x36); 74 | } 75 | 76 | __attribute__((always_inline)) static void aes128_load_dec_only(__m128i *key_schedule){ 77 | key_schedule[11] = _mm_aesimc_si128(key_schedule[9]); 78 | key_schedule[12] = _mm_aesimc_si128(key_schedule[8]); 79 | key_schedule[13] = _mm_aesimc_si128(key_schedule[7]); 80 | key_schedule[14] = _mm_aesimc_si128(key_schedule[6]); 81 | key_schedule[15] = _mm_aesimc_si128(key_schedule[5]); 82 | key_schedule[16] = _mm_aesimc_si128(key_schedule[4]); 83 | key_schedule[17] = _mm_aesimc_si128(key_schedule[3]); 84 | key_schedule[18] = _mm_aesimc_si128(key_schedule[2]); 85 | key_schedule[19] = _mm_aesimc_si128(key_schedule[1]); 86 | } 87 | 88 | __attribute__((always_inline)) static void aes128_load_key(const uint8_t *enc_key, __m128i *key_schedule){ 89 | aes128_load_key_enc_only(enc_key, key_schedule); 90 | 91 | key_schedule[11] = _mm_aesimc_si128(key_schedule[9]); 92 | key_schedule[12] = _mm_aesimc_si128(key_schedule[8]); 93 | key_schedule[13] = _mm_aesimc_si128(key_schedule[7]); 94 | key_schedule[14] = _mm_aesimc_si128(key_schedule[6]); 95 | key_schedule[15] = _mm_aesimc_si128(key_schedule[5]); 96 | key_schedule[16] = _mm_aesimc_si128(key_schedule[4]); 97 | key_schedule[17] = _mm_aesimc_si128(key_schedule[3]); 98 | key_schedule[18] = _mm_aesimc_si128(key_schedule[2]); 99 | key_schedule[19] = _mm_aesimc_si128(key_schedule[1]); 100 | } 101 | 102 | __attribute__((always_inline)) static void aes128_enc(__m128i *key_schedule, uint8_t *plainText,uint8_t *cipherText){ 103 | __m128i m = _mm_loadu_si128((__m128i *) plainText); 104 | 105 | DO_ENC_BLOCK(m,key_schedule); 106 | 107 | _mm_storeu_si128((__m128i *) cipherText, m); 108 | } 109 | 110 | __attribute__((always_inline)) static __m128i aes128_enc_fast(__m128i *key_schedule, __m128i plainText){ 111 | DO_ENC_BLOCK(plainText,key_schedule); 112 | 113 | return plainText; 114 | } 115 | 116 | __attribute__((always_inline)) static void aes128_dec(__m128i *key_schedule, uint8_t *cipherText,uint8_t *plainText){ 117 | __m128i m = _mm_loadu_si128((__m128i *) cipherText); 118 | 119 | DO_DEC_BLOCK(m,key_schedule); 120 | 121 | _mm_storeu_si128((__m128i *) plainText, m); 122 | } 123 | 124 | __attribute__((always_inline)) static __m128i aes128_dec_fast(__m128i *key_schedule, __m128i cipherText){ 125 | DO_DEC_BLOCK(cipherText,key_schedule); 126 | 127 | return cipherText; 128 | } 129 | 130 | #endif -------------------------------------------------------------------------------- /build_and_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # compile 4 | clang++-7 hulk.cpp -O3 -march=native -fms-extensions -o hulk -lpthread -g 5 | 6 | #./hulk e 00000000000000000000000000000000 66e94bd4ef8a2c3b884cfa59ca342b2e 00000000000000000000000000000000 7 | #./hulk d 66e94bd4ef8a2c3b884cfa59ca342b2e 00000000000000000000000000000000 00000000000000000000000000000000 8 | 9 | #./hulk e 6bc1bee22e409f96e93d7e117393172a 3ad77bb40d7a3660a89ecaf32466ef97 2b7e151628aed2a6abf7158809cf4f3c 10 | #./hulk d 3ad77bb40d7a3660a89ecaf32466ef97 6bc1bee22e409f96e93d7e117393172a 2b7e151628aed2a6abf7158809cf4f3c 11 | 12 | #time ./hulk e 00000000000000000000000000000000 a1f6258c877d5fcd8964484538bfc92c FFFFFFFFFFFFFFFFFFFFFFFF???????? 13 | #time ./hulk d a1f6258c877d5fcd8964484538bfc92c 00000000000000000000000000000000 ????FFFFFFFFFFFFFFFFFFFFFFFF???? 14 | 15 | #./hulk d 00000000000000000000000000000000 ac589cfe8a7ae5dd875d9786e5832400 3525ac10bb391d8d5f3914fe94341985 16 | #./hulk e ac589cfe8a7ae5dd875d9786e5832400 00000000000000000000000000000000 3525ac10bb391d8d5f3914fe94341985 17 | 18 | #time ./hulk d 00000000000000000000000000000000 ac589cfe8a7ae5dd875d9786e5832400 462f????6ec0fe2b1d63??a59f??cdd0 19 | #./hulk d 00000000000000000000000000000000 ac589cfe8a7ae5dd875d9786e5832400 462f8e8e6ec0fe2b1d63b2a59f7fcdd0 10 20 | 21 | # bruteforce 22 | #./hulk d 00000000000000000000000000000000 ac589cfe8a7ae5dd875d9786e5832400 462f????6ec0fe2b1d63??a59f??cdd0 10 23 | 24 | #time ./hulk d 00000000000000000000000000000000 ac589cfe8a7ae5dd875d9786e5832400 462f8e8e6ec0fe2b1d63??a59f?????? 10 25 | 26 | #time ./hulk e ac589cfe8a7ae5dd875d9786e5832400 00000000000000000000000000000000 3525ac10bb391d8d5f3914fe???????? 27 | 28 | time ./hulk d 00000000000000000000000000000000 ac589cfe8a7ae5dd875d9786e5832400 3525ac10bb391d8d5f3914fe???????? 29 | -------------------------------------------------------------------------------- /hulk.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | // aes ni 10 | #include "aesni.h" 11 | 12 | typedef struct { 13 | int ThreadID; 14 | uint64_t Min; 15 | uint64_t Max; 16 | } Range; 17 | static std::vector Ranges; 18 | 19 | typedef struct { 20 | int Index; 21 | uint8_t Value; 22 | int Shift; 23 | } BByte; 24 | static std::vector MissingBytes; 25 | 26 | 27 | static uint8_t *CHRHEX = (uint8_t *) 28 | "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" \ 29 | "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" \ 30 | "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" \ 31 | "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\xFF\xFF\xFF\xFF\xFF\xFF" \ 32 | "\xFF\x0A\x0B\x0C\x0D\x0E\x0F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" \ 33 | "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" \ 34 | "\xFF\x0A\x0B\x0C\x0D\x0E\x0F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" \ 35 | "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" \ 36 | "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" \ 37 | "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" \ 38 | "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" \ 39 | "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" \ 40 | "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" \ 41 | "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" \ 42 | "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" \ 43 | "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"; 44 | 45 | 46 | static bool GetNNICapability() 47 | { 48 | unsigned int b; 49 | 50 | __asm 51 | { 52 | mov eax, 1 53 | cpuid 54 | mov b, ecx 55 | } 56 | 57 | return (b & (1 << 25)) != 0; 58 | } 59 | 60 | static void phex(uint8_t* str) 61 | { 62 | unsigned char i; 63 | for(i = 0; i < 16; ++i) 64 | printf("%.2x", str[i]); 65 | printf("\n"); 66 | } 67 | 68 | static void parseInput(char *I, uint8_t *Out) { 69 | int n=0; 70 | const uint8_t *p; 71 | const uint8_t *D; 72 | uint8_t c=0, e, *d; 73 | p = (const uint8_t *) I; 74 | d = Out; 75 | D = (d + 16); 76 | for (; d != D && *p; p++) { 77 | e = CHRHEX [(int) *p]; 78 | if (e != 0xFF) { 79 | c = ((c << 4) | e); 80 | n++; 81 | if (n == 2) { 82 | *(d++) = c; 83 | n = 0; 84 | } 85 | } 86 | } 87 | } 88 | 89 | static void parseKey(char *I, uint8_t *Out) { 90 | int n=0; 91 | const uint8_t *p; 92 | const uint8_t *D; 93 | uint8_t c=0, e, *d; 94 | p = (const uint8_t *) I; 95 | d = Out; 96 | D = (d + 16); 97 | int Index = 0; 98 | for (; d != D && *p; p++) { 99 | if (*p == '?') { 100 | // Unknown Byte 101 | BByte BB; 102 | BB.Index = Index; 103 | BB.Value = 0; 104 | BB.Shift = MissingBytes.size() * 8; 105 | MissingBytes.push_back(BB); 106 | 107 | p++; 108 | *d = 0; 109 | d++; 110 | n = 0; 111 | Index++; 112 | } else { 113 | e = CHRHEX [(int) *p]; 114 | if (e != 0xFF) { 115 | c = ((c << 4) | e); 116 | n++; 117 | if (n == 2) { 118 | *(d++) = c; 119 | n = 0; 120 | Index++; 121 | } 122 | } 123 | } 124 | } 125 | } 126 | 127 | __attribute__((always_inline)) static bool CompareResult(const uint8_t *A, const uint8_t *B) { 128 | return !memcmp(A,B,16); 129 | } 130 | 131 | __attribute__((always_inline)) static void EncryptNI(uint8_t *I, const uint8_t *K) { 132 | __m128i key_schedule[11]; 133 | aes128_load_key_enc_only(K,key_schedule); 134 | aes128_enc(key_schedule,I,I); 135 | } 136 | 137 | __attribute__((always_inline)) static void DecryptNI(uint8_t *I, const uint8_t *K) { 138 | __m128i key_schedule[20]; 139 | aes128_load_key(K,key_schedule); 140 | aes128_dec(key_schedule,I,I); 141 | } 142 | 143 | static void BruteforceMissingBytes(const uint8_t Input[16], const uint8_t Expected[16], uint8_t IKey[16], bool Enc, int Round=0) { 144 | int B = 0; 145 | for (auto &BB : MissingBytes) { 146 | printf("[*] Byte %i ", B++); 147 | printf("Index %i\n", BB.Index); 148 | } 149 | 150 | if (MissingBytes.size() > 7) { 151 | printf("[!] Too many missing bytes! (7 max)"); 152 | return; 153 | } 154 | 155 | // Get amount of threads 156 | uint64_t V=0; 157 | uint64_t Max = (uint64_t) ((std::pow(2, MissingBytes.size() *8)) - 1); 158 | 159 | const int AESNI_Threads = std::thread::hardware_concurrency() / 2; 160 | uint64_t Step = (Max) / AESNI_Threads; 161 | uint64_t Min = 0; 162 | 163 | printf("[*] AES-NI Units : %i\n", AESNI_Threads); 164 | printf("[*] Range : %08lX - %08lX\n", Min, Max); 165 | printf("[*] Step : %08lX\n", Step); 166 | 167 | for (int i=0;i Max) { 171 | R.Max = Max; 172 | } else { 173 | R.Max = Min + Step; 174 | } 175 | 176 | Min += Step + 1; 177 | 178 | Ranges.push_back(R); 179 | } 180 | 181 | int TID = 0; 182 | for (auto &R : Ranges) { 183 | R.ThreadID = TID++; 184 | printf("[*] T%02i Range : %08lX - %08lX\n", R.ThreadID,R.Min,R.Max); 185 | } 186 | 187 | // Bruteforce threads 188 | bool Finished = false; 189 | std::vector workers; 190 | for (auto &R : Ranges) { 191 | // Encryption Thread 192 | if (Enc) { 193 | workers.push_back(std::thread([&]() { 194 | __m128i key_schedule[20]; 195 | 196 | uint64_t RMin = R.Min; 197 | uint64_t RMax = R.Max; 198 | 199 | __m128i Expected128 = _mm_loadu_si128((__m128i *) Expected); 200 | __m128i Input128 = _mm_loadu_si128((__m128i *) Input); 201 | 202 | // Set input key 203 | uint8_t KeyThread[16] = {0}; 204 | memcpy(KeyThread, IKey, 16); 205 | 206 | // Bruteforce 207 | for (uint64_t i=RMin; i<=RMax; i++) { 208 | // Set bruteforced bytes 209 | for (auto &B : MissingBytes) { 210 | KeyThread[B.Index] = (uint8_t) ((i >> B.Shift)); 211 | } 212 | 213 | // Attack Round 10 on decryption if needed 214 | __m128i Ciphertext128; 215 | if (Round > 0) { 216 | key_schedule[10] = _mm_loadu_si128((const __m128i*) KeyThread); 217 | KeyExpansionINV_Fast(key_schedule); 218 | Ciphertext128 = aes128_enc_fast(key_schedule, Input128); 219 | } else { 220 | aes128_load_key_enc_only(KeyThread, key_schedule); 221 | Ciphertext128 = aes128_enc_fast(key_schedule, Input128); 222 | } 223 | 224 | // Compare if result found 225 | __m128i neq = _mm_xor_si128(Ciphertext128, Expected128); 226 | if(_mm_test_all_zeros(neq,neq)) { 227 | // Key found 228 | Finished = true; 229 | 230 | printf("[!] T%02i Key found : ", R.ThreadID); 231 | if (Round > 0) { 232 | memcpy(IKey, &key_schedule[0], 16); 233 | phex(IKey); 234 | printf("[!] Round 10 Key : "); 235 | phex((uint8_t *) &key_schedule[10]); 236 | } else { 237 | memcpy(IKey, KeyThread, 16); 238 | phex(IKey); 239 | } 240 | return; 241 | } 242 | 243 | // Check if finished 244 | if (Finished) { 245 | return; 246 | } 247 | } 248 | })); 249 | } else { 250 | // Decryption Thread 251 | workers.push_back(std::thread([&]() { 252 | __m128i key_schedule_fast[20]; 253 | 254 | uint8_t KeyThread[16]; 255 | memcpy(KeyThread, IKey, 16); 256 | 257 | __m128i Expected128 = _mm_loadu_si128((__m128i *) Expected); 258 | __m128i Input128 = _mm_loadu_si128((__m128i *) Input); 259 | 260 | uint64_t RMin = R.Min; 261 | uint64_t RMax = R.Max; 262 | 263 | // Bruteforce 264 | for (uint64_t i=RMin; i<=RMax; i++) { 265 | // Set bruteforced bytes 266 | for (auto &B : MissingBytes) { 267 | KeyThread[B.Index] = (uint8_t) ((i >> B.Shift)); 268 | } 269 | 270 | // Attack Round 10 on decryption if needed 271 | __m128i Ciphertext128; 272 | if (Round > 0) { 273 | key_schedule_fast[10] = _mm_loadu_si128((const __m128i*) KeyThread); 274 | KeyExpansionINV_Fast(key_schedule_fast); 275 | aes128_load_dec_only(key_schedule_fast); 276 | Ciphertext128 = aes128_dec_fast(key_schedule_fast, Input128); 277 | } else { 278 | aes128_load_key(KeyThread, key_schedule_fast); 279 | Ciphertext128 = aes128_dec_fast(key_schedule_fast, Input128); 280 | } 281 | 282 | // Compare if result found 283 | __m128i neq = _mm_xor_si128(Ciphertext128, Expected128); 284 | if(_mm_test_all_zeros(neq,neq)) { 285 | // Key found 286 | Finished = true; 287 | 288 | printf("[!] T%02i Key found : ", R.ThreadID); 289 | if (Round > 0) { 290 | memcpy(IKey, &key_schedule_fast[0], 16); 291 | phex(IKey); 292 | printf("[!] Round 10 Key : "); 293 | phex((uint8_t *) &key_schedule_fast[10]); 294 | } else { 295 | memcpy(IKey, KeyThread, 16); 296 | phex(IKey); 297 | } 298 | return; 299 | } 300 | 301 | // if finished, key was found so end the thread 302 | if (Finished) 303 | return; 304 | } 305 | })); 306 | } 307 | } 308 | 309 | // Wait until all threads are finished 310 | for (auto &t : workers) { 311 | t.join(); 312 | }; 313 | } 314 | 315 | int main(int argc, char **argv) { 316 | bool Enc = true; 317 | int KeyScheduleRound = 0; 318 | uint8_t plaintext[16] = {0}; 319 | uint8_t ciphertext[16] = {0}; 320 | uint8_t key[16] = {0}; 321 | 322 | printf("Hulk v1.2 (Peter Garba 2018)\n"); 323 | if (argc < 5) { 324 | printf("Usage: %s mode \n", argv[0]); 325 | return 1; 326 | } 327 | 328 | if (GetNNICapability() == false) { 329 | printf("AES-NI is not supported by this CPU!\n"); 330 | return 0; 331 | } 332 | 333 | printf("[*] AES-NI is supported by this CPU!\n"); 334 | 335 | if (argv[1][0] != 'e') 336 | Enc = false; 337 | 338 | parseInput(argv[2], plaintext); 339 | parseInput(argv[3], ciphertext); 340 | 341 | // parse key and keep ?? 342 | parseKey(argv[4], key); 343 | std::string StrKey = argv[4]; 344 | for (auto &c : StrKey) { 345 | c = std::toupper(c); 346 | } 347 | 348 | if (argc == 6) { 349 | KeyScheduleRound = atoi(argv[5]); 350 | printf("[*] Round : %i\n", KeyScheduleRound); 351 | } 352 | 353 | printf("[*] Mode : "); 354 | if (Enc == true) 355 | printf("Encryption\n"); 356 | else 357 | printf("Decryption\n"); 358 | 359 | 360 | printf("[*] Key : "); 361 | printf("%s\n", StrKey.c_str()); 362 | 363 | printf("[*] Input : "); 364 | phex(plaintext); 365 | 366 | printf("[*] Expected : "); 367 | phex(ciphertext); 368 | 369 | if (MissingBytes.size() > 0) { 370 | printf("[!] Bruteforce : %li missing bytes\n", MissingBytes.size()); 371 | BruteforceMissingBytes(plaintext, ciphertext, key, Enc, KeyScheduleRound); 372 | } 373 | 374 | if (MissingBytes.size() == 0 && KeyScheduleRound > 0) { 375 | __m128i key_schedule_fast[20]; 376 | key_schedule_fast[10] = _mm_loadu_si128((const __m128i*) key); 377 | KeyExpansionINV_Fast(key_schedule_fast); 378 | printf("[*] Round 0 Key : "); 379 | memcpy(key, &key_schedule_fast[0], 16); 380 | phex(key); 381 | } 382 | 383 | if (Enc) { 384 | EncryptNI(plaintext, key); 385 | } else { 386 | DecryptNI(plaintext, key); 387 | } 388 | 389 | printf("[*] Output : "); 390 | phex(plaintext); 391 | 392 | bool R = CompareResult(plaintext, ciphertext); 393 | if (R == true) { 394 | printf("[!] Valid key!\n"); 395 | } else { 396 | printf("[!] Wrong key!\n"); 397 | } 398 | 399 | printf("\n"); 400 | 401 | return 0; 402 | } 403 | --------------------------------------------------------------------------------