2 * AES-256 file encryption program
4 * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine
6 * Copyright (C) 2009 Paul Bakker <polarssl_maintainer at polarssl dot org>
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
14 * * Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * * Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * * Neither the names of PolarSSL or XySSL nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 #ifndef _CRT_SECURE_NO_DEPRECATE
37 #define _CRT_SECURE_NO_DEPRECATE 1
44 #include <sys/types.h>
53 #include "tropicssl/aes.h"
54 #include "tropicssl/sha2.h"
56 #define MODE_ENCRYPT 0
57 #define MODE_DECRYPT 1
60 "\n aescrypt2 <mode> <input filename> <output filename> <key>\n" \
61 "\n <mode>: 0 = encrypt, 1 = decrypt\n" \
62 "\n example: aescrypt2 0 file file.aes hex:E76B2413958B00E193\n" \
65 int main(int argc
, char *argv
[])
68 int keylen
, mode
, lastn
;
69 FILE *fkey
, *fin
, *fout
;
73 unsigned char key
[512];
74 unsigned char digest
[32];
75 unsigned char buffer
[1024];
81 LARGE_INTEGER li_size
;
82 __int64 filesize
, offset
;
84 off_t filesize
, offset
;
88 * Parse the command-line arguments.
94 printf("\n Press Enter to exit this program.\n");
102 mode
= atoi(argv
[1]);
104 if (mode
!= MODE_ENCRYPT
&& mode
!= MODE_DECRYPT
) {
105 fprintf(stderr
, "invalide operation mode\n");
109 if (strcmp(argv
[2], argv
[3]) == 0) {
110 fprintf(stderr
, "input and output filenames must differ\n");
114 if ((fin
= fopen(argv
[2], "rb")) == NULL
) {
115 fprintf(stderr
, "fopen(%s,rb) failed\n", argv
[2]);
119 if ((fout
= fopen(argv
[3], "wb+")) == NULL
) {
120 fprintf(stderr
, "fopen(%s,wb+) failed\n", argv
[3]);
125 * Read the secret key and clean the command line.
127 if ((fkey
= fopen(argv
[4], "rb")) != NULL
) {
128 keylen
= fread(key
, 1, sizeof(key
), fkey
);
131 if (memcmp(argv
[4], "hex:", 4) == 0) {
135 while (sscanf(p
, "%02X", &n
) > 0 &&
136 keylen
< (int)sizeof(key
)) {
137 key
[keylen
++] = (unsigned char)n
;
141 keylen
= strlen(argv
[4]);
143 if (keylen
> (int)sizeof(key
))
144 keylen
= (int)sizeof(key
);
146 memcpy(key
, argv
[4], keylen
);
150 memset(argv
[4], 0, strlen(argv
[4]));
154 * Support large files (> 2Gb) on Win32
156 li_size
.QuadPart
= 0;
158 SetFilePointer((HANDLE
) _get_osfhandle(_fileno(fin
)),
159 li_size
.LowPart
, &li_size
.HighPart
, FILE_END
);
161 if (li_size
.LowPart
== 0xFFFFFFFF && GetLastError() != NO_ERROR
) {
162 fprintf(stderr
, "SetFilePointer(0,FILE_END) failed\n");
166 filesize
= li_size
.QuadPart
;
168 if ((filesize
= lseek(fileno(fin
), 0, SEEK_END
)) < 0) {
174 if (fseek(fin
, 0, SEEK_SET
) < 0) {
175 fprintf(stderr
, "fseek(0,SEEK_SET) failed\n");
179 if (mode
== MODE_ENCRYPT
) {
181 * Generate the initialization vector as:
182 * IV = SHA-256( filesize || filename )[0..15]
184 for (i
= 0; i
< 8; i
++)
185 buffer
[i
] = (unsigned char)(filesize
>> (i
<< 3));
189 sha2_starts(&sha_ctx
, 0);
190 sha2_update(&sha_ctx
, buffer
, 8);
191 sha2_update(&sha_ctx
, (unsigned char *)p
, strlen(p
));
192 sha2_finish(&sha_ctx
, digest
);
194 memcpy(IV
, digest
, 16);
197 * The last four bits in the IV are actually used
198 * to store the file size modulo the AES block size.
200 lastn
= (int)(filesize
& 0x0F);
202 IV
[15] = (unsigned char)
203 ((IV
[15] & 0xF0) | lastn
);
206 * Append the IV at the beginning of the output.
208 if (fwrite(IV
, 1, 16, fout
) != 16) {
209 fprintf(stderr
, "fwrite(%d bytes) failed\n", 16);
214 * Hash the IV and the secret key together 8192 times
215 * using the result to setup the AES context and HMAC.
217 memset(digest
, 0, 32);
218 memcpy(digest
, IV
, 16);
220 for (i
= 0; i
< 8192; i
++) {
221 sha2_starts(&sha_ctx
, 0);
222 sha2_update(&sha_ctx
, digest
, 32);
223 sha2_update(&sha_ctx
, key
, keylen
);
224 sha2_finish(&sha_ctx
, digest
);
227 memset(key
, 0, sizeof(key
));
228 aes_setkey_enc(&aes_ctx
, digest
, 256);
229 sha2_hmac_starts(&sha_ctx
, digest
, 32, 0);
232 * Encrypt and write the ciphertext.
234 for (offset
= 0; offset
< filesize
; offset
+= 16) {
235 n
= (filesize
- offset
> 16) ? 16 : (int)
238 if (fread(buffer
, 1, n
, fin
) != (size_t) n
) {
239 fprintf(stderr
, "fread(%d bytes) failed\n", n
);
243 for (i
= 0; i
< 16; i
++)
244 buffer
[i
] = (unsigned char)(buffer
[i
] ^ IV
[i
]);
246 aes_crypt_ecb(&aes_ctx
, AES_ENCRYPT
, buffer
, buffer
);
247 sha2_hmac_update(&sha_ctx
, buffer
, 16);
249 if (fwrite(buffer
, 1, 16, fout
) != 16) {
250 fprintf(stderr
, "fwrite(%d bytes) failed\n",
255 memcpy(IV
, buffer
, 16);
259 * Finally write the HMAC.
261 sha2_hmac_finish(&sha_ctx
, digest
);
263 if (fwrite(digest
, 1, 32, fout
) != 32) {
264 fprintf(stderr
, "fwrite(%d bytes) failed\n", 16);
269 if (mode
== MODE_DECRYPT
) {
270 unsigned char tmp
[16];
273 * The encrypted file must be structured as follows:
275 * 00 .. 15 Initialization Vector
276 * 16 .. 31 AES Encrypted Block #1
278 * N*16 .. (N+1)*16 - 1 AES Encrypted Block #N
279 * (N+1)*16 .. (N+1)*16 + 32 HMAC-SHA-256(ciphertext)
282 fprintf(stderr
, "File too short to be encrypted.\n");
286 if ((filesize
& 0x0F) != 0) {
287 fprintf(stderr
, "File size not a multiple of 16.\n");
292 * Substract the IV + HMAC length.
294 filesize
-= (16 + 32);
297 * Read the IV and original filesize modulo 16.
299 if (fread(buffer
, 1, 16, fin
) != 16) {
300 fprintf(stderr
, "fread(%d bytes) failed\n", 16);
304 memcpy(IV
, buffer
, 16);
305 lastn
= IV
[15] & 0x0F;
308 * Hash the IV and the secret key together 8192 times
309 * using the result to setup the AES context and HMAC.
311 memset(digest
, 0, 32);
312 memcpy(digest
, IV
, 16);
314 for (i
= 0; i
< 8192; i
++) {
315 sha2_starts(&sha_ctx
, 0);
316 sha2_update(&sha_ctx
, digest
, 32);
317 sha2_update(&sha_ctx
, key
, keylen
);
318 sha2_finish(&sha_ctx
, digest
);
321 memset(key
, 0, sizeof(key
));
322 aes_setkey_dec(&aes_ctx
, digest
, 256);
323 sha2_hmac_starts(&sha_ctx
, digest
, 32, 0);
326 * Decrypt and write the plaintext.
328 for (offset
= 0; offset
< filesize
; offset
+= 16) {
329 if (fread(buffer
, 1, 16, fin
) != 16) {
330 fprintf(stderr
, "fread(%d bytes) failed\n", 16);
334 memcpy(tmp
, buffer
, 16);
336 sha2_hmac_update(&sha_ctx
, buffer
, 16);
337 aes_crypt_ecb(&aes_ctx
, AES_DECRYPT
, buffer
, buffer
);
339 for (i
= 0; i
< 16; i
++)
340 buffer
[i
] = (unsigned char)(buffer
[i
] ^ IV
[i
]);
344 n
= (lastn
> 0 && offset
== filesize
- 16)
347 if (fwrite(buffer
, 1, n
, fout
) != (size_t) n
) {
348 fprintf(stderr
, "fwrite(%d bytes) failed\n", n
);
354 * Verify the message authentication code.
356 sha2_hmac_finish(&sha_ctx
, digest
);
358 if (fread(buffer
, 1, 32, fin
) != 32) {
359 fprintf(stderr
, "fread(%d bytes) failed\n", 32);
363 if (memcmp(digest
, buffer
, 32) != 0) {
364 fprintf(stderr
, "HMAC check failed: wrong key, "
365 "or file corrupted.\n");
374 memset(buffer
, 0, sizeof(buffer
));
375 memset(digest
, 0, sizeof(digest
));
377 memset(&aes_ctx
, 0, sizeof(aes_context
));
378 memset(&sha_ctx
, 0, sizeof(sha2_context
));