├── decrypt_wxdb.vcxproj.user ├── crypto ├── sha.h ├── pbkdf2_hmac.h ├── aes.h ├── pbkdf2_hmac.c ├── sha.c └── aes.c ├── README.md ├── decrypt_wxdb.sln ├── decrypt_wxdb.vcxproj.filters ├── decrypt_wxdb.vcxproj └── main.c /decrypt_wxdb.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | -------------------------------------------------------------------------------- /crypto/sha.h: -------------------------------------------------------------------------------- 1 | #ifndef _CIPHER_SHASHA_H 2 | #define _CIPHER_SHASHA_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif /* __cplusplus */ 6 | typedef unsigned int uint32; 7 | typedef uint32 word32; 8 | typedef struct { 9 | uint32 h[5]; 10 | unsigned char block[64]; 11 | int blkused; 12 | uint32 lenhi, lenlo; 13 | } SHA_State; 14 | void SHA_Init(SHA_State * s); 15 | void SHA_Bytes(SHA_State * s, const void *p, int len); 16 | void SHA_Final(SHA_State * s, unsigned char *output); 17 | void SHA_Simple(const void *p, int len, unsigned char *output); 18 | #ifdef __cplusplus 19 | } 20 | #endif /* __cplusplus */ 21 | #endif /* _CIPHER_SHASHA_H */ 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # decrypt-PC-WeChat-db 2 | 3 | ​ 把网上解密微信数据库ChatMsg.db的祖传代码改了一下,去掉了OpenSSL的依赖,用相关的密码算法源码替换了,就算是密码学作业了。 4 | 5 | ​ 添加了自动获取密钥的功能,需登录微信。适用于版本2.8.0.121。 6 | 7 | #### 加密结构说明 8 | 9 | ​ 微信数据库采用的加密算法是256位的AES-CBC。数据库的默认的页大小是4096字节即4KB,其中每一个页都是被单独加解密的。 10 | 11 | ​ 加密文件的每一个页都有一个随机的初始化向量,它被保存在每一页的末尾。 12 | 13 | ​ 加密文件的每一页都存有着消息认证码,算法使用的是HMAC-SHA1(安卓数据库使用的是SHA512)。它也被保存在每一页的末尾。 14 | 15 | ​ 每一个数据库文件的开头16字节都保存了一段唯一且随机的盐值,作为HMAC的验证和数据的解密。 16 | 17 | ​ 用来计算HMAC的key与解密的key是不同的,解密用的密钥是主密钥和之前提到的16字节的盐值通过PKCS5_PBKF2_HMAC1密钥扩展算法迭代64000次计算得到的。而计算HMAC的密钥是刚提到的解密密钥和16字节盐值异或0x3a的值通过PKCS5_PBKF2_HMAC1密钥扩展算法迭代2次计算得到的。 18 | 19 | ​ 为了保证数据部分长度是16字节即AES块大小的整倍数,每一页的末尾将填充一段空字节,使得保留字段的长度为48字节。 20 | 21 | ​ 综上,加密文件结构为第一页4KB数据前16字节为盐值,紧接着4032字节数据,再加上16字节IV和20字节HMAC以及12字节空字节;而后的页均是4048字节长度的加密数据段和48字节的保留段。 22 | 23 | 24 | 25 | ​ 参考:https://www.zetetic.net/sqlcipher/design/ -------------------------------------------------------------------------------- /crypto/pbkdf2_hmac.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include "sha.h" 3 | #ifndef _CIPHER_PKCS5_PBKDF2_HMAC_H 4 | #define _CIPHER_PKCS5_PBKDF2_HMAC_H 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif /* __cplusplus */ 8 | 9 | #define KEY_IOPAD_SIZE 64 10 | #define PUT_32BIT_MSB_FIRST(cp, value) ( \ 11 | (cp)[0] = (unsigned char)((value) >> 24), \ 12 | (cp)[1] = (unsigned char)((value) >> 16), \ 13 | (cp)[2] = (unsigned char)((value) >> 8), \ 14 | (cp)[3] = (unsigned char)(value)) 15 | typedef struct { 16 | SHA_State ctx; 17 | unsigned char ipad[KEY_IOPAD_SIZE]; /*!< HMAC: inner padding */ 18 | unsigned char opad[KEY_IOPAD_SIZE]; /*!< HMAC: outer padding */ 19 | } sha1_context; 20 | 21 | void PKCS5_PBKDF2_HMAC(const unsigned char *password, size_t plen, 22 | const unsigned char *salt, size_t slen, 23 | const unsigned long iteration_count, const unsigned long key_length, 24 | unsigned char *output); 25 | 26 | void sha1_hmac_starts(sha1_context * ctx, const unsigned char *key, int keylen); 27 | void sha1_hmac_update(sha1_context * ctx, const unsigned char *input, int ilen); 28 | void sha1_hmac_finish(sha1_context * ctx, unsigned char output[20]); 29 | 30 | #ifdef __cplusplus 31 | } 32 | #endif /* __cplusplus */ 33 | #endif // _CIPHER_PKCS5_PBKDF2_HMAC_H 34 | -------------------------------------------------------------------------------- /decrypt_wxdb.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.1169 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "decrypt_wxdb", "decrypt_wxdb.vcxproj", "{0142F0A9-0D2B-4CE7-83BF-F8335FCD8A1E}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {0142F0A9-0D2B-4CE7-83BF-F8335FCD8A1E}.Debug|x64.ActiveCfg = Debug|x64 17 | {0142F0A9-0D2B-4CE7-83BF-F8335FCD8A1E}.Debug|x64.Build.0 = Debug|x64 18 | {0142F0A9-0D2B-4CE7-83BF-F8335FCD8A1E}.Debug|x86.ActiveCfg = Debug|Win32 19 | {0142F0A9-0D2B-4CE7-83BF-F8335FCD8A1E}.Debug|x86.Build.0 = Debug|Win32 20 | {0142F0A9-0D2B-4CE7-83BF-F8335FCD8A1E}.Release|x64.ActiveCfg = Release|x64 21 | {0142F0A9-0D2B-4CE7-83BF-F8335FCD8A1E}.Release|x64.Build.0 = Release|x64 22 | {0142F0A9-0D2B-4CE7-83BF-F8335FCD8A1E}.Release|x86.ActiveCfg = Release|Win32 23 | {0142F0A9-0D2B-4CE7-83BF-F8335FCD8A1E}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {133164B3-7D3E-4146-BD2E-BEAD340E3436} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /decrypt_wxdb.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 源文件 20 | 21 | 22 | 源文件 23 | 24 | 25 | 源文件 26 | 27 | 28 | 源文件 29 | 30 | 31 | 32 | 33 | 头文件 34 | 35 | 36 | 头文件 37 | 38 | 39 | 头文件 40 | 41 | 42 | -------------------------------------------------------------------------------- /crypto/aes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef AES_H 4 | #define AES_H 5 | 6 | #include 7 | 8 | #define AES_BLOCK_SIZE 16 // AES operates on 16 bytes at a time 9 | 10 | typedef unsigned char BYTE; // 8-bit byte 11 | typedef unsigned int DWORD; // 32-bit word, change to "long" for 16-bit machines 12 | // Key setup must be done before any AES en/de-cryption functions can be used. 13 | void aes_key_setup(const BYTE key[], // The key, must be 128, 192, or 256 bits 14 | DWORD w[], // Output key schedule to be used later 15 | int keysize); // Bit length of the key, 128, 192, or 256 16 | 17 | void aes_encrypt(const BYTE in[], // 16 bytes of plaintext 18 | BYTE out[], // 16 bytes of ciphertext 19 | const DWORD key[], // From the key setup 20 | int keysize); // Bit length of the key, 128, 192, or 256 21 | 22 | void aes_decrypt(const BYTE in[], // 16 bytes of ciphertext 23 | BYTE out[], // 16 bytes of plaintext 24 | const DWORD key[], // From the key setup 25 | int keysize); // Bit length of the key, 128, 192, or 256 26 | 27 | 28 | // AES - CBC 29 | 30 | int aes_encrypt_cbc(const BYTE in[], // Plaintext 31 | size_t in_len, // Must be a multiple of AES_BLOCK_SIZE 32 | BYTE out[], // Ciphertext, same length as plaintext 33 | const DWORD key[], // From the key setup 34 | int keysize, // Bit length of the key, 128, 192, or 256 35 | const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long 36 | 37 | // Only output the CBC-MAC of the input. 38 | int aes_encrypt_cbc_mac(const BYTE in[], // plaintext 39 | size_t in_len, // Must be a multiple of AES_BLOCK_SIZE 40 | BYTE out[], // Output MAC 41 | const DWORD key[], // From the key setup 42 | int keysize, // Bit length of the key, 128, 192, or 256 43 | const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long 44 | 45 | #endif // AES_H 46 | -------------------------------------------------------------------------------- /crypto/pbkdf2_hmac.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "pbkdf2_hmac.h" 5 | #include "sha.h" 6 | 7 | #ifndef min 8 | #define min( a, b ) ( ((a) < (b)) ? (a) : (b) ) 9 | #endif 10 | 11 | 12 | void sha1_hmac_starts(sha1_context * ctx, const unsigned char *key, int keylen) 13 | { 14 | int i; 15 | unsigned char sum[20]; 16 | 17 | if (keylen > 64) { 18 | SHA_Simple(key, keylen, sum); 19 | keylen = 20; 20 | key = sum; 21 | } 22 | 23 | memset(ctx->ipad, 0x36, KEY_IOPAD_SIZE); 24 | memset(ctx->opad, 0x5C, KEY_IOPAD_SIZE); 25 | 26 | for (i = 0; i < keylen; i++) { 27 | ctx->ipad[i] = (unsigned char)(ctx->ipad[i] ^ key[i]); 28 | ctx->opad[i] = (unsigned char)(ctx->opad[i] ^ key[i]); 29 | } 30 | 31 | SHA_Init(&ctx->ctx); 32 | SHA_Bytes(&ctx->ctx, ctx->ipad, KEY_IOPAD_SIZE); 33 | 34 | } 35 | 36 | /* 37 | * SHA-1 HMAC process buffer 38 | */ 39 | void sha1_hmac_update(sha1_context * ctx, const unsigned char *input, int ilen) 40 | { 41 | SHA_Bytes(&ctx->ctx, input, ilen); 42 | } 43 | 44 | /* 45 | * SHA-1 HMAC final digest 46 | */ 47 | void sha1_hmac_finish(sha1_context * ctx, unsigned char output[20]) 48 | { 49 | unsigned char tmpbuf[20]; 50 | 51 | SHA_Final(&ctx->ctx, tmpbuf); 52 | SHA_Init(&ctx->ctx); 53 | SHA_Bytes(&ctx->ctx, ctx->opad, 64); 54 | SHA_Bytes(&ctx->ctx, tmpbuf, 20); 55 | SHA_Final(&ctx->ctx, output); 56 | 57 | } 58 | 59 | 60 | void PKCS5_PBKDF2_HMAC(const unsigned char *password, size_t plen, 61 | const unsigned char *salt, size_t slen, 62 | const unsigned long iteration_count, const unsigned long key_length, 63 | unsigned char *output) 64 | { 65 | sha1_context ctx; 66 | SHA_Init(&ctx.ctx); 67 | 68 | // Size of the generated digest 69 | unsigned char md_size = 20; 70 | unsigned char md1[20]; 71 | unsigned char work[20]; 72 | 73 | unsigned long counter = 1; 74 | unsigned long generated_key_length = 0; 75 | while (generated_key_length < key_length) { 76 | // U1 ends up in md1 and work 77 | unsigned char c[4]; 78 | PUT_32BIT_MSB_FIRST(c, counter); 79 | sha1_hmac_starts(&ctx, password, plen); 80 | sha1_hmac_update(&ctx, salt, slen); 81 | sha1_hmac_update(&ctx, c, 4); 82 | sha1_hmac_finish(&ctx, md1); 83 | memcpy(work, md1, md_size); 84 | 85 | unsigned long ic = 1; 86 | for (ic = 1; ic < iteration_count; ic++) { 87 | // U2 ends up in md1 88 | sha1_hmac_starts(&ctx, password, plen); 89 | sha1_hmac_update(&ctx, md1, md_size); 90 | sha1_hmac_finish(&ctx, md1); 91 | // U1 xor U2 92 | unsigned long i = 0; 93 | for (i = 0; i < md_size; i++) { 94 | work[i] ^= md1[i]; 95 | } 96 | // and so on until iteration_count 97 | } 98 | 99 | // Copy the generated bytes to the key 100 | unsigned long bytes_to_write = 101 | min((key_length - generated_key_length), md_size); 102 | memcpy(output + generated_key_length, work, bytes_to_write); 103 | generated_key_length += bytes_to_write; 104 | ++counter; 105 | } 106 | } 107 | 108 | -------------------------------------------------------------------------------- /crypto/sha.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SHA1 hash algorithm. Used in SSH-2 as a MAC, and the transform is 3 | * also used as a `stirring' function for the PuTTY random number 4 | * pool. Implemented directly from the specification by Simon 5 | * Tatham. 6 | */ 7 | #include 8 | #include "sha.h" 9 | 10 | /* ---------------------------------------------------------------------- 11 | * Core SHA algorithm: processes 16-word blocks into a message digest. 12 | */ 13 | 14 | #define rol(x,y) ( ((x) << (y)) | (((uint32)x) >> (32-y)) ) 15 | #define PUT_32BIT_MSB_FIRST(cp, value) ( \ 16 | (cp)[0] = (unsigned char)((value) >> 24), \ 17 | (cp)[1] = (unsigned char)((value) >> 16), \ 18 | (cp)[2] = (unsigned char)((value) >> 8), \ 19 | (cp)[3] = (unsigned char)(value) ) 20 | 21 | static void SHA_Core_Init(uint32 h[5]) 22 | { 23 | h[0] = 0x67452301; 24 | h[1] = 0xefcdab89; 25 | h[2] = 0x98badcfe; 26 | h[3] = 0x10325476; 27 | h[4] = 0xc3d2e1f0; 28 | } 29 | 30 | void SHATransform(word32 * digest, word32 * block) 31 | { 32 | word32 w[80]; 33 | word32 a, b, c, d, e; 34 | int t; 35 | 36 | #ifdef RANDOM_DIAGNOSTICS 37 | { 38 | extern int random_diagnostics; 39 | if (random_diagnostics) { 40 | int i; 41 | printf("SHATransform:"); 42 | for (i = 0; i < 5; i++) 43 | printf(" %08x", digest[i]); 44 | printf(" +"); 45 | for (i = 0; i < 16; i++) 46 | printf(" %08x", block[i]); 47 | } 48 | } 49 | #endif 50 | 51 | for (t = 0; t < 16; t++) 52 | w[t] = block[t]; 53 | 54 | for (t = 16; t < 80; t++) { 55 | word32 tmp = w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16]; 56 | w[t] = rol(tmp, 1); 57 | } 58 | 59 | a = digest[0]; 60 | b = digest[1]; 61 | c = digest[2]; 62 | d = digest[3]; 63 | e = digest[4]; 64 | 65 | for (t = 0; t < 20; t++) { 66 | word32 tmp = 67 | rol(a, 5) + ((b & c) | (d & ~b)) + e + w[t] + 0x5a827999; 68 | e = d; 69 | d = c; 70 | c = rol(b, 30); 71 | b = a; 72 | a = tmp; 73 | } 74 | for (t = 20; t < 40; t++) { 75 | word32 tmp = rol(a, 5) + (b ^ c ^ d) + e + w[t] + 0x6ed9eba1; 76 | e = d; 77 | d = c; 78 | c = rol(b, 30); 79 | b = a; 80 | a = tmp; 81 | } 82 | for (t = 40; t < 60; t++) { 83 | word32 tmp = rol(a, 84 | 5) + ((b & c) | (b & d) | (c & d)) + e + w[t] + 85 | 0x8f1bbcdc; 86 | e = d; 87 | d = c; 88 | c = rol(b, 30); 89 | b = a; 90 | a = tmp; 91 | } 92 | for (t = 60; t < 80; t++) { 93 | word32 tmp = rol(a, 5) + (b ^ c ^ d) + e + w[t] + 0xca62c1d6; 94 | e = d; 95 | d = c; 96 | c = rol(b, 30); 97 | b = a; 98 | a = tmp; 99 | } 100 | 101 | digest[0] += a; 102 | digest[1] += b; 103 | digest[2] += c; 104 | digest[3] += d; 105 | digest[4] += e; 106 | 107 | #ifdef RANDOM_DIAGNOSTICS 108 | { 109 | extern int random_diagnostics; 110 | if (random_diagnostics) { 111 | int i; 112 | printf(" ="); 113 | for (i = 0; i < 5; i++) 114 | printf(" %08x", digest[i]); 115 | printf("\n"); 116 | } 117 | } 118 | #endif 119 | } 120 | 121 | /* ---------------------------------------------------------------------- 122 | * Outer SHA algorithm: take an arbitrary length byte string, 123 | * convert it into 16-word blocks with the prescribed padding at 124 | * the end, and pass those blocks to the core SHA algorithm. 125 | */ 126 | 127 | void SHA_Init(SHA_State * s) 128 | { 129 | SHA_Core_Init(s->h); 130 | s->blkused = 0; 131 | s->lenhi = s->lenlo = 0; 132 | } 133 | 134 | void SHA_Bytes(SHA_State * s, const void *p, int len) 135 | { 136 | const unsigned char *q = (const unsigned char *) p; 137 | uint32 wordblock[16]; 138 | uint32 lenw = len; 139 | int i; 140 | 141 | /* 142 | * Update the length field. 143 | */ 144 | s->lenlo += lenw; 145 | s->lenhi += (s->lenlo < lenw); 146 | 147 | if (s->blkused && s->blkused + len < 64) { 148 | /* 149 | * Trivial case: just add to the block. 150 | */ 151 | memcpy(s->block + s->blkused, q, len); 152 | s->blkused += len; 153 | } else { 154 | /* 155 | * We must complete and process at least one block. 156 | */ 157 | while (s->blkused + len >= 64) { 158 | memcpy(s->block + s->blkused, q, 64 - s->blkused); 159 | q += 64 - s->blkused; 160 | len -= 64 - s->blkused; 161 | /* Now process the block. Gather bytes big-endian into words */ 162 | for (i = 0; i < 16; i++) { 163 | wordblock[i] = 164 | (((uint32) s->block[i * 4 + 0]) << 24) | 165 | (((uint32) s->block[i * 4 + 1]) << 16) | 166 | (((uint32) s->block[i * 4 + 2]) << 8) | 167 | (((uint32) s->block[i * 4 + 3]) << 0); 168 | } 169 | SHATransform(s->h, wordblock); 170 | s->blkused = 0; 171 | } 172 | memcpy(s->block, q, len); 173 | s->blkused = len; 174 | } 175 | } 176 | 177 | void SHA_Final(SHA_State * s, unsigned char *output) 178 | { 179 | int i; 180 | int pad; 181 | unsigned char c[64]; 182 | uint32 lenhi, lenlo; 183 | 184 | if (s->blkused >= 56) 185 | pad = 56 + 64 - s->blkused; 186 | else 187 | pad = 56 - s->blkused; 188 | 189 | lenhi = (s->lenhi << 3) | (s->lenlo >> (32 - 3)); 190 | lenlo = (s->lenlo << 3); 191 | 192 | memset(c, 0, pad); 193 | c[0] = 0x80; 194 | SHA_Bytes(s, &c, pad); 195 | 196 | c[0] = (lenhi >> 24) & 0xFF; 197 | c[1] = (lenhi >> 16) & 0xFF; 198 | c[2] = (lenhi >> 8) & 0xFF; 199 | c[3] = (lenhi >> 0) & 0xFF; 200 | c[4] = (lenlo >> 24) & 0xFF; 201 | c[5] = (lenlo >> 16) & 0xFF; 202 | c[6] = (lenlo >> 8) & 0xFF; 203 | c[7] = (lenlo >> 0) & 0xFF; 204 | 205 | SHA_Bytes(s, &c, 8); 206 | 207 | for (i = 0; i < 5; i++) { 208 | output[i * 4] = (s->h[i] >> 24) & 0xFF; 209 | output[i * 4 + 1] = (s->h[i] >> 16) & 0xFF; 210 | output[i * 4 + 2] = (s->h[i] >> 8) & 0xFF; 211 | output[i * 4 + 3] = (s->h[i]) & 0xFF; 212 | } 213 | } 214 | 215 | void SHA_Simple(const void *p, int len, unsigned char *output) 216 | { 217 | SHA_State s; 218 | 219 | SHA_Init(&s); 220 | SHA_Bytes(&s, p, len); 221 | SHA_Final(&s, output); 222 | } 223 | -------------------------------------------------------------------------------- /decrypt_wxdb.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {0142F0A9-0D2B-4CE7-83BF-F8335FCD8A1E} 24 | decryptwxdb 25 | 10.0.17763.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v141 32 | MultiByte 33 | 34 | 35 | Application 36 | false 37 | v141 38 | true 39 | MultiByte 40 | 41 | 42 | Application 43 | true 44 | v141 45 | MultiByte 46 | 47 | 48 | Application 49 | false 50 | v141 51 | true 52 | MultiByte 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Level3 76 | Disabled 77 | true 78 | true 79 | 80 | 81 | Console 82 | 83 | 84 | 85 | 86 | Level3 87 | Disabled 88 | true 89 | true 90 | 91 | 92 | Console 93 | 94 | 95 | 96 | 97 | Level3 98 | MaxSpeed 99 | true 100 | true 101 | true 102 | true 103 | 104 | 105 | Console 106 | true 107 | true 108 | 109 | 110 | 111 | 112 | Level3 113 | MaxSpeed 114 | true 115 | true 116 | true 117 | true 118 | 119 | 120 | Console 121 | true 122 | true 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "crypto/pbkdf2_hmac.h" 8 | #include "crypto/sha.h" 9 | #include "crypto/aes.h" 10 | 11 | #pragma comment(lib,"shlwapi.lib") 12 | 13 | 14 | #undef _UNICODE 15 | #define SQLITE_FILE_HEADER "SQLite format 3" 16 | #define IV_SIZE 16 17 | #define HMAC_SHA1_SIZE 20 18 | #define KEY_SIZE 32 19 | 20 | #define SL3SIGNLEN 20 21 | 22 | #ifndef ANDROID_WECHAT 23 | //4048数据 + 16IV + 20 HMAC + 12 24 | #define DEFAULT_PAGESIZE 4096 25 | #define DEFAULT_ITER 64000 26 | #else 27 | #define NO_USE_HMAC_SHA1 28 | #define DEFAULT_PAGESIZE 1024 29 | #define DEFAULT_ITER 4000 30 | #endif 31 | 32 | 33 | //for WeChat Version 2.8.0.121 34 | //密钥指针相对于WeChatWin.dll基地址偏移 35 | #define KEY_OFFSET 0x161cc50 36 | #define WXID_OFFSET 0x161cc78 37 | 38 | char dbfilename[32] = "ChatMsg.db"; 39 | 40 | BOOL Decryptdb(char *szFilePath, BYTE *pass); 41 | 42 | DWORD FindProcessId(const char *processname) 43 | { 44 | HANDLE hProcessSnap; 45 | PROCESSENTRY32 pe32; 46 | DWORD result = NULL; 47 | 48 | // Take a snapshot of all processes in the system. 49 | hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 50 | if (INVALID_HANDLE_VALUE == hProcessSnap) return(FALSE); 51 | 52 | pe32.dwSize = sizeof(PROCESSENTRY32); // <----- IMPORTANT 53 | 54 | // Retrieve information about the first process, 55 | // and exit if unsuccessful 56 | if (!Process32First(hProcessSnap, &pe32)) 57 | { 58 | CloseHandle(hProcessSnap); // clean the snapshot object 59 | printf("!!! Failed to gather information on system processes! \n"); 60 | return(NULL); 61 | } 62 | 63 | do 64 | { 65 | //printf("Checking process %ls\n", pe32.szExeFile); 66 | if (0 == strcmp(processname, pe32.szExeFile)) 67 | { 68 | result = pe32.th32ProcessID; 69 | break; 70 | } 71 | } while (Process32Next(hProcessSnap, &pe32)); 72 | 73 | CloseHandle(hProcessSnap); 74 | 75 | return result; 76 | } 77 | 78 | DWORD FindProcess(char *szProcName) { 79 | DWORD pid; 80 | 81 | while (TRUE) { 82 | pid = FindProcessId(szProcName); 83 | if (pid) 84 | { 85 | return pid; 86 | } 87 | Sleep(500); 88 | } 89 | 90 | } 91 | 92 | 93 | HMODULE GetModule(DWORD processID, TCHAR * szModuleName) 94 | { 95 | HMODULE hMods[1024]; 96 | HANDLE hProcess; 97 | DWORD cbNeeded; 98 | unsigned int i; 99 | 100 | // Get a handle to the process. 101 | hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | 102 | PROCESS_VM_READ, 103 | FALSE, processID); 104 | if (NULL == hProcess) 105 | return NULL; 106 | 107 | // Get a list of all the modules in this process. 108 | if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) 109 | { 110 | for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) 111 | { 112 | TCHAR szModName[MAX_PATH]; 113 | 114 | // Get the full path to the module's file. 115 | if (GetModuleFileNameEx(hProcess, hMods[i], szModName, 116 | sizeof(szModName) / sizeof(TCHAR))) 117 | { 118 | // Print the module name and handle value. 119 | PathStripPath(szModName); 120 | if (!_tcscmp(szModName, szModuleName)) { 121 | //_tprintf(TEXT("\t%s (0x%08X)\n"), szModName, hMods[i]); 122 | CloseHandle(hProcess); 123 | return hMods[i]; 124 | } 125 | } 126 | } 127 | } 128 | 129 | // Release the handle to the process. 130 | CloseHandle(hProcess); 131 | 132 | return 0; 133 | } 134 | 135 | 136 | BOOL GetDatabaseKey(DWORD pid, LPVOID *buf) { 137 | DWORD pKey = 0; 138 | 139 | HMODULE pWeChatdll = GetModule(pid, "WeChatWin.dll"); 140 | if (!pWeChatdll) 141 | { 142 | printf("GetModule error!\n"); 143 | return 0; 144 | } 145 | 146 | HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); 147 | ReadProcessMemory(hProcess, (DWORD)pWeChatdll + KEY_OFFSET, &pKey, 4, NULL); 148 | ReadProcessMemory(hProcess, pKey, buf, 32, NULL); 149 | CloseHandle(hProcess); 150 | 151 | if (!pKey) { 152 | return 0; 153 | } 154 | return 1; 155 | } 156 | 157 | 158 | BOOL GetWeChatID(DWORD pid, char *szWXID) 159 | { 160 | BYTE buffer[MAX_PATH]; 161 | 162 | HMODULE pWeChatdll = GetModule(pid, "WeChatWin.dll"); 163 | if (!pWeChatdll) 164 | { 165 | printf("GetModule error!\n"); 166 | return FALSE; 167 | } 168 | HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); 169 | ReadProcessMemory(hProcess, (DWORD)pWeChatdll + WXID_OFFSET, &buffer, MAX_PATH, NULL); 170 | 171 | size_t len = strlen(buffer); 172 | if (len> MAX_PATH) 173 | { 174 | printf("get wechat id error!\n"); 175 | return 0; 176 | } 177 | strcpy_s(szWXID, MAX_PATH, buffer); 178 | return TRUE; 179 | } 180 | 181 | 182 | int main(int argc, char* argv[]) 183 | { 184 | 185 | printf("正在检测微信进程...\n"); 186 | DWORD pid = FindProcess("WeChat.exe"); 187 | printf("检测到微信运行!\n"); 188 | 189 | BOOL bRet; 190 | char szwxid[MAX_PATH] ; 191 | 192 | BOOL bRet = GetWeChatID(pid, szwxid); 193 | if (!bRet) 194 | { 195 | getchar(); 196 | return 0; 197 | } 198 | printf("wxid:%s\n", szwxid); 199 | 200 | 201 | char homePath[MAX_PATH] = { 0 }; 202 | DWORD dwPathSize = GetEnvironmentVariable("USERPROFILE", homePath, MAX_PATH); 203 | if (dwPathSize == 0 || dwPathSize > MAX_PATH) 204 | { 205 | printf("get home path error!\n"); 206 | getchar(); 207 | return 0; 208 | } 209 | //printf("homepath:%s\n", homePath); 210 | 211 | char szDBPath[MAX_PATH]; 212 | snprintf(szDBPath, MAX_PATH, 213 | "%s\\Documents\\WeChat Files\\%s\\Msg\\%s", homePath, szwxid, dbfilename); 214 | printf("DataBasePath:%s\n", szDBPath); 215 | 216 | 217 | BYTE KeyBuffer[32]; 218 | bRet = GetDatabaseKey(pid, KeyBuffer); 219 | if (!bRet) 220 | { 221 | printf("get key error!\n"); 222 | getchar(); 223 | return 0; 224 | } 225 | //for (int i = 0; i < 32; i++) { 226 | // printf("%02x", KeyBuffer[i]); 227 | //} 228 | 229 | Decryptdb(szDBPath, KeyBuffer); 230 | return 0; 231 | } 232 | //打开db文件 233 | size_t OpenDBFile(char *szFilePath,BYTE ** pDbBuffer) { 234 | 235 | DWORD RSize; 236 | HANDLE hFile = CreateFile(szFilePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); 237 | if (hFile == INVALID_HANDLE_VALUE) 238 | { 239 | printf("open datebase file error! %d \n",GetLastError()); 240 | return 0; 241 | } 242 | 243 | DWORD dwFileSize = GetFileSize(hFile, NULL); 244 | *pDbBuffer = (BYTE*)malloc(sizeof(BYTE)*dwFileSize); 245 | 246 | 247 | ReadFile(hFile, *pDbBuffer, dwFileSize, &RSize, NULL); 248 | if (dwFileSize != RSize) 249 | { 250 | printf("read file error!\n"); 251 | return 0; 252 | } 253 | CloseHandle(hFile); 254 | return dwFileSize; 255 | 256 | }; 257 | 258 | BOOL Decryptdb(char *szFilePath,BYTE *pass) 259 | { 260 | BYTE* pDbBuffer = NULL; 261 | size_t nFileSize = OpenDBFile(szFilePath,&pDbBuffer); 262 | if (!nFileSize) { 263 | return 0; 264 | } 265 | 266 | //数据库文件前16字节为盐值 267 | BYTE salt[16] = { 0 }; 268 | memcpy(salt, pDbBuffer, 16); 269 | 270 | #ifndef NO_USE_HMAC_SHA1 271 | //HMAC验证用的盐值需要异或0x3a 272 | BYTE mac_salt[16] = { 0 }; 273 | memcpy(mac_salt, salt, 16); 274 | for (int i = 0; i < sizeof(salt); i++) 275 | mac_salt[i] ^= 0x3a; 276 | #endif 277 | 278 | //保留段长度,PC端每4KB有48B 279 | int reserve = IV_SIZE; 280 | #ifndef NO_USE_HMAC_SHA1 281 | reserve += HMAC_SHA1_SIZE; 282 | #endif 283 | reserve = ((reserve % AES_BLOCK_SIZE) == 0) ? reserve : ((reserve / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE; 284 | 285 | //密钥扩展,分别对应AES解密密钥和HMAC验证密钥 286 | BYTE key[KEY_SIZE] = { 0 }; 287 | BYTE mac_key[KEY_SIZE] = { 0 }; 288 | PKCS5_PBKDF2_HMAC((const BYTE*)pass, 32, 289 | salt, sizeof(salt), DEFAULT_ITER, sizeof(key), key); 290 | #ifndef NO_USE_HMAC_SHA1 291 | PKCS5_PBKDF2_HMAC((const BYTE*)key, sizeof(key), 292 | mac_salt, sizeof(mac_salt), 2, sizeof(mac_key), mac_key); 293 | #endif 294 | 295 | BYTE* pTemp = pDbBuffer; 296 | BYTE pDecryptPerPageBuffer[DEFAULT_PAGESIZE]; 297 | int nPage = 1; 298 | int offset = 16; 299 | printf("\n 开始解密 \n"); 300 | while (pTemp < pDbBuffer + nFileSize) 301 | { 302 | printf("解密数据页:%d/%d \n", nPage, nFileSize / DEFAULT_PAGESIZE); 303 | 304 | //计算加密数据的HMAC,并与保留字段中的值进行比较 305 | #ifndef NO_USE_HMAC_SHA1 306 | BYTE hash_mac[HMAC_SHA1_SIZE] = { 0 }; 307 | sha1_context hctx; 308 | SHA_Init(&hctx.ctx); 309 | sha1_hmac_starts(&hctx, mac_key, sizeof(mac_key)); 310 | sha1_hmac_update(&hctx, pTemp + offset, DEFAULT_PAGESIZE - reserve - offset + IV_SIZE);//4096-48-16+16 311 | sha1_hmac_update(&hctx, (const BYTE*)& nPage, sizeof(nPage)); 312 | sha1_hmac_finish(&hctx, hash_mac); 313 | BYTE* pHMAC = pTemp + DEFAULT_PAGESIZE - reserve + IV_SIZE; 314 | if (0 != memcmp(hash_mac, pHMAC, sizeof(hash_mac))) 315 | { 316 | printf("\n 哈希值错误! \n"); 317 | getchar(); 318 | return 0; 319 | } 320 | #endif 321 | 322 | if (nPage == 1) 323 | memcpy(pDecryptPerPageBuffer, SQLITE_FILE_HEADER, offset); 324 | 325 | //AES解密操作 326 | BYTE key_schedule[40]; 327 | aes_key_setup(key, key_schedule, 256); 328 | aes_decrypt_cbc( 329 | pTemp + offset, DEFAULT_PAGESIZE - reserve - offset, 330 | pDecryptPerPageBuffer + offset, 331 | key_schedule, 256, 332 | pTemp + (DEFAULT_PAGESIZE - reserve) 333 | ); 334 | 335 | 336 | memcpy(pDecryptPerPageBuffer + DEFAULT_PAGESIZE - reserve, 337 | pTemp + DEFAULT_PAGESIZE - reserve, 338 | reserve); 339 | 340 | //将解密后的数据写入到文件中 341 | char decFile[1024] = { 0 }; 342 | sprintf_s(decFile, 1024, "dec_%s", dbfilename); 343 | 344 | FILE * fp; 345 | fopen_s(&fp, decFile, "ab+"); 346 | fwrite(pDecryptPerPageBuffer, 1, DEFAULT_PAGESIZE, fp); 347 | fclose(fp); 348 | 349 | nPage++; 350 | offset = 0; 351 | pTemp += DEFAULT_PAGESIZE; 352 | } 353 | printf("\n 解密成功! \n"); 354 | printf("\n dec_%s文件可用navicat之类的软件读取! \n", dbfilename); 355 | 356 | getchar(); 357 | return TRUE; 358 | } -------------------------------------------------------------------------------- /crypto/aes.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | 6 | #include 7 | #include "aes.h" 8 | 9 | #define KE_ROTWORD(x) (((x) << 8) | ((x) >> 24)) 10 | 11 | #define TRUE 1 12 | #define FALSE 0 13 | 14 | 15 | #define AES_128_ROUNDS 10 16 | #define AES_192_ROUNDS 12 17 | #define AES_256_ROUNDS 14 18 | 19 | 20 | 21 | static const BYTE aes_sbox[16][16] = { 22 | { 0x63,0x7C,0x77,0x7B,0xF2,0x6B,0x6F,0xC5,0x30,0x01,0x67,0x2B,0xFE,0xD7,0xAB,0x76 }, 23 | { 0xCA,0x82,0xC9,0x7D,0xFA,0x59,0x47,0xF0,0xAD,0xD4,0xA2,0xAF,0x9C,0xA4,0x72,0xC0 }, 24 | { 0xB7,0xFD,0x93,0x26,0x36,0x3F,0xF7,0xCC,0x34,0xA5,0xE5,0xF1,0x71,0xD8,0x31,0x15 }, 25 | { 0x04,0xC7,0x23,0xC3,0x18,0x96,0x05,0x9A,0x07,0x12,0x80,0xE2,0xEB,0x27,0xB2,0x75 }, 26 | { 0x09,0x83,0x2C,0x1A,0x1B,0x6E,0x5A,0xA0,0x52,0x3B,0xD6,0xB3,0x29,0xE3,0x2F,0x84 }, 27 | { 0x53,0xD1,0x00,0xED,0x20,0xFC,0xB1,0x5B,0x6A,0xCB,0xBE,0x39,0x4A,0x4C,0x58,0xCF }, 28 | { 0xD0,0xEF,0xAA,0xFB,0x43,0x4D,0x33,0x85,0x45,0xF9,0x02,0x7F,0x50,0x3C,0x9F,0xA8 }, 29 | { 0x51,0xA3,0x40,0x8F,0x92,0x9D,0x38,0xF5,0xBC,0xB6,0xDA,0x21,0x10,0xFF,0xF3,0xD2 }, 30 | { 0xCD,0x0C,0x13,0xEC,0x5F,0x97,0x44,0x17,0xC4,0xA7,0x7E,0x3D,0x64,0x5D,0x19,0x73 }, 31 | { 0x60,0x81,0x4F,0xDC,0x22,0x2A,0x90,0x88,0x46,0xEE,0xB8,0x14,0xDE,0x5E,0x0B,0xDB }, 32 | { 0xE0,0x32,0x3A,0x0A,0x49,0x06,0x24,0x5C,0xC2,0xD3,0xAC,0x62,0x91,0x95,0xE4,0x79 }, 33 | { 0xE7,0xC8,0x37,0x6D,0x8D,0xD5,0x4E,0xA9,0x6C,0x56,0xF4,0xEA,0x65,0x7A,0xAE,0x08 }, 34 | { 0xBA,0x78,0x25,0x2E,0x1C,0xA6,0xB4,0xC6,0xE8,0xDD,0x74,0x1F,0x4B,0xBD,0x8B,0x8A }, 35 | { 0x70,0x3E,0xB5,0x66,0x48,0x03,0xF6,0x0E,0x61,0x35,0x57,0xB9,0x86,0xC1,0x1D,0x9E }, 36 | { 0xE1,0xF8,0x98,0x11,0x69,0xD9,0x8E,0x94,0x9B,0x1E,0x87,0xE9,0xCE,0x55,0x28,0xDF }, 37 | { 0x8C,0xA1,0x89,0x0D,0xBF,0xE6,0x42,0x68,0x41,0x99,0x2D,0x0F,0xB0,0x54,0xBB,0x16 } 38 | }; 39 | 40 | static const BYTE aes_invsbox[16][16] = { 41 | { 0x52,0x09,0x6A,0xD5,0x30,0x36,0xA5,0x38,0xBF,0x40,0xA3,0x9E,0x81,0xF3,0xD7,0xFB }, 42 | { 0x7C,0xE3,0x39,0x82,0x9B,0x2F,0xFF,0x87,0x34,0x8E,0x43,0x44,0xC4,0xDE,0xE9,0xCB }, 43 | { 0x54,0x7B,0x94,0x32,0xA6,0xC2,0x23,0x3D,0xEE,0x4C,0x95,0x0B,0x42,0xFA,0xC3,0x4E }, 44 | { 0x08,0x2E,0xA1,0x66,0x28,0xD9,0x24,0xB2,0x76,0x5B,0xA2,0x49,0x6D,0x8B,0xD1,0x25 }, 45 | { 0x72,0xF8,0xF6,0x64,0x86,0x68,0x98,0x16,0xD4,0xA4,0x5C,0xCC,0x5D,0x65,0xB6,0x92 }, 46 | { 0x6C,0x70,0x48,0x50,0xFD,0xED,0xB9,0xDA,0x5E,0x15,0x46,0x57,0xA7,0x8D,0x9D,0x84 }, 47 | { 0x90,0xD8,0xAB,0x00,0x8C,0xBC,0xD3,0x0A,0xF7,0xE4,0x58,0x05,0xB8,0xB3,0x45,0x06 }, 48 | { 0xD0,0x2C,0x1E,0x8F,0xCA,0x3F,0x0F,0x02,0xC1,0xAF,0xBD,0x03,0x01,0x13,0x8A,0x6B }, 49 | { 0x3A,0x91,0x11,0x41,0x4F,0x67,0xDC,0xEA,0x97,0xF2,0xCF,0xCE,0xF0,0xB4,0xE6,0x73 }, 50 | { 0x96,0xAC,0x74,0x22,0xE7,0xAD,0x35,0x85,0xE2,0xF9,0x37,0xE8,0x1C,0x75,0xDF,0x6E }, 51 | { 0x47,0xF1,0x1A,0x71,0x1D,0x29,0xC5,0x89,0x6F,0xB7,0x62,0x0E,0xAA,0x18,0xBE,0x1B }, 52 | { 0xFC,0x56,0x3E,0x4B,0xC6,0xD2,0x79,0x20,0x9A,0xDB,0xC0,0xFE,0x78,0xCD,0x5A,0xF4 }, 53 | { 0x1F,0xDD,0xA8,0x33,0x88,0x07,0xC7,0x31,0xB1,0x12,0x10,0x59,0x27,0x80,0xEC,0x5F }, 54 | { 0x60,0x51,0x7F,0xA9,0x19,0xB5,0x4A,0x0D,0x2D,0xE5,0x7A,0x9F,0x93,0xC9,0x9C,0xEF }, 55 | { 0xA0,0xE0,0x3B,0x4D,0xAE,0x2A,0xF5,0xB0,0xC8,0xEB,0xBB,0x3C,0x83,0x53,0x99,0x61 }, 56 | { 0x17,0x2B,0x04,0x7E,0xBA,0x77,0xD6,0x26,0xE1,0x69,0x14,0x63,0x55,0x21,0x0C,0x7D } 57 | }; 58 | 59 | 60 | static const BYTE gf_mul[256][6] = { 61 | { 0x00,0x00,0x00,0x00,0x00,0x00 },{ 0x02,0x03,0x09,0x0b,0x0d,0x0e }, 62 | { 0x04,0x06,0x12,0x16,0x1a,0x1c },{ 0x06,0x05,0x1b,0x1d,0x17,0x12 }, 63 | { 0x08,0x0c,0x24,0x2c,0x34,0x38 },{ 0x0a,0x0f,0x2d,0x27,0x39,0x36 }, 64 | { 0x0c,0x0a,0x36,0x3a,0x2e,0x24 },{ 0x0e,0x09,0x3f,0x31,0x23,0x2a }, 65 | { 0x10,0x18,0x48,0x58,0x68,0x70 },{ 0x12,0x1b,0x41,0x53,0x65,0x7e }, 66 | { 0x14,0x1e,0x5a,0x4e,0x72,0x6c },{ 0x16,0x1d,0x53,0x45,0x7f,0x62 }, 67 | { 0x18,0x14,0x6c,0x74,0x5c,0x48 },{ 0x1a,0x17,0x65,0x7f,0x51,0x46 }, 68 | { 0x1c,0x12,0x7e,0x62,0x46,0x54 },{ 0x1e,0x11,0x77,0x69,0x4b,0x5a }, 69 | { 0x20,0x30,0x90,0xb0,0xd0,0xe0 },{ 0x22,0x33,0x99,0xbb,0xdd,0xee }, 70 | { 0x24,0x36,0x82,0xa6,0xca,0xfc },{ 0x26,0x35,0x8b,0xad,0xc7,0xf2 }, 71 | { 0x28,0x3c,0xb4,0x9c,0xe4,0xd8 },{ 0x2a,0x3f,0xbd,0x97,0xe9,0xd6 }, 72 | { 0x2c,0x3a,0xa6,0x8a,0xfe,0xc4 },{ 0x2e,0x39,0xaf,0x81,0xf3,0xca }, 73 | { 0x30,0x28,0xd8,0xe8,0xb8,0x90 },{ 0x32,0x2b,0xd1,0xe3,0xb5,0x9e }, 74 | { 0x34,0x2e,0xca,0xfe,0xa2,0x8c },{ 0x36,0x2d,0xc3,0xf5,0xaf,0x82 }, 75 | { 0x38,0x24,0xfc,0xc4,0x8c,0xa8 },{ 0x3a,0x27,0xf5,0xcf,0x81,0xa6 }, 76 | { 0x3c,0x22,0xee,0xd2,0x96,0xb4 },{ 0x3e,0x21,0xe7,0xd9,0x9b,0xba }, 77 | { 0x40,0x60,0x3b,0x7b,0xbb,0xdb },{ 0x42,0x63,0x32,0x70,0xb6,0xd5 }, 78 | { 0x44,0x66,0x29,0x6d,0xa1,0xc7 },{ 0x46,0x65,0x20,0x66,0xac,0xc9 }, 79 | { 0x48,0x6c,0x1f,0x57,0x8f,0xe3 },{ 0x4a,0x6f,0x16,0x5c,0x82,0xed }, 80 | { 0x4c,0x6a,0x0d,0x41,0x95,0xff },{ 0x4e,0x69,0x04,0x4a,0x98,0xf1 }, 81 | { 0x50,0x78,0x73,0x23,0xd3,0xab },{ 0x52,0x7b,0x7a,0x28,0xde,0xa5 }, 82 | { 0x54,0x7e,0x61,0x35,0xc9,0xb7 },{ 0x56,0x7d,0x68,0x3e,0xc4,0xb9 }, 83 | { 0x58,0x74,0x57,0x0f,0xe7,0x93 },{ 0x5a,0x77,0x5e,0x04,0xea,0x9d }, 84 | { 0x5c,0x72,0x45,0x19,0xfd,0x8f },{ 0x5e,0x71,0x4c,0x12,0xf0,0x81 }, 85 | { 0x60,0x50,0xab,0xcb,0x6b,0x3b },{ 0x62,0x53,0xa2,0xc0,0x66,0x35 }, 86 | { 0x64,0x56,0xb9,0xdd,0x71,0x27 },{ 0x66,0x55,0xb0,0xd6,0x7c,0x29 }, 87 | { 0x68,0x5c,0x8f,0xe7,0x5f,0x03 },{ 0x6a,0x5f,0x86,0xec,0x52,0x0d }, 88 | { 0x6c,0x5a,0x9d,0xf1,0x45,0x1f },{ 0x6e,0x59,0x94,0xfa,0x48,0x11 }, 89 | { 0x70,0x48,0xe3,0x93,0x03,0x4b },{ 0x72,0x4b,0xea,0x98,0x0e,0x45 }, 90 | { 0x74,0x4e,0xf1,0x85,0x19,0x57 },{ 0x76,0x4d,0xf8,0x8e,0x14,0x59 }, 91 | { 0x78,0x44,0xc7,0xbf,0x37,0x73 },{ 0x7a,0x47,0xce,0xb4,0x3a,0x7d }, 92 | { 0x7c,0x42,0xd5,0xa9,0x2d,0x6f },{ 0x7e,0x41,0xdc,0xa2,0x20,0x61 }, 93 | { 0x80,0xc0,0x76,0xf6,0x6d,0xad },{ 0x82,0xc3,0x7f,0xfd,0x60,0xa3 }, 94 | { 0x84,0xc6,0x64,0xe0,0x77,0xb1 },{ 0x86,0xc5,0x6d,0xeb,0x7a,0xbf }, 95 | { 0x88,0xcc,0x52,0xda,0x59,0x95 },{ 0x8a,0xcf,0x5b,0xd1,0x54,0x9b }, 96 | { 0x8c,0xca,0x40,0xcc,0x43,0x89 },{ 0x8e,0xc9,0x49,0xc7,0x4e,0x87 }, 97 | { 0x90,0xd8,0x3e,0xae,0x05,0xdd },{ 0x92,0xdb,0x37,0xa5,0x08,0xd3 }, 98 | { 0x94,0xde,0x2c,0xb8,0x1f,0xc1 },{ 0x96,0xdd,0x25,0xb3,0x12,0xcf }, 99 | { 0x98,0xd4,0x1a,0x82,0x31,0xe5 },{ 0x9a,0xd7,0x13,0x89,0x3c,0xeb }, 100 | { 0x9c,0xd2,0x08,0x94,0x2b,0xf9 },{ 0x9e,0xd1,0x01,0x9f,0x26,0xf7 }, 101 | { 0xa0,0xf0,0xe6,0x46,0xbd,0x4d },{ 0xa2,0xf3,0xef,0x4d,0xb0,0x43 }, 102 | { 0xa4,0xf6,0xf4,0x50,0xa7,0x51 },{ 0xa6,0xf5,0xfd,0x5b,0xaa,0x5f }, 103 | { 0xa8,0xfc,0xc2,0x6a,0x89,0x75 },{ 0xaa,0xff,0xcb,0x61,0x84,0x7b }, 104 | { 0xac,0xfa,0xd0,0x7c,0x93,0x69 },{ 0xae,0xf9,0xd9,0x77,0x9e,0x67 }, 105 | { 0xb0,0xe8,0xae,0x1e,0xd5,0x3d },{ 0xb2,0xeb,0xa7,0x15,0xd8,0x33 }, 106 | { 0xb4,0xee,0xbc,0x08,0xcf,0x21 },{ 0xb6,0xed,0xb5,0x03,0xc2,0x2f }, 107 | { 0xb8,0xe4,0x8a,0x32,0xe1,0x05 },{ 0xba,0xe7,0x83,0x39,0xec,0x0b }, 108 | { 0xbc,0xe2,0x98,0x24,0xfb,0x19 },{ 0xbe,0xe1,0x91,0x2f,0xf6,0x17 }, 109 | { 0xc0,0xa0,0x4d,0x8d,0xd6,0x76 },{ 0xc2,0xa3,0x44,0x86,0xdb,0x78 }, 110 | { 0xc4,0xa6,0x5f,0x9b,0xcc,0x6a },{ 0xc6,0xa5,0x56,0x90,0xc1,0x64 }, 111 | { 0xc8,0xac,0x69,0xa1,0xe2,0x4e },{ 0xca,0xaf,0x60,0xaa,0xef,0x40 }, 112 | { 0xcc,0xaa,0x7b,0xb7,0xf8,0x52 },{ 0xce,0xa9,0x72,0xbc,0xf5,0x5c }, 113 | { 0xd0,0xb8,0x05,0xd5,0xbe,0x06 },{ 0xd2,0xbb,0x0c,0xde,0xb3,0x08 }, 114 | { 0xd4,0xbe,0x17,0xc3,0xa4,0x1a },{ 0xd6,0xbd,0x1e,0xc8,0xa9,0x14 }, 115 | { 0xd8,0xb4,0x21,0xf9,0x8a,0x3e },{ 0xda,0xb7,0x28,0xf2,0x87,0x30 }, 116 | { 0xdc,0xb2,0x33,0xef,0x90,0x22 },{ 0xde,0xb1,0x3a,0xe4,0x9d,0x2c }, 117 | { 0xe0,0x90,0xdd,0x3d,0x06,0x96 },{ 0xe2,0x93,0xd4,0x36,0x0b,0x98 }, 118 | { 0xe4,0x96,0xcf,0x2b,0x1c,0x8a },{ 0xe6,0x95,0xc6,0x20,0x11,0x84 }, 119 | { 0xe8,0x9c,0xf9,0x11,0x32,0xae },{ 0xea,0x9f,0xf0,0x1a,0x3f,0xa0 }, 120 | { 0xec,0x9a,0xeb,0x07,0x28,0xb2 },{ 0xee,0x99,0xe2,0x0c,0x25,0xbc }, 121 | { 0xf0,0x88,0x95,0x65,0x6e,0xe6 },{ 0xf2,0x8b,0x9c,0x6e,0x63,0xe8 }, 122 | { 0xf4,0x8e,0x87,0x73,0x74,0xfa },{ 0xf6,0x8d,0x8e,0x78,0x79,0xf4 }, 123 | { 0xf8,0x84,0xb1,0x49,0x5a,0xde },{ 0xfa,0x87,0xb8,0x42,0x57,0xd0 }, 124 | { 0xfc,0x82,0xa3,0x5f,0x40,0xc2 },{ 0xfe,0x81,0xaa,0x54,0x4d,0xcc }, 125 | { 0x1b,0x9b,0xec,0xf7,0xda,0x41 },{ 0x19,0x98,0xe5,0xfc,0xd7,0x4f }, 126 | { 0x1f,0x9d,0xfe,0xe1,0xc0,0x5d },{ 0x1d,0x9e,0xf7,0xea,0xcd,0x53 }, 127 | { 0x13,0x97,0xc8,0xdb,0xee,0x79 },{ 0x11,0x94,0xc1,0xd0,0xe3,0x77 }, 128 | { 0x17,0x91,0xda,0xcd,0xf4,0x65 },{ 0x15,0x92,0xd3,0xc6,0xf9,0x6b }, 129 | { 0x0b,0x83,0xa4,0xaf,0xb2,0x31 },{ 0x09,0x80,0xad,0xa4,0xbf,0x3f }, 130 | { 0x0f,0x85,0xb6,0xb9,0xa8,0x2d },{ 0x0d,0x86,0xbf,0xb2,0xa5,0x23 }, 131 | { 0x03,0x8f,0x80,0x83,0x86,0x09 },{ 0x01,0x8c,0x89,0x88,0x8b,0x07 }, 132 | { 0x07,0x89,0x92,0x95,0x9c,0x15 },{ 0x05,0x8a,0x9b,0x9e,0x91,0x1b }, 133 | { 0x3b,0xab,0x7c,0x47,0x0a,0xa1 },{ 0x39,0xa8,0x75,0x4c,0x07,0xaf }, 134 | { 0x3f,0xad,0x6e,0x51,0x10,0xbd },{ 0x3d,0xae,0x67,0x5a,0x1d,0xb3 }, 135 | { 0x33,0xa7,0x58,0x6b,0x3e,0x99 },{ 0x31,0xa4,0x51,0x60,0x33,0x97 }, 136 | { 0x37,0xa1,0x4a,0x7d,0x24,0x85 },{ 0x35,0xa2,0x43,0x76,0x29,0x8b }, 137 | { 0x2b,0xb3,0x34,0x1f,0x62,0xd1 },{ 0x29,0xb0,0x3d,0x14,0x6f,0xdf }, 138 | { 0x2f,0xb5,0x26,0x09,0x78,0xcd },{ 0x2d,0xb6,0x2f,0x02,0x75,0xc3 }, 139 | { 0x23,0xbf,0x10,0x33,0x56,0xe9 },{ 0x21,0xbc,0x19,0x38,0x5b,0xe7 }, 140 | { 0x27,0xb9,0x02,0x25,0x4c,0xf5 },{ 0x25,0xba,0x0b,0x2e,0x41,0xfb }, 141 | { 0x5b,0xfb,0xd7,0x8c,0x61,0x9a },{ 0x59,0xf8,0xde,0x87,0x6c,0x94 }, 142 | { 0x5f,0xfd,0xc5,0x9a,0x7b,0x86 },{ 0x5d,0xfe,0xcc,0x91,0x76,0x88 }, 143 | { 0x53,0xf7,0xf3,0xa0,0x55,0xa2 },{ 0x51,0xf4,0xfa,0xab,0x58,0xac }, 144 | { 0x57,0xf1,0xe1,0xb6,0x4f,0xbe },{ 0x55,0xf2,0xe8,0xbd,0x42,0xb0 }, 145 | { 0x4b,0xe3,0x9f,0xd4,0x09,0xea },{ 0x49,0xe0,0x96,0xdf,0x04,0xe4 }, 146 | { 0x4f,0xe5,0x8d,0xc2,0x13,0xf6 },{ 0x4d,0xe6,0x84,0xc9,0x1e,0xf8 }, 147 | { 0x43,0xef,0xbb,0xf8,0x3d,0xd2 },{ 0x41,0xec,0xb2,0xf3,0x30,0xdc }, 148 | { 0x47,0xe9,0xa9,0xee,0x27,0xce },{ 0x45,0xea,0xa0,0xe5,0x2a,0xc0 }, 149 | { 0x7b,0xcb,0x47,0x3c,0xb1,0x7a },{ 0x79,0xc8,0x4e,0x37,0xbc,0x74 }, 150 | { 0x7f,0xcd,0x55,0x2a,0xab,0x66 },{ 0x7d,0xce,0x5c,0x21,0xa6,0x68 }, 151 | { 0x73,0xc7,0x63,0x10,0x85,0x42 },{ 0x71,0xc4,0x6a,0x1b,0x88,0x4c }, 152 | { 0x77,0xc1,0x71,0x06,0x9f,0x5e },{ 0x75,0xc2,0x78,0x0d,0x92,0x50 }, 153 | { 0x6b,0xd3,0x0f,0x64,0xd9,0x0a },{ 0x69,0xd0,0x06,0x6f,0xd4,0x04 }, 154 | { 0x6f,0xd5,0x1d,0x72,0xc3,0x16 },{ 0x6d,0xd6,0x14,0x79,0xce,0x18 }, 155 | { 0x63,0xdf,0x2b,0x48,0xed,0x32 },{ 0x61,0xdc,0x22,0x43,0xe0,0x3c }, 156 | { 0x67,0xd9,0x39,0x5e,0xf7,0x2e },{ 0x65,0xda,0x30,0x55,0xfa,0x20 }, 157 | { 0x9b,0x5b,0x9a,0x01,0xb7,0xec },{ 0x99,0x58,0x93,0x0a,0xba,0xe2 }, 158 | { 0x9f,0x5d,0x88,0x17,0xad,0xf0 },{ 0x9d,0x5e,0x81,0x1c,0xa0,0xfe }, 159 | { 0x93,0x57,0xbe,0x2d,0x83,0xd4 },{ 0x91,0x54,0xb7,0x26,0x8e,0xda }, 160 | { 0x97,0x51,0xac,0x3b,0x99,0xc8 },{ 0x95,0x52,0xa5,0x30,0x94,0xc6 }, 161 | { 0x8b,0x43,0xd2,0x59,0xdf,0x9c },{ 0x89,0x40,0xdb,0x52,0xd2,0x92 }, 162 | { 0x8f,0x45,0xc0,0x4f,0xc5,0x80 },{ 0x8d,0x46,0xc9,0x44,0xc8,0x8e }, 163 | { 0x83,0x4f,0xf6,0x75,0xeb,0xa4 },{ 0x81,0x4c,0xff,0x7e,0xe6,0xaa }, 164 | { 0x87,0x49,0xe4,0x63,0xf1,0xb8 },{ 0x85,0x4a,0xed,0x68,0xfc,0xb6 }, 165 | { 0xbb,0x6b,0x0a,0xb1,0x67,0x0c },{ 0xb9,0x68,0x03,0xba,0x6a,0x02 }, 166 | { 0xbf,0x6d,0x18,0xa7,0x7d,0x10 },{ 0xbd,0x6e,0x11,0xac,0x70,0x1e }, 167 | { 0xb3,0x67,0x2e,0x9d,0x53,0x34 },{ 0xb1,0x64,0x27,0x96,0x5e,0x3a }, 168 | { 0xb7,0x61,0x3c,0x8b,0x49,0x28 },{ 0xb5,0x62,0x35,0x80,0x44,0x26 }, 169 | { 0xab,0x73,0x42,0xe9,0x0f,0x7c },{ 0xa9,0x70,0x4b,0xe2,0x02,0x72 }, 170 | { 0xaf,0x75,0x50,0xff,0x15,0x60 },{ 0xad,0x76,0x59,0xf4,0x18,0x6e }, 171 | { 0xa3,0x7f,0x66,0xc5,0x3b,0x44 },{ 0xa1,0x7c,0x6f,0xce,0x36,0x4a }, 172 | { 0xa7,0x79,0x74,0xd3,0x21,0x58 },{ 0xa5,0x7a,0x7d,0xd8,0x2c,0x56 }, 173 | { 0xdb,0x3b,0xa1,0x7a,0x0c,0x37 },{ 0xd9,0x38,0xa8,0x71,0x01,0x39 }, 174 | { 0xdf,0x3d,0xb3,0x6c,0x16,0x2b },{ 0xdd,0x3e,0xba,0x67,0x1b,0x25 }, 175 | { 0xd3,0x37,0x85,0x56,0x38,0x0f },{ 0xd1,0x34,0x8c,0x5d,0x35,0x01 }, 176 | { 0xd7,0x31,0x97,0x40,0x22,0x13 },{ 0xd5,0x32,0x9e,0x4b,0x2f,0x1d }, 177 | { 0xcb,0x23,0xe9,0x22,0x64,0x47 },{ 0xc9,0x20,0xe0,0x29,0x69,0x49 }, 178 | { 0xcf,0x25,0xfb,0x34,0x7e,0x5b },{ 0xcd,0x26,0xf2,0x3f,0x73,0x55 }, 179 | { 0xc3,0x2f,0xcd,0x0e,0x50,0x7f },{ 0xc1,0x2c,0xc4,0x05,0x5d,0x71 }, 180 | { 0xc7,0x29,0xdf,0x18,0x4a,0x63 },{ 0xc5,0x2a,0xd6,0x13,0x47,0x6d }, 181 | { 0xfb,0x0b,0x31,0xca,0xdc,0xd7 },{ 0xf9,0x08,0x38,0xc1,0xd1,0xd9 }, 182 | { 0xff,0x0d,0x23,0xdc,0xc6,0xcb },{ 0xfd,0x0e,0x2a,0xd7,0xcb,0xc5 }, 183 | { 0xf3,0x07,0x15,0xe6,0xe8,0xef },{ 0xf1,0x04,0x1c,0xed,0xe5,0xe1 }, 184 | { 0xf7,0x01,0x07,0xf0,0xf2,0xf3 },{ 0xf5,0x02,0x0e,0xfb,0xff,0xfd }, 185 | { 0xeb,0x13,0x79,0x92,0xb4,0xa7 },{ 0xe9,0x10,0x70,0x99,0xb9,0xa9 }, 186 | { 0xef,0x15,0x6b,0x84,0xae,0xbb },{ 0xed,0x16,0x62,0x8f,0xa3,0xb5 }, 187 | { 0xe3,0x1f,0x5d,0xbe,0x80,0x9f },{ 0xe1,0x1c,0x54,0xb5,0x8d,0x91 }, 188 | { 0xe7,0x19,0x4f,0xa8,0x9a,0x83 },{ 0xe5,0x1a,0x46,0xa3,0x97,0x8d } 189 | }; 190 | 191 | 192 | // XORs the in and out buffers, storing the result in out. Length is in bytes. 193 | void xor_buf(const BYTE in[], BYTE out[], size_t len) 194 | { 195 | size_t idx; 196 | 197 | for (idx = 0; idx < len; idx++) 198 | out[idx] ^= in[idx]; 199 | } 200 | 201 | 202 | int aes_encrypt_cbc(const BYTE in[], size_t in_len, BYTE out[], const DWORD key[], int keysize, const BYTE iv[]) 203 | { 204 | BYTE buf_in[AES_BLOCK_SIZE], buf_out[AES_BLOCK_SIZE], iv_buf[AES_BLOCK_SIZE]; 205 | int blocks, idx; 206 | 207 | if (in_len % AES_BLOCK_SIZE != 0) 208 | return(FALSE); 209 | 210 | blocks = in_len / AES_BLOCK_SIZE; 211 | 212 | memcpy(iv_buf, iv, AES_BLOCK_SIZE); 213 | 214 | for (idx = 0; idx < blocks; idx++) { 215 | memcpy(buf_in, &in[idx * AES_BLOCK_SIZE], AES_BLOCK_SIZE); 216 | xor_buf(iv_buf, buf_in, AES_BLOCK_SIZE); 217 | aes_encrypt(buf_in, buf_out, key, keysize); 218 | memcpy(&out[idx * AES_BLOCK_SIZE], buf_out, AES_BLOCK_SIZE); 219 | memcpy(iv_buf, buf_out, AES_BLOCK_SIZE); 220 | } 221 | 222 | return(TRUE); 223 | } 224 | 225 | int aes_encrypt_cbc_mac(const BYTE in[], size_t in_len, BYTE out[], const DWORD key[], int keysize, const BYTE iv[]) 226 | { 227 | BYTE buf_in[AES_BLOCK_SIZE], buf_out[AES_BLOCK_SIZE], iv_buf[AES_BLOCK_SIZE]; 228 | int blocks, idx; 229 | 230 | if (in_len % AES_BLOCK_SIZE != 0) 231 | return(FALSE); 232 | 233 | blocks = in_len / AES_BLOCK_SIZE; 234 | 235 | memcpy(iv_buf, iv, AES_BLOCK_SIZE); 236 | 237 | for (idx = 0; idx < blocks; idx++) { 238 | memcpy(buf_in, &in[idx * AES_BLOCK_SIZE], AES_BLOCK_SIZE); 239 | xor_buf(iv_buf, buf_in, AES_BLOCK_SIZE); 240 | aes_encrypt(buf_in, buf_out, key, keysize); 241 | memcpy(iv_buf, buf_out, AES_BLOCK_SIZE); 242 | } 243 | 244 | memcpy(out, buf_out, AES_BLOCK_SIZE); // Only output the last block. 245 | 246 | return(TRUE); 247 | } 248 | 249 | int aes_decrypt_cbc(const BYTE in[], size_t in_len, BYTE out[], const DWORD key[], int keysize, const BYTE iv[]) 250 | { 251 | BYTE buf_in[AES_BLOCK_SIZE], buf_out[AES_BLOCK_SIZE], iv_buf[AES_BLOCK_SIZE]; 252 | int blocks, idx; 253 | 254 | if (in_len % AES_BLOCK_SIZE != 0) 255 | return(FALSE); 256 | 257 | blocks = in_len / AES_BLOCK_SIZE; 258 | 259 | memcpy(iv_buf, iv, AES_BLOCK_SIZE); 260 | 261 | for (idx = 0; idx < blocks; idx++) { 262 | memcpy(buf_in, &in[idx * AES_BLOCK_SIZE], AES_BLOCK_SIZE); 263 | aes_decrypt(buf_in, buf_out, key, keysize); 264 | xor_buf(iv_buf, buf_out, AES_BLOCK_SIZE); 265 | memcpy(&out[idx * AES_BLOCK_SIZE], buf_out, AES_BLOCK_SIZE); 266 | memcpy(iv_buf, buf_in, AES_BLOCK_SIZE); 267 | } 268 | 269 | return(TRUE); 270 | } 271 | 272 | 273 | /** 274 | * AES 275 | */ 276 | 277 | // KEY EXPANSION 278 | // Substitutes a word using the AES S-Box. 279 | DWORD SubWord(DWORD word) 280 | { 281 | unsigned int result; 282 | 283 | result = (int)aes_sbox[(word >> 4) & 0x0000000F][word & 0x0000000F]; 284 | result += (int)aes_sbox[(word >> 12) & 0x0000000F][(word >> 8) & 0x0000000F] << 8; 285 | result += (int)aes_sbox[(word >> 20) & 0x0000000F][(word >> 16) & 0x0000000F] << 16; 286 | result += (int)aes_sbox[(word >> 28) & 0x0000000F][(word >> 24) & 0x0000000F] << 24; 287 | return(result); 288 | } 289 | 290 | 291 | void aes_key_setup(const BYTE key[], DWORD w[], int keysize) 292 | { 293 | int Nb = 4, Nr, Nk, idx; 294 | DWORD temp, Rcon[] = { 0x01000000,0x02000000,0x04000000,0x08000000,0x10000000,0x20000000, 295 | 0x40000000,0x80000000,0x1b000000,0x36000000,0x6c000000,0xd8000000, 296 | 0xab000000,0x4d000000,0x9a000000 }; 297 | 298 | switch (keysize) { 299 | case 128: Nr = 10; Nk = 4; break; 300 | case 192: Nr = 12; Nk = 6; break; 301 | case 256: Nr = 14; Nk = 8; break; 302 | default: return; 303 | } 304 | 305 | for (idx = 0; idx < Nk; ++idx) { 306 | w[idx] = ((key[4 * idx]) << 24) | ((key[4 * idx + 1]) << 16) | 307 | ((key[4 * idx + 2]) << 8) | ((key[4 * idx + 3])); 308 | } 309 | 310 | for (idx = Nk; idx < Nb * (Nr + 1); ++idx) { 311 | temp = w[idx - 1]; 312 | if ((idx % Nk) == 0) 313 | temp = SubWord(KE_ROTWORD(temp)) ^ Rcon[(idx - 1) / Nk]; 314 | else if (Nk > 6 && (idx % Nk) == 4) 315 | temp = SubWord(temp); 316 | w[idx] = w[idx - Nk] ^ temp; 317 | } 318 | } 319 | 320 | 321 | // ADD ROUND KEY 322 | void AddRoundKey(BYTE state[][4], const DWORD w[]) 323 | { 324 | BYTE subkey[4]; 325 | 326 | // Subkey 1 327 | subkey[0] = w[0] >> 24; 328 | subkey[1] = w[0] >> 16; 329 | subkey[2] = w[0] >> 8; 330 | subkey[3] = w[0]; 331 | state[0][0] ^= subkey[0]; 332 | state[1][0] ^= subkey[1]; 333 | state[2][0] ^= subkey[2]; 334 | state[3][0] ^= subkey[3]; 335 | // Subkey 2 336 | subkey[0] = w[1] >> 24; 337 | subkey[1] = w[1] >> 16; 338 | subkey[2] = w[1] >> 8; 339 | subkey[3] = w[1]; 340 | state[0][1] ^= subkey[0]; 341 | state[1][1] ^= subkey[1]; 342 | state[2][1] ^= subkey[2]; 343 | state[3][1] ^= subkey[3]; 344 | // Subkey 3 345 | subkey[0] = w[2] >> 24; 346 | subkey[1] = w[2] >> 16; 347 | subkey[2] = w[2] >> 8; 348 | subkey[3] = w[2]; 349 | state[0][2] ^= subkey[0]; 350 | state[1][2] ^= subkey[1]; 351 | state[2][2] ^= subkey[2]; 352 | state[3][2] ^= subkey[3]; 353 | // Subkey 4 354 | subkey[0] = w[3] >> 24; 355 | subkey[1] = w[3] >> 16; 356 | subkey[2] = w[3] >> 8; 357 | subkey[3] = w[3]; 358 | state[0][3] ^= subkey[0]; 359 | state[1][3] ^= subkey[1]; 360 | state[2][3] ^= subkey[2]; 361 | state[3][3] ^= subkey[3]; 362 | } 363 | 364 | 365 | // (Inv)SubBytes 366 | void SubBytes(BYTE state[][4]) 367 | { 368 | state[0][0] = aes_sbox[state[0][0] >> 4][state[0][0] & 0x0F]; 369 | state[0][1] = aes_sbox[state[0][1] >> 4][state[0][1] & 0x0F]; 370 | state[0][2] = aes_sbox[state[0][2] >> 4][state[0][2] & 0x0F]; 371 | state[0][3] = aes_sbox[state[0][3] >> 4][state[0][3] & 0x0F]; 372 | state[1][0] = aes_sbox[state[1][0] >> 4][state[1][0] & 0x0F]; 373 | state[1][1] = aes_sbox[state[1][1] >> 4][state[1][1] & 0x0F]; 374 | state[1][2] = aes_sbox[state[1][2] >> 4][state[1][2] & 0x0F]; 375 | state[1][3] = aes_sbox[state[1][3] >> 4][state[1][3] & 0x0F]; 376 | state[2][0] = aes_sbox[state[2][0] >> 4][state[2][0] & 0x0F]; 377 | state[2][1] = aes_sbox[state[2][1] >> 4][state[2][1] & 0x0F]; 378 | state[2][2] = aes_sbox[state[2][2] >> 4][state[2][2] & 0x0F]; 379 | state[2][3] = aes_sbox[state[2][3] >> 4][state[2][3] & 0x0F]; 380 | state[3][0] = aes_sbox[state[3][0] >> 4][state[3][0] & 0x0F]; 381 | state[3][1] = aes_sbox[state[3][1] >> 4][state[3][1] & 0x0F]; 382 | state[3][2] = aes_sbox[state[3][2] >> 4][state[3][2] & 0x0F]; 383 | state[3][3] = aes_sbox[state[3][3] >> 4][state[3][3] & 0x0F]; 384 | } 385 | 386 | void InvSubBytes(BYTE state[][4]) 387 | { 388 | state[0][0] = aes_invsbox[state[0][0] >> 4][state[0][0] & 0x0F]; 389 | state[0][1] = aes_invsbox[state[0][1] >> 4][state[0][1] & 0x0F]; 390 | state[0][2] = aes_invsbox[state[0][2] >> 4][state[0][2] & 0x0F]; 391 | state[0][3] = aes_invsbox[state[0][3] >> 4][state[0][3] & 0x0F]; 392 | state[1][0] = aes_invsbox[state[1][0] >> 4][state[1][0] & 0x0F]; 393 | state[1][1] = aes_invsbox[state[1][1] >> 4][state[1][1] & 0x0F]; 394 | state[1][2] = aes_invsbox[state[1][2] >> 4][state[1][2] & 0x0F]; 395 | state[1][3] = aes_invsbox[state[1][3] >> 4][state[1][3] & 0x0F]; 396 | state[2][0] = aes_invsbox[state[2][0] >> 4][state[2][0] & 0x0F]; 397 | state[2][1] = aes_invsbox[state[2][1] >> 4][state[2][1] & 0x0F]; 398 | state[2][2] = aes_invsbox[state[2][2] >> 4][state[2][2] & 0x0F]; 399 | state[2][3] = aes_invsbox[state[2][3] >> 4][state[2][3] & 0x0F]; 400 | state[3][0] = aes_invsbox[state[3][0] >> 4][state[3][0] & 0x0F]; 401 | state[3][1] = aes_invsbox[state[3][1] >> 4][state[3][1] & 0x0F]; 402 | state[3][2] = aes_invsbox[state[3][2] >> 4][state[3][2] & 0x0F]; 403 | state[3][3] = aes_invsbox[state[3][3] >> 4][state[3][3] & 0x0F]; 404 | } 405 | 406 | 407 | // (Inv)ShiftRows 408 | void ShiftRows(BYTE state[][4]) 409 | { 410 | int t; 411 | 412 | // Shift left by 1 413 | t = state[1][0]; 414 | state[1][0] = state[1][1]; 415 | state[1][1] = state[1][2]; 416 | state[1][2] = state[1][3]; 417 | state[1][3] = t; 418 | // Shift left by 2 419 | t = state[2][0]; 420 | state[2][0] = state[2][2]; 421 | state[2][2] = t; 422 | t = state[2][1]; 423 | state[2][1] = state[2][3]; 424 | state[2][3] = t; 425 | // Shift left by 3 426 | t = state[3][0]; 427 | state[3][0] = state[3][3]; 428 | state[3][3] = state[3][2]; 429 | state[3][2] = state[3][1]; 430 | state[3][1] = t; 431 | } 432 | 433 | void InvShiftRows(BYTE state[][4]) 434 | { 435 | int t; 436 | 437 | // Shift right by 1 438 | t = state[1][3]; 439 | state[1][3] = state[1][2]; 440 | state[1][2] = state[1][1]; 441 | state[1][1] = state[1][0]; 442 | state[1][0] = t; 443 | // Shift right by 2 444 | t = state[2][3]; 445 | state[2][3] = state[2][1]; 446 | state[2][1] = t; 447 | t = state[2][2]; 448 | state[2][2] = state[2][0]; 449 | state[2][0] = t; 450 | // Shift right by 3 451 | t = state[3][3]; 452 | state[3][3] = state[3][0]; 453 | state[3][0] = state[3][1]; 454 | state[3][1] = state[3][2]; 455 | state[3][2] = t; 456 | } 457 | 458 | 459 | // (Inv)MixColumns 460 | void MixColumns(BYTE state[][4]) 461 | { 462 | BYTE col[4]; 463 | 464 | // Column 1 465 | col[0] = state[0][0]; 466 | col[1] = state[1][0]; 467 | col[2] = state[2][0]; 468 | col[3] = state[3][0]; 469 | state[0][0] = gf_mul[col[0]][0]; 470 | state[0][0] ^= gf_mul[col[1]][1]; 471 | state[0][0] ^= col[2]; 472 | state[0][0] ^= col[3]; 473 | state[1][0] = col[0]; 474 | state[1][0] ^= gf_mul[col[1]][0]; 475 | state[1][0] ^= gf_mul[col[2]][1]; 476 | state[1][0] ^= col[3]; 477 | state[2][0] = col[0]; 478 | state[2][0] ^= col[1]; 479 | state[2][0] ^= gf_mul[col[2]][0]; 480 | state[2][0] ^= gf_mul[col[3]][1]; 481 | state[3][0] = gf_mul[col[0]][1]; 482 | state[3][0] ^= col[1]; 483 | state[3][0] ^= col[2]; 484 | state[3][0] ^= gf_mul[col[3]][0]; 485 | // Column 2 486 | col[0] = state[0][1]; 487 | col[1] = state[1][1]; 488 | col[2] = state[2][1]; 489 | col[3] = state[3][1]; 490 | state[0][1] = gf_mul[col[0]][0]; 491 | state[0][1] ^= gf_mul[col[1]][1]; 492 | state[0][1] ^= col[2]; 493 | state[0][1] ^= col[3]; 494 | state[1][1] = col[0]; 495 | state[1][1] ^= gf_mul[col[1]][0]; 496 | state[1][1] ^= gf_mul[col[2]][1]; 497 | state[1][1] ^= col[3]; 498 | state[2][1] = col[0]; 499 | state[2][1] ^= col[1]; 500 | state[2][1] ^= gf_mul[col[2]][0]; 501 | state[2][1] ^= gf_mul[col[3]][1]; 502 | state[3][1] = gf_mul[col[0]][1]; 503 | state[3][1] ^= col[1]; 504 | state[3][1] ^= col[2]; 505 | state[3][1] ^= gf_mul[col[3]][0]; 506 | // Column 3 507 | col[0] = state[0][2]; 508 | col[1] = state[1][2]; 509 | col[2] = state[2][2]; 510 | col[3] = state[3][2]; 511 | state[0][2] = gf_mul[col[0]][0]; 512 | state[0][2] ^= gf_mul[col[1]][1]; 513 | state[0][2] ^= col[2]; 514 | state[0][2] ^= col[3]; 515 | state[1][2] = col[0]; 516 | state[1][2] ^= gf_mul[col[1]][0]; 517 | state[1][2] ^= gf_mul[col[2]][1]; 518 | state[1][2] ^= col[3]; 519 | state[2][2] = col[0]; 520 | state[2][2] ^= col[1]; 521 | state[2][2] ^= gf_mul[col[2]][0]; 522 | state[2][2] ^= gf_mul[col[3]][1]; 523 | state[3][2] = gf_mul[col[0]][1]; 524 | state[3][2] ^= col[1]; 525 | state[3][2] ^= col[2]; 526 | state[3][2] ^= gf_mul[col[3]][0]; 527 | // Column 4 528 | col[0] = state[0][3]; 529 | col[1] = state[1][3]; 530 | col[2] = state[2][3]; 531 | col[3] = state[3][3]; 532 | state[0][3] = gf_mul[col[0]][0]; 533 | state[0][3] ^= gf_mul[col[1]][1]; 534 | state[0][3] ^= col[2]; 535 | state[0][3] ^= col[3]; 536 | state[1][3] = col[0]; 537 | state[1][3] ^= gf_mul[col[1]][0]; 538 | state[1][3] ^= gf_mul[col[2]][1]; 539 | state[1][3] ^= col[3]; 540 | state[2][3] = col[0]; 541 | state[2][3] ^= col[1]; 542 | state[2][3] ^= gf_mul[col[2]][0]; 543 | state[2][3] ^= gf_mul[col[3]][1]; 544 | state[3][3] = gf_mul[col[0]][1]; 545 | state[3][3] ^= col[1]; 546 | state[3][3] ^= col[2]; 547 | state[3][3] ^= gf_mul[col[3]][0]; 548 | } 549 | 550 | void InvMixColumns(BYTE state[][4]) 551 | { 552 | BYTE col[4]; 553 | 554 | // Column 1 555 | col[0] = state[0][0]; 556 | col[1] = state[1][0]; 557 | col[2] = state[2][0]; 558 | col[3] = state[3][0]; 559 | state[0][0] = gf_mul[col[0]][5]; 560 | state[0][0] ^= gf_mul[col[1]][3]; 561 | state[0][0] ^= gf_mul[col[2]][4]; 562 | state[0][0] ^= gf_mul[col[3]][2]; 563 | state[1][0] = gf_mul[col[0]][2]; 564 | state[1][0] ^= gf_mul[col[1]][5]; 565 | state[1][0] ^= gf_mul[col[2]][3]; 566 | state[1][0] ^= gf_mul[col[3]][4]; 567 | state[2][0] = gf_mul[col[0]][4]; 568 | state[2][0] ^= gf_mul[col[1]][2]; 569 | state[2][0] ^= gf_mul[col[2]][5]; 570 | state[2][0] ^= gf_mul[col[3]][3]; 571 | state[3][0] = gf_mul[col[0]][3]; 572 | state[3][0] ^= gf_mul[col[1]][4]; 573 | state[3][0] ^= gf_mul[col[2]][2]; 574 | state[3][0] ^= gf_mul[col[3]][5]; 575 | // Column 2 576 | col[0] = state[0][1]; 577 | col[1] = state[1][1]; 578 | col[2] = state[2][1]; 579 | col[3] = state[3][1]; 580 | state[0][1] = gf_mul[col[0]][5]; 581 | state[0][1] ^= gf_mul[col[1]][3]; 582 | state[0][1] ^= gf_mul[col[2]][4]; 583 | state[0][1] ^= gf_mul[col[3]][2]; 584 | state[1][1] = gf_mul[col[0]][2]; 585 | state[1][1] ^= gf_mul[col[1]][5]; 586 | state[1][1] ^= gf_mul[col[2]][3]; 587 | state[1][1] ^= gf_mul[col[3]][4]; 588 | state[2][1] = gf_mul[col[0]][4]; 589 | state[2][1] ^= gf_mul[col[1]][2]; 590 | state[2][1] ^= gf_mul[col[2]][5]; 591 | state[2][1] ^= gf_mul[col[3]][3]; 592 | state[3][1] = gf_mul[col[0]][3]; 593 | state[3][1] ^= gf_mul[col[1]][4]; 594 | state[3][1] ^= gf_mul[col[2]][2]; 595 | state[3][1] ^= gf_mul[col[3]][5]; 596 | // Column 3 597 | col[0] = state[0][2]; 598 | col[1] = state[1][2]; 599 | col[2] = state[2][2]; 600 | col[3] = state[3][2]; 601 | state[0][2] = gf_mul[col[0]][5]; 602 | state[0][2] ^= gf_mul[col[1]][3]; 603 | state[0][2] ^= gf_mul[col[2]][4]; 604 | state[0][2] ^= gf_mul[col[3]][2]; 605 | state[1][2] = gf_mul[col[0]][2]; 606 | state[1][2] ^= gf_mul[col[1]][5]; 607 | state[1][2] ^= gf_mul[col[2]][3]; 608 | state[1][2] ^= gf_mul[col[3]][4]; 609 | state[2][2] = gf_mul[col[0]][4]; 610 | state[2][2] ^= gf_mul[col[1]][2]; 611 | state[2][2] ^= gf_mul[col[2]][5]; 612 | state[2][2] ^= gf_mul[col[3]][3]; 613 | state[3][2] = gf_mul[col[0]][3]; 614 | state[3][2] ^= gf_mul[col[1]][4]; 615 | state[3][2] ^= gf_mul[col[2]][2]; 616 | state[3][2] ^= gf_mul[col[3]][5]; 617 | // Column 4 618 | col[0] = state[0][3]; 619 | col[1] = state[1][3]; 620 | col[2] = state[2][3]; 621 | col[3] = state[3][3]; 622 | state[0][3] = gf_mul[col[0]][5]; 623 | state[0][3] ^= gf_mul[col[1]][3]; 624 | state[0][3] ^= gf_mul[col[2]][4]; 625 | state[0][3] ^= gf_mul[col[3]][2]; 626 | state[1][3] = gf_mul[col[0]][2]; 627 | state[1][3] ^= gf_mul[col[1]][5]; 628 | state[1][3] ^= gf_mul[col[2]][3]; 629 | state[1][3] ^= gf_mul[col[3]][4]; 630 | state[2][3] = gf_mul[col[0]][4]; 631 | state[2][3] ^= gf_mul[col[1]][2]; 632 | state[2][3] ^= gf_mul[col[2]][5]; 633 | state[2][3] ^= gf_mul[col[3]][3]; 634 | state[3][3] = gf_mul[col[0]][3]; 635 | state[3][3] ^= gf_mul[col[1]][4]; 636 | state[3][3] ^= gf_mul[col[2]][2]; 637 | state[3][3] ^= gf_mul[col[3]][5]; 638 | } 639 | 640 | 641 | // (En/De)Crypt 642 | void aes_encrypt(const BYTE in[], BYTE out[], const DWORD key[], int keysize) 643 | { 644 | BYTE state[4][4]; 645 | 646 | state[0][0] = in[0]; 647 | state[1][0] = in[1]; 648 | state[2][0] = in[2]; 649 | state[3][0] = in[3]; 650 | state[0][1] = in[4]; 651 | state[1][1] = in[5]; 652 | state[2][1] = in[6]; 653 | state[3][1] = in[7]; 654 | state[0][2] = in[8]; 655 | state[1][2] = in[9]; 656 | state[2][2] = in[10]; 657 | state[3][2] = in[11]; 658 | state[0][3] = in[12]; 659 | state[1][3] = in[13]; 660 | state[2][3] = in[14]; 661 | state[3][3] = in[15]; 662 | 663 | 664 | AddRoundKey(state, &key[0]); 665 | SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state, &key[4]); 666 | SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state, &key[8]); 667 | SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state, &key[12]); 668 | SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state, &key[16]); 669 | SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state, &key[20]); 670 | SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state, &key[24]); 671 | SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state, &key[28]); 672 | SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state, &key[32]); 673 | SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state, &key[36]); 674 | if (keysize != 128) { 675 | SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state, &key[40]); 676 | SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state, &key[44]); 677 | if (keysize != 192) { 678 | SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state, &key[48]); 679 | SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state, &key[52]); 680 | SubBytes(state); ShiftRows(state); AddRoundKey(state, &key[56]); 681 | } 682 | else { 683 | SubBytes(state); ShiftRows(state); AddRoundKey(state, &key[48]); 684 | } 685 | } 686 | else { 687 | SubBytes(state); ShiftRows(state); AddRoundKey(state, &key[40]); 688 | } 689 | 690 | 691 | out[0] = state[0][0]; 692 | out[1] = state[1][0]; 693 | out[2] = state[2][0]; 694 | out[3] = state[3][0]; 695 | out[4] = state[0][1]; 696 | out[5] = state[1][1]; 697 | out[6] = state[2][1]; 698 | out[7] = state[3][1]; 699 | out[8] = state[0][2]; 700 | out[9] = state[1][2]; 701 | out[10] = state[2][2]; 702 | out[11] = state[3][2]; 703 | out[12] = state[0][3]; 704 | out[13] = state[1][3]; 705 | out[14] = state[2][3]; 706 | out[15] = state[3][3]; 707 | } 708 | 709 | void aes_decrypt(const BYTE in[], BYTE out[], const DWORD key[], int keysize) 710 | { 711 | BYTE state[4][4]; 712 | state[0][0] = in[0]; 713 | state[1][0] = in[1]; 714 | state[2][0] = in[2]; 715 | state[3][0] = in[3]; 716 | state[0][1] = in[4]; 717 | state[1][1] = in[5]; 718 | state[2][1] = in[6]; 719 | state[3][1] = in[7]; 720 | state[0][2] = in[8]; 721 | state[1][2] = in[9]; 722 | state[2][2] = in[10]; 723 | state[3][2] = in[11]; 724 | state[0][3] = in[12]; 725 | state[1][3] = in[13]; 726 | state[2][3] = in[14]; 727 | state[3][3] = in[15]; 728 | 729 | if (keysize > 128) { 730 | if (keysize > 192) { 731 | AddRoundKey(state, &key[56]); 732 | InvShiftRows(state); InvSubBytes(state); AddRoundKey(state, &key[52]); InvMixColumns(state); 733 | InvShiftRows(state); InvSubBytes(state); AddRoundKey(state, &key[48]); InvMixColumns(state); 734 | } 735 | else { 736 | AddRoundKey(state, &key[48]); 737 | } 738 | InvShiftRows(state); InvSubBytes(state); AddRoundKey(state, &key[44]); InvMixColumns(state); 739 | InvShiftRows(state); InvSubBytes(state); AddRoundKey(state, &key[40]); InvMixColumns(state); 740 | } 741 | else { 742 | AddRoundKey(state, &key[40]); 743 | } 744 | InvShiftRows(state); InvSubBytes(state); AddRoundKey(state, &key[36]); InvMixColumns(state); 745 | InvShiftRows(state); InvSubBytes(state); AddRoundKey(state, &key[32]); InvMixColumns(state); 746 | InvShiftRows(state); InvSubBytes(state); AddRoundKey(state, &key[28]); InvMixColumns(state); 747 | InvShiftRows(state); InvSubBytes(state); AddRoundKey(state, &key[24]); InvMixColumns(state); 748 | InvShiftRows(state); InvSubBytes(state); AddRoundKey(state, &key[20]); InvMixColumns(state); 749 | InvShiftRows(state); InvSubBytes(state); AddRoundKey(state, &key[16]); InvMixColumns(state); 750 | InvShiftRows(state); InvSubBytes(state); AddRoundKey(state, &key[12]); InvMixColumns(state); 751 | InvShiftRows(state); InvSubBytes(state); AddRoundKey(state, &key[8]); InvMixColumns(state); 752 | InvShiftRows(state); InvSubBytes(state); AddRoundKey(state, &key[4]); InvMixColumns(state); 753 | InvShiftRows(state); InvSubBytes(state); AddRoundKey(state, &key[0]); 754 | 755 | 756 | out[0] = state[0][0]; 757 | out[1] = state[1][0]; 758 | out[2] = state[2][0]; 759 | out[3] = state[3][0]; 760 | out[4] = state[0][1]; 761 | out[5] = state[1][1]; 762 | out[6] = state[2][1]; 763 | out[7] = state[3][1]; 764 | out[8] = state[0][2]; 765 | out[9] = state[1][2]; 766 | out[10] = state[2][2]; 767 | out[11] = state[3][2]; 768 | out[12] = state[0][3]; 769 | out[13] = state[1][3]; 770 | out[14] = state[2][3]; 771 | out[15] = state[3][3]; 772 | } 773 | 774 | 775 | /* 776 | 777 | void print_state(BYTE state[][4]) 778 | { 779 | int idx,idx2; 780 | 781 | for (idx=0; idx < 4; idx++) 782 | for (idx2=0; idx2 < 4; idx2++) 783 | printf("%02x",state[idx2][idx]); 784 | printf("\n"); 785 | } 786 | 787 | // This prints the key (4 consecutive ints) used for a given round as a linear hex string. 788 | void print_rnd_key(DWORD key[]) 789 | { 790 | int idx; 791 | 792 | for (idx=0; idx < 4; idx++) 793 | printf("%08x",key[idx]); 794 | printf("\n"); 795 | } 796 | */ --------------------------------------------------------------------------------