tpbkdf2.c - tomb - the crypto undertaker
 (HTM) git clone git://parazyd.org/tomb.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       tpbkdf2.c (4265B)
       ---
            1 /*
            2 ** SYNOPSIS
            3 **   echo "passphrase" | pbkdf2 salt_hex count > 48_byte_hex_key_and_iv
            4 **
            5 ** DESCRIPTION
            6 **
            7 ** Make the "Password-Based Key Derivation Function v2" function found in
            8 ** the openssl library available to the command line, as it is not available
            9 ** for use from the "openssl" command.  At the time of writing the "openssl"
           10 ** command only encrypts using the older, 'fast' pbkdf1.5 method.
           11 **
           12 ** The 'salt_hex' is the salt to be used, as a hexadecimal string. Typically
           13 ** this is 8 bytes (64 bit), and is an assigned randomly during encryption.
           14 **
           15 ** The 'count' is iteration count used to make the calculation of the key
           16 ** from the passphrase longer so as to take 1/2 to 2 seconds to generate.
           17 ** This complexity prevents slows down brute force attacks enormously.
           18 **
           19 ** The output of the above is a 48 bytes in hexadeximal, which is typically
           20 ** used for 32 byte encryption key KEY and a 16 byte IV as needed by
           21 ** Crypt-AES-256 (or some other encryption method).
           22 **
           23 ** NOTE: While the "openssl" command can accept a hex encoded 'key' and 'iv'
           24 ** it only does so on the command line, which is insecure.  As such I
           25 ** recommend that the output only be used with API access to the "OpenSSL"
           26 ** cryptography libraries.
           27 **
           28 *************
           29 **
           30 ** Anthony Thyssen   4 November 2009      A.Thyssen@griffith.edu.au
           31 **
           32 ** Based on a test program "pkcs5.c" found on
           33 **   http://www.mail-archive.com/openssl-users@openssl.org
           34 ** which uses openssl to perform PBKDF2 (RFC2898) iteritive (slow) password
           35 ** hashing.
           36 **
           37 ** Build
           38 **    gcc -o pbkdf2 pbkdf2.c -lcrypto
           39 **
           40 */
           41 #include <stdio.h>
           42 #include <string.h>
           43 
           44 #include <gcrypt.h>
           45 
           46 /* TODO: move print_hex and hex_to_binary to utils.h, with separate compiling */
           47 void print_hex(unsigned char *buf, int len)
           48 {
           49         int i;
           50 
           51         for(i=0;i<len;i++)
           52                 printf("%02x", buf[i]);
           53         printf("\n");
           54 }
           55 
           56 int hex_to_binary(unsigned char *buf, char *hex)
           57 {
           58         int ret;
           59         int count=0;
           60         while(*hex) {
           61                 if( hex[1] ) {
           62                         ret = sscanf( hex, "%2x", (unsigned int*) buf++ );
           63                         hex += 2;
           64                 }
           65                 else {
           66                         ret = sscanf( hex++, "%1x", (unsigned int*)buf++ );
           67                 }
           68                 count++;
           69                 if( ret != 1)
           70                         return -1;
           71         }
           72         *buf = 0;  // null terminate -- precaution
           73         return count;
           74 }
           75 
           76 int main(int argc, char *argv[])
           77 {
           78         char *pass = NULL;
           79         unsigned char *salt;
           80         int salt_len;                  // salt length in bytes
           81         int ic=0;                        // iterative count
           82         int result_len;
           83         unsigned char *result;       // result (binary - 32+16 chars)
           84         int i;
           85 
           86         if ( argc != 4 ) {
           87                 fprintf(stderr, "usage: %s salt count len <passwd >binary_key_iv\n", argv[0]);
           88                 exit(10);
           89         }
           90 
           91         //TODO: move to base64decode
           92         salt=calloc(strlen(argv[1])/2+3, sizeof(char));
           93         salt_len=hex_to_binary(salt, argv[1]);
           94         if( salt_len <= 0 ) {
           95                 fprintf(stderr, "Error: %s is not a valid salt (it must be a hexadecimal string)\n", argv[1]);
           96                 exit(1);
           97         }
           98 
           99         if( sscanf(argv[2], "%d", &ic) == 0 || ic<=0) {
          100                 fprintf(stderr, "Error: count must be a positive integer\n");
          101                 exit(1);
          102         }
          103         if( sscanf(argv[3], "%d", &result_len) == 0 || result_len<=0) {
          104                 fprintf(stderr, "Error: result_len must be a positive integer\n");
          105                 exit(1);
          106         }
          107 
          108         fscanf(stdin, "%ms", &pass);
          109         if ( pass[strlen(pass)-1] == '\n' )
          110                 pass[strlen(pass)-1] = '\0';
          111 
          112         // PBKDF 2
          113         result = calloc(result_len, sizeof(unsigned char*));
          114         if (!gcry_check_version ("1.5.0")) {
          115                 fputs ("libgcrypt version mismatch\n", stderr);
          116                 exit (2);
          117         }
          118         /* Allocate a pool of 16k secure memory.  This make the secure memory
          119         available and also drops privileges where needed.  */
          120         gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
          121         /* It is now okay to let Libgcrypt complain when there was/is
          122         a problem with the secure memory. */
          123         gcry_control (GCRYCTL_RESUME_SECMEM_WARN);
          124         /* Tell Libgcrypt that initialization has completed. */
          125         gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
          126 
          127         gcry_kdf_derive( pass, strlen(pass), GCRY_KDF_PBKDF2, GCRY_MD_SHA1, salt, salt_len, ic, result_len, result);
          128         print_hex(result, result_len);            // Key + IV   (as hex string)
          129 
          130         //clear and free everything
          131         for(i=0; i<result_len;i++)
          132                 result[i]=0;
          133         free(result);
          134         for(i=0; i<strlen(pass); i++) //blank
          135                 pass[i]=0;
          136         free(pass);
          137         for(i=0; i<strlen(argv[1])/2+3; i++) //blank
          138                 salt[i]=0;
          139         free(salt);
          140 
          141         return(0);
          142 }
          143 
          144 /* vim: set noexpandtab ts=4 sw=4: */