/home/dko/projects/mobilec/trunk/src/security/xyssl-0.7/programs/aes/aescrypt2.c

Go to the documentation of this file.
00001 /*
00002  *  AES-256 file encryption program
00003  *
00004  *  Copyright (C) 2006-2007  Christophe Devine
00005  *
00006  *  This library is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU Lesser General Public
00008  *  License, version 2.1 as published by the Free Software Foundation.
00009  *
00010  *  This library is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  *  Lesser General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU Lesser General Public
00016  *  License along with this library; if not, write to the Free Software
00017  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00018  *  MA  02110-1301  USA
00019  */
00020 
00021 #ifndef _CRT_SECURE_NO_DEPRECATE
00022 #define _CRT_SECURE_NO_DEPRECATE 1
00023 #endif
00024 
00025 #ifndef WIN32
00026 #include <sys/types.h>
00027 #include <unistd.h>
00028 #else
00029 #include <windows.h>
00030 #include <io.h>
00031 #endif
00032 
00033 #include <string.h>
00034 #include <stdlib.h>
00035 #include <stdio.h>
00036 #include <time.h>
00037 
00038 #include "xyssl/aes.h"
00039 #include "xyssl/sha2.h"
00040 
00041 #define MODE_ENCRYPT    0
00042 #define MODE_DECRYPT    1
00043 
00044 #define USAGE   \
00045     "\n  aescrypt2 <mode> <input filename> <output filename> <key>\n" \
00046     "\n   <mode>: 0 = encrypt, 1 = decrypt\n" \
00047     "\n  example: aescrypt2 0 file file.aes hex:E76B2413958B00E193\n" \
00048     "\n"
00049 
00050 void scanf_argv( char *prompt, char **arg )
00051 {
00052     printf( "%s", prompt );
00053     fflush( stdout );
00054     *arg = (char *) malloc( 1024 );
00055     scanf( "%1023s", *arg );
00056 }
00057 
00058 int main( int argc, char *argv[] )
00059 {
00060     int ret, i, n;
00061     int keylen, mode, lastn;
00062     FILE *fkey, *fin, *fout;
00063 
00064     char *p;
00065     unsigned char IV[16];
00066     unsigned char key[512];
00067     unsigned char digest[32];
00068     unsigned char buffer[1024];
00069 
00070     aes_context aes_ctx;
00071     sha2_context sha_ctx;
00072 
00073 #ifndef WIN32
00074       off_t filesize, offset;
00075 #else
00076     __int64 filesize, offset;
00077 #endif
00078 
00079     ret = 1;
00080 
00081     if( argc != 5 )
00082     {
00083         printf( USAGE );
00084 
00085 #ifndef WIN32
00086         goto exit;
00087 #else
00088         scanf_argv( "  mode    -> ", &argv[1] );
00089         scanf_argv( "  infile  -> ", &argv[2] );
00090         scanf_argv( "  outfile -> ", &argv[3] );
00091         scanf_argv( "  key     -> ", &argv[4] );
00092         printf( "\n" );
00093 #endif
00094     }
00095 
00096     /*
00097      * Parse the command-line arguments.
00098      */
00099     mode = atoi( argv[1] );
00100 
00101     if( mode != MODE_ENCRYPT && mode != MODE_DECRYPT )
00102     {
00103         fprintf( stderr, "invalide operation mode\n" );
00104         goto exit;
00105     }
00106 
00107     if( strcmp( argv[2], argv[3] ) == 0 )
00108     {
00109         fprintf( stderr, "input and output filenames must differ\n" );
00110         goto exit;
00111     }
00112 
00113     if( ( fin = fopen( argv[2], "rb" ) ) == NULL )
00114     {
00115         fprintf( stderr, "fopen(%s,rb) failed\n", argv[2] );
00116         goto exit;
00117     }
00118 
00119     if( ( fout = fopen( argv[3], "wb+" ) ) == NULL )
00120     {
00121         fprintf( stderr, "fopen(%s,wb+) failed\n", argv[3] );
00122         goto exit;
00123     }
00124 
00125     /*
00126      * Read the secret key and clean the command line.
00127      */
00128     if( ( fkey = fopen( argv[4], "rb" ) ) != NULL )
00129     {
00130         keylen = fread( key, 1, sizeof( key ), fkey );
00131         fclose( fkey );
00132     }
00133     else
00134     {
00135         if( memcmp( argv[4], "hex:", 4 ) == 0 )
00136         {
00137             p = &argv[4][4];
00138             keylen = 0;
00139 
00140             while( sscanf( p, "%02X", &n ) > 0 &&
00141                    keylen < (int) sizeof( key ) )
00142             {
00143                 key[keylen++] = n;
00144                 p += 2;
00145             }
00146         }
00147         else
00148         {
00149             keylen = strlen( argv[4] );
00150 
00151             if( keylen > (int) sizeof( key ) )
00152                 keylen = (int) sizeof( key );
00153 
00154             memcpy( key, argv[4], keylen );
00155         }
00156     }
00157 
00158     memset( argv[4], 0, strlen( argv[4] ) );
00159 
00160     /*
00161      * Read the input file size.
00162      */
00163 #ifndef WIN32
00164     if( ( filesize = lseek( fileno( fin ), 0, SEEK_END ) ) < 0 )
00165     {
00166         perror( "lseek" );
00167         goto exit;
00168     }
00169 #else
00170     {
00171         /*
00172          * Properly handle very large files on Win32.
00173          */
00174         LARGE_INTEGER li_size;
00175 
00176         li_size.QuadPart = 0;
00177         li_size.LowPart  = SetFilePointer(
00178             (HANDLE) _get_osfhandle( _fileno( fin ) ),
00179             li_size.LowPart, &li_size.HighPart, FILE_END );
00180 
00181         if( li_size.LowPart == 0xFFFFFFFF && GetLastError() != NO_ERROR )
00182         {
00183             fprintf( stderr, "SetFilePointer(0,FILE_END) failed\n" );
00184             goto exit;
00185         }
00186 
00187         filesize = li_size.QuadPart;
00188     }
00189 #endif
00190 
00191     if( fseek( fin, 0, SEEK_SET ) < 0 )
00192     {
00193         fprintf( stderr, "fseek(0,SEEK_SET) failed\n" );
00194         goto exit;
00195     }
00196 
00197     if( mode == MODE_ENCRYPT )
00198     {
00199         /*
00200          * Generate the initialization vector as:
00201          * IV = SHA-256( filesize || filename )[0..15]
00202          */
00203         for( i = 0; i < 8; i++ )
00204             buffer[i] = (unsigned char)( filesize >> ( i << 3 ) );
00205 
00206         p = argv[2];
00207 
00208         sha2_starts( &sha_ctx, 0 );
00209         sha2_update( &sha_ctx, buffer, 8 );
00210         sha2_update( &sha_ctx, (unsigned char *) p, strlen( p ) );
00211         sha2_finish( &sha_ctx, digest );
00212 
00213         memcpy( IV, digest, 16 );
00214 
00215         /*
00216          * The last four bits in the IV are actually used
00217          * to store the file size modulo the AES block size.
00218          */
00219         lastn = (int) ( filesize & 0x0F );
00220 
00221         IV[15] &= 0xF0;
00222         IV[15] |= lastn;
00223 
00224         /*
00225          * Append the IV at the beginning of the output.
00226          */
00227         if( fwrite( IV, 1, 16, fout ) != 16 )
00228         {
00229             fprintf( stderr, "fwrite(%d bytes) failed\n", 16 );
00230             goto exit;
00231         }
00232 
00233         /*
00234          * Hash the IV and the secret key together 8192 times
00235          * using the result to setup the AES context and HMAC.
00236          */
00237         memset( digest, 0,  32 );
00238         memcpy( digest, IV, 16 );
00239 
00240         for( i = 0; i < 8192; i++ )
00241         {
00242             sha2_starts( &sha_ctx, 0 );
00243             sha2_update( &sha_ctx, digest, 32 );
00244             sha2_update( &sha_ctx, key, keylen );
00245             sha2_finish( &sha_ctx, digest );
00246         }
00247 
00248         memset( key, 0, sizeof( key ) );
00249         aes_set_key( &aes_ctx, digest, 256 );
00250         sha2_hmac_starts( &sha_ctx, 0, digest, 32 );
00251 
00252         /*
00253          * Encrypt and write the ciphertext.
00254          */
00255         for( offset = 0; offset < filesize; offset += 16 )
00256         {
00257             n = ( filesize - offset > 16 ) ? 16 : (int)
00258                 ( filesize - offset );
00259 
00260             if( fread( buffer, 1, n, fin ) != (size_t) n )
00261             {
00262                 fprintf( stderr, "fread(%d bytes) failed\n", n );
00263                 goto exit;
00264             }
00265 
00266             for( i = 0; i < 16; i++ )
00267                 buffer[i] ^= IV[i];
00268 
00269             aes_encrypt( &aes_ctx, buffer, buffer );
00270             sha2_hmac_update( &sha_ctx, buffer, 16 );
00271 
00272             if( fwrite( buffer, 1, 16, fout ) != 16 )
00273             {
00274                 fprintf( stderr, "fwrite(%d bytes) failed\n", 16 );
00275                 goto exit;
00276             }
00277 
00278             memcpy( IV, buffer, 16 );
00279         }
00280 
00281         /*
00282          * Finally write the HMAC.
00283          */
00284         sha2_hmac_finish( &sha_ctx, digest );
00285 
00286         if( fwrite( digest, 1, 32, fout ) != 32 )
00287         {
00288             fprintf( stderr, "fwrite(%d bytes) failed\n", 16 );
00289             goto exit;
00290         }
00291     }
00292 
00293     if( mode == MODE_DECRYPT )
00294     {
00295         unsigned char tmp[16];
00296 
00297         /*
00298          *  The encrypted file must be structured as follows:
00299          *
00300          *        00 .. 15              Initialization Vector
00301          *        16 .. 31              AES Encrypted Block #1
00302          *           ..
00303          *      N*16 .. (N+1)*16 - 1    AES Encrypted Block #N
00304          *  (N+1)*16 .. (N+1)*16 + 32   HMAC-SHA-256(ciphertext)
00305          */
00306         if( filesize < 48 )
00307         {
00308             fprintf( stderr, "File too short to be encrypted.\n" );
00309             goto exit;
00310         }
00311 
00312         if( ( filesize & 0x0F ) != 0 )
00313         {
00314             fprintf( stderr, "File size not a multiple of 16.\n" );
00315             goto exit;
00316         }
00317 
00318         /*
00319          * Substract the IV + HMAC length.
00320          */
00321         filesize -= ( 16 + 32 );
00322 
00323         /*
00324          * Read the IV and original filesize modulo 16.
00325          */
00326         if( fread( buffer, 1, 16, fin ) != 16 )
00327         {
00328             fprintf( stderr, "fread(%d bytes) failed\n", 16 );
00329             goto exit;
00330         }
00331 
00332         memcpy( IV, buffer, 16 );
00333         lastn = IV[15] & 0x0F;
00334 
00335         /*
00336          * Hash the IV and the secret key together 8192 times
00337          * using the result to setup the AES context and HMAC.
00338          */
00339         memset( digest, 0,  32 );
00340         memcpy( digest, IV, 16 );
00341 
00342         for( i = 0; i < 8192; i++ )
00343         {
00344             sha2_starts( &sha_ctx, 0 );
00345             sha2_update( &sha_ctx, digest, 32 );
00346             sha2_update( &sha_ctx, key, keylen );
00347             sha2_finish( &sha_ctx, digest );
00348         }
00349 
00350         memset( key, 0, sizeof( key ) );
00351         aes_set_key( &aes_ctx, digest, 256 );
00352         sha2_hmac_starts( &sha_ctx, 0, digest, 32 );
00353 
00354         /*
00355          * Decrypt and write the plaintext.
00356          */
00357         for( offset = 0; offset < filesize; offset += 16 )
00358         {
00359             if( fread( buffer, 1, 16, fin ) != 16 )
00360             {
00361                 fprintf( stderr, "fread(%d bytes) failed\n", 16 );
00362                 goto exit;
00363             }
00364 
00365             memcpy( tmp, buffer, 16 );
00366  
00367             sha2_hmac_update( &sha_ctx, buffer, 16 );
00368             aes_decrypt( &aes_ctx, buffer, buffer );
00369    
00370             for( i = 0; i < 16; i++ )
00371                 buffer[i] ^= IV[i];
00372 
00373             memcpy( IV, tmp, 16 );
00374 
00375             n = ( lastn > 0 && offset == filesize - 16 )
00376                 ? lastn : 16;
00377 
00378             if( fwrite( buffer, 1, n, fout ) != (size_t) n )
00379             {
00380                 fprintf( stderr, "fwrite(%d bytes) failed\n", n );
00381                 goto exit;
00382             }
00383         }
00384 
00385         /*
00386          * Verify the message authentication code.
00387          */
00388         sha2_hmac_finish( &sha_ctx, digest );
00389 
00390         if( fread( buffer, 1, 32, fin ) != 32 )
00391         {
00392             fprintf( stderr, "fread(%d bytes) failed\n", 32 );
00393             goto exit;
00394         }
00395 
00396         if( memcmp( digest, buffer, 32 ) != 0 )
00397         {
00398             fprintf( stderr, "HMAC check failed: wrong key, "
00399                              "or file corrupted.\n" );
00400             goto exit;
00401         }
00402     }
00403 
00404     ret = 0;
00405 
00406 exit:
00407 
00408     memset( buffer, 0, sizeof( buffer ) );
00409     memset( digest, 0, sizeof( digest ) );
00410 
00411     memset( &aes_ctx, 0, sizeof(  aes_context ) );
00412     memset( &sha_ctx, 0, sizeof( sha2_context ) );
00413 
00414 #ifdef WIN32
00415     if( ret != 0 )
00416     {
00417         fflush( stderr );
00418         printf( "\nPress Enter to exit this program.\n" );
00419         fflush( stdout ); getchar();
00420     }
00421 #endif
00422 
00423     return( ret );
00424 }

Generated on Fri May 16 14:49:55 2008 for Mobile-C by  doxygen 1.5.4