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

Generated on Fri Jul 11 17:59:46 2008 for Mobile-C by  doxygen 1.5.4