├── 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 | */
--------------------------------------------------------------------------------