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

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

Generated on Tue Jul 1 15:29:59 2008 for Mobile-C by  doxygen 1.5.4