PageRenderTime 48ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/programs/aes/crypt_and_hash.c

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