source: trunk/programs/aes/aescrypt2.c @ 1122

Revision 1122, 10.9 KB checked in by paul, 6 months ago (diff)
  • Lots of minimal changes to better support WINCE as a build target
Line 
1/*
2 *  AES-256 file encryption program
3 *
4 *  Copyright (C) 2006-2011, Brainspark B.V.
5 *
6 *  This file is part of PolarSSL (http://www.polarssl.org)
7 *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
8 *
9 *  All rights reserved.
10 *
11 *  This program is free software; you can redistribute it and/or modify
12 *  it under the terms of the GNU General Public License as published by
13 *  the Free Software Foundation; either version 2 of the License, or
14 *  (at your option) any later version.
15 *
16 *  This program is distributed in the hope that it will be useful,
17 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 *  GNU General Public License for more details.
20 *
21 *  You should have received a copy of the GNU General Public License along
22 *  with this program; if not, write to the Free Software Foundation, Inc.,
23 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 */
25
26#ifndef _CRT_SECURE_NO_DEPRECATE
27#define _CRT_SECURE_NO_DEPRECATE 1
28#endif
29
30#if defined(_WIN32)
31#include <windows.h>
32#if !defined(_WIN32_WCE)
33#include <io.h>
34#endif
35#else
36#include <sys/types.h>
37#include <unistd.h>
38#endif
39
40#include <string.h>
41#include <stdlib.h>
42#include <stdio.h>
43#include <time.h>
44
45#include "polarssl/config.h"
46
47#include "polarssl/aes.h"
48#include "polarssl/sha2.h"
49
50#define MODE_ENCRYPT    0
51#define MODE_DECRYPT    1
52
53#define USAGE   \
54    "\n  aescrypt2 <mode> <input filename> <output filename> <key>\n" \
55    "\n   <mode>: 0 = encrypt, 1 = decrypt\n" \
56    "\n  example: aescrypt2 0 file file.aes hex:E76B2413958B00E193\n" \
57    "\n"
58
59#if !defined(POLARSSL_AES_C) || !defined(POLARSSL_SHA2_C)
60int main( int argc, char *argv[] )
61{
62    ((void) argc);
63    ((void) argv);
64    printf("POLARSSL_AES_C and/or POLARSSL_SHA2_C not defined.\n");
65    return( 0 );
66}
67#else
68int main( int argc, char *argv[] )
69{
70    int ret = 1;
71
72    int i, n;
73    int mode, lastn;
74    size_t keylen;
75    FILE *fkey, *fin = NULL, *fout = NULL;
76
77    char *p;
78    unsigned char IV[16];
79    unsigned char key[512];
80    unsigned char digest[32];
81    unsigned char buffer[1024];
82
83    aes_context aes_ctx;
84    sha2_context sha_ctx;
85
86#if defined(_WIN32_WCE)
87    long filesize, offset;
88#elif defined(_WIN32)
89       LARGE_INTEGER li_size;
90    __int64 filesize, offset;
91#else
92      off_t filesize, offset;
93#endif
94
95    /*
96     * Parse the command-line arguments.
97     */
98    if( argc != 5 )
99    {
100        printf( USAGE );
101
102#if defined(_WIN32)
103        printf( "\n  Press Enter to exit this program.\n" );
104        fflush( stdout ); getchar();
105#endif
106
107        goto exit;
108    }
109
110    mode = atoi( argv[1] );
111
112    if( mode != MODE_ENCRYPT && mode != MODE_DECRYPT )
113    {
114        fprintf( stderr, "invalide operation mode\n" );
115        goto exit;
116    }
117
118    if( strcmp( argv[2], argv[3] ) == 0 )
119    {
120        fprintf( stderr, "input and output filenames must differ\n" );
121        goto exit;
122    }
123
124    if( ( fin = fopen( argv[2], "rb" ) ) == NULL )
125    {
126        fprintf( stderr, "fopen(%s,rb) failed\n", argv[2] );
127        goto exit;
128    }
129
130    if( ( fout = fopen( argv[3], "wb+" ) ) == NULL )
131    {
132        fprintf( stderr, "fopen(%s,wb+) failed\n", argv[3] );
133        goto exit;
134    }
135
136    /*
137     * Read the secret key and clean the command line.
138     */
139    if( ( fkey = fopen( argv[4], "rb" ) ) != NULL )
140    {
141        keylen = fread( key, 1, sizeof( key ), fkey );
142        fclose( fkey );
143    }
144    else
145    {
146        if( memcmp( argv[4], "hex:", 4 ) == 0 )
147        {
148            p = &argv[4][4];
149            keylen = 0;
150
151            while( sscanf( p, "%02X", &n ) > 0 &&
152                   keylen < (int) sizeof( key ) )
153            {
154                key[keylen++] = (unsigned char) n;
155                p += 2;
156            }
157        }
158        else
159        {
160            keylen = strlen( argv[4] );
161
162            if( keylen > (int) sizeof( key ) )
163                keylen = (int) sizeof( key );
164
165            memcpy( key, argv[4], keylen );
166        }
167    }
168
169    memset( argv[4], 0, strlen( argv[4] ) );
170
171#if defined(_WIN32_WCE)
172    filesize = fseek( fin, 0L, SEEK_END );
173#else
174#if defined(_WIN32)
175    /*
176     * Support large files (> 2Gb) on Win32
177     */
178    li_size.QuadPart = 0;
179    li_size.LowPart  =
180        SetFilePointer( (HANDLE) _get_osfhandle( _fileno( fin ) ),
181                        li_size.LowPart, &li_size.HighPart, FILE_END );
182
183    if( li_size.LowPart == 0xFFFFFFFF && GetLastError() != NO_ERROR )
184    {
185        fprintf( stderr, "SetFilePointer(0,FILE_END) failed\n" );
186        goto exit;
187    }
188
189    filesize = li_size.QuadPart;
190#else
191    if( ( filesize = lseek( fileno( fin ), 0, SEEK_END ) ) < 0 )
192    {
193        perror( "lseek" );
194        goto exit;
195    }
196#endif
197#endif
198
199    if( fseek( fin, 0, SEEK_SET ) < 0 )
200    {
201        fprintf( stderr, "fseek(0,SEEK_SET) failed\n" );
202        goto exit;
203    }
204
205    if( mode == MODE_ENCRYPT )
206    {
207        /*
208         * Generate the initialization vector as:
209         * IV = SHA-256( filesize || filename )[0..15]
210         */
211        for( i = 0; i < 8; i++ )
212            buffer[i] = (unsigned char)( filesize >> ( i << 3 ) );
213
214        p = argv[2];
215
216        sha2_starts( &sha_ctx, 0 );
217        sha2_update( &sha_ctx, buffer, 8 );
218        sha2_update( &sha_ctx, (unsigned char *) p, strlen( p ) );
219        sha2_finish( &sha_ctx, digest );
220
221        memcpy( IV, digest, 16 );
222
223        /*
224         * The last four bits in the IV are actually used
225         * to store the file size modulo the AES block size.
226         */
227        lastn = (int)( filesize & 0x0F );
228
229        IV[15] = (unsigned char)
230            ( ( IV[15] & 0xF0 ) | lastn );
231
232        /*
233         * Append the IV at the beginning of the output.
234         */
235        if( fwrite( IV, 1, 16, fout ) != 16 )
236        {
237            fprintf( stderr, "fwrite(%d bytes) failed\n", 16 );
238            goto exit;
239        }
240
241        /*
242         * Hash the IV and the secret key together 8192 times
243         * using the result to setup the AES context and HMAC.
244         */
245        memset( digest, 0,  32 );
246        memcpy( digest, IV, 16 );
247
248        for( i = 0; i < 8192; i++ )
249        {
250            sha2_starts( &sha_ctx, 0 );
251            sha2_update( &sha_ctx, digest, 32 );
252            sha2_update( &sha_ctx, key, keylen );
253            sha2_finish( &sha_ctx, digest );
254        }
255
256        memset( key, 0, sizeof( key ) );
257          aes_setkey_enc( &aes_ctx, digest, 256 );
258        sha2_hmac_starts( &sha_ctx, digest, 32, 0 );
259
260        /*
261         * Encrypt and write the ciphertext.
262         */
263        for( offset = 0; offset < filesize; offset += 16 )
264        {
265            n = ( filesize - offset > 16 ) ? 16 : (int)
266                ( filesize - offset );
267
268            if( fread( buffer, 1, n, fin ) != (size_t) n )
269            {
270                fprintf( stderr, "fread(%d bytes) failed\n", n );
271                goto exit;
272            }
273
274            for( i = 0; i < 16; i++ )
275                buffer[i] = (unsigned char)( buffer[i] ^ IV[i] );
276
277            aes_crypt_ecb( &aes_ctx, AES_ENCRYPT, buffer, buffer );
278            sha2_hmac_update( &sha_ctx, buffer, 16 );
279
280            if( fwrite( buffer, 1, 16, fout ) != 16 )
281            {
282                fprintf( stderr, "fwrite(%d bytes) failed\n", 16 );
283                goto exit;
284            }
285
286            memcpy( IV, buffer, 16 );
287        }
288
289        /*
290         * Finally write the HMAC.
291         */
292        sha2_hmac_finish( &sha_ctx, digest );
293
294        if( fwrite( digest, 1, 32, fout ) != 32 )
295        {
296            fprintf( stderr, "fwrite(%d bytes) failed\n", 16 );
297            goto exit;
298        }
299    }
300
301    if( mode == MODE_DECRYPT )
302    {
303        unsigned char tmp[16];
304
305        /*
306         *  The encrypted file must be structured as follows:
307         *
308         *        00 .. 15              Initialization Vector
309         *        16 .. 31              AES Encrypted Block #1
310         *           ..
311         *      N*16 .. (N+1)*16 - 1    AES Encrypted Block #N
312         *  (N+1)*16 .. (N+1)*16 + 32   HMAC-SHA-256(ciphertext)
313         */
314        if( filesize < 48 )
315        {
316            fprintf( stderr, "File too short to be encrypted.\n" );
317            goto exit;
318        }
319
320        if( ( filesize & 0x0F ) != 0 )
321        {
322            fprintf( stderr, "File size not a multiple of 16.\n" );
323            goto exit;
324        }
325
326        /*
327         * Substract the IV + HMAC length.
328         */
329        filesize -= ( 16 + 32 );
330
331        /*
332         * Read the IV and original filesize modulo 16.
333         */
334        if( fread( buffer, 1, 16, fin ) != 16 )
335        {
336            fprintf( stderr, "fread(%d bytes) failed\n", 16 );
337            goto exit;
338        }
339
340        memcpy( IV, buffer, 16 );
341        lastn = IV[15] & 0x0F;
342
343        /*
344         * Hash the IV and the secret key together 8192 times
345         * using the result to setup the AES context and HMAC.
346         */
347        memset( digest, 0,  32 );
348        memcpy( digest, IV, 16 );
349
350        for( i = 0; i < 8192; i++ )
351        {
352            sha2_starts( &sha_ctx, 0 );
353            sha2_update( &sha_ctx, digest, 32 );
354            sha2_update( &sha_ctx, key, keylen );
355            sha2_finish( &sha_ctx, digest );
356        }
357
358        memset( key, 0, sizeof( key ) );
359          aes_setkey_dec( &aes_ctx, digest, 256 );
360        sha2_hmac_starts( &sha_ctx, digest, 32, 0 );
361
362        /*
363         * Decrypt and write the plaintext.
364         */
365        for( offset = 0; offset < filesize; offset += 16 )
366        {
367            if( fread( buffer, 1, 16, fin ) != 16 )
368            {
369                fprintf( stderr, "fread(%d bytes) failed\n", 16 );
370                goto exit;
371            }
372
373            memcpy( tmp, buffer, 16 );
374 
375            sha2_hmac_update( &sha_ctx, buffer, 16 );
376            aes_crypt_ecb( &aes_ctx, AES_DECRYPT, buffer, buffer );
377   
378            for( i = 0; i < 16; i++ )
379                buffer[i] = (unsigned char)( buffer[i] ^ IV[i] );
380
381            memcpy( IV, tmp, 16 );
382
383            n = ( lastn > 0 && offset == filesize - 16 )
384                ? lastn : 16;
385
386            if( fwrite( buffer, 1, n, fout ) != (size_t) n )
387            {
388                fprintf( stderr, "fwrite(%d bytes) failed\n", n );
389                goto exit;
390            }
391        }
392
393        /*
394         * Verify the message authentication code.
395         */
396        sha2_hmac_finish( &sha_ctx, digest );
397
398        if( fread( buffer, 1, 32, fin ) != 32 )
399        {
400            fprintf( stderr, "fread(%d bytes) failed\n", 32 );
401            goto exit;
402        }
403
404        if( memcmp( digest, buffer, 32 ) != 0 )
405        {
406            fprintf( stderr, "HMAC check failed: wrong key, "
407                             "or file corrupted.\n" );
408            goto exit;
409        }
410    }
411
412    ret = 0;
413
414exit:
415    if( fin )
416        fclose( fin );
417    if( fout )
418        fclose( fout );
419
420    memset( buffer, 0, sizeof( buffer ) );
421    memset( digest, 0, sizeof( digest ) );
422
423    memset( &aes_ctx, 0, sizeof(  aes_context ) );
424    memset( &sha_ctx, 0, sizeof( sha2_context ) );
425
426    return( ret );
427}
428#endif /* POLARSSL_AES_C && POLARSSL_SHA2_C */
Note: See TracBrowser for help on using the repository browser.

What are you looking for?