bignum: make mpi_init() and mpi_free() accept a single argument
[tropicssl.git] / programs / aes / aescrypt2.c
blob0a1d24dd590854825380936fefd5af9a830d6fe8
1 /*
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>
8 * All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
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
38 #endif
40 #if defined(WIN32)
41 #include <windows.h>
42 #include <io.h>
43 #else
44 #include <sys/types.h>
45 #include <unistd.h>
46 #endif
48 #include <string.h>
49 #include <stdlib.h>
50 #include <stdio.h>
51 #include <time.h>
53 #include "tropicssl/aes.h"
54 #include "tropicssl/sha2.h"
56 #define MODE_ENCRYPT 0
57 #define MODE_DECRYPT 1
59 #define USAGE \
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" \
63 "\n"
65 int main(int argc, char *argv[])
67 int ret = 1, i, n;
68 int keylen, mode, lastn;
69 FILE *fkey, *fin, *fout;
71 char *p;
72 unsigned char IV[16];
73 unsigned char key[512];
74 unsigned char digest[32];
75 unsigned char buffer[1024];
77 aes_context aes_ctx;
78 sha2_context sha_ctx;
80 #if defined(WIN32)
81 LARGE_INTEGER li_size;
82 __int64 filesize, offset;
83 #else
84 off_t filesize, offset;
85 #endif
88 * Parse the command-line arguments.
90 if (argc != 5) {
91 printf(USAGE);
93 #if defined(WIN32)
94 printf("\n Press Enter to exit this program.\n");
95 fflush(stdout);
96 getchar();
97 #endif
99 goto exit;
102 mode = atoi(argv[1]);
104 if (mode != MODE_ENCRYPT && mode != MODE_DECRYPT) {
105 fprintf(stderr, "invalide operation mode\n");
106 goto exit;
109 if (strcmp(argv[2], argv[3]) == 0) {
110 fprintf(stderr, "input and output filenames must differ\n");
111 goto exit;
114 if ((fin = fopen(argv[2], "rb")) == NULL) {
115 fprintf(stderr, "fopen(%s,rb) failed\n", argv[2]);
116 goto exit;
119 if ((fout = fopen(argv[3], "wb+")) == NULL) {
120 fprintf(stderr, "fopen(%s,wb+) failed\n", argv[3]);
121 goto exit;
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);
129 fclose(fkey);
130 } else {
131 if (memcmp(argv[4], "hex:", 4) == 0) {
132 p = &argv[4][4];
133 keylen = 0;
135 while (sscanf(p, "%02X", &n) > 0 &&
136 keylen < (int)sizeof(key)) {
137 key[keylen++] = (unsigned char)n;
138 p += 2;
140 } else {
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]));
152 #if defined(WIN32)
154 * Support large files (> 2Gb) on Win32
156 li_size.QuadPart = 0;
157 li_size.LowPart =
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");
163 goto exit;
166 filesize = li_size.QuadPart;
167 #else
168 if ((filesize = lseek(fileno(fin), 0, SEEK_END)) < 0) {
169 perror("lseek");
170 goto exit;
172 #endif
174 if (fseek(fin, 0, SEEK_SET) < 0) {
175 fprintf(stderr, "fseek(0,SEEK_SET) failed\n");
176 goto exit;
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));
187 p = argv[2];
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);
210 goto exit;
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)
236 (filesize - offset);
238 if (fread(buffer, 1, n, fin) != (size_t) n) {
239 fprintf(stderr, "fread(%d bytes) failed\n", n);
240 goto exit;
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",
251 16);
252 goto exit;
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);
265 goto exit;
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
277 * ..
278 * N*16 .. (N+1)*16 - 1 AES Encrypted Block #N
279 * (N+1)*16 .. (N+1)*16 + 32 HMAC-SHA-256(ciphertext)
281 if (filesize < 48) {
282 fprintf(stderr, "File too short to be encrypted.\n");
283 goto exit;
286 if ((filesize & 0x0F) != 0) {
287 fprintf(stderr, "File size not a multiple of 16.\n");
288 goto exit;
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);
301 goto exit;
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);
331 goto exit;
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]);
342 memcpy(IV, tmp, 16);
344 n = (lastn > 0 && offset == filesize - 16)
345 ? lastn : 16;
347 if (fwrite(buffer, 1, n, fout) != (size_t) n) {
348 fprintf(stderr, "fwrite(%d bytes) failed\n", n);
349 goto exit;
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);
360 goto exit;
363 if (memcmp(digest, buffer, 32) != 0) {
364 fprintf(stderr, "HMAC check failed: wrong key, "
365 "or file corrupted.\n");
366 goto exit;
370 ret = 0;
372 exit:
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));
380 return (ret);