pbkdf2.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: */