tpbkdf2.c - tomb - the crypto undertaker
HTML 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: */