Thanks a lot Dave for pointing out few things which i need to take care. By the way as this is not complete code, original code already has taken care of few things.
Now coming to the original question, how do i make sure PKCS5_PBKDF2_HMAC_SHA1() is generating the correct result of my i/p data? When i input RAND_bytes() data into PKCS5_PBKDF2_HMAC_SHA1(), i get a different result but when the same is converted to ASCII (human readable format), i get a different result. ... Any thoughts on this? Dave Thompson-5 wrote: > >> From: owner-openssl-us...@openssl.org On Behalf Of pkumarn >> Sent: Monday, 19 March, 2012 03:06 > >> I am trying to use PKCS5_PBKDF2_HMAC_SHA1() and below is my >> sample program. >> I wanted to make sure if my result of >> PKCS5_PBKDF2_HMAC_SHA1() is correct so >> i verified the same with the below wesbite >> http://anandam.name/pbkdf2/ and i >> see a different result... Am i using the API correctly? >> I am having doubts if i am passing salt value correctly... >> > That site is Javascript which treats the salt (and password) > directly as data. I don't know if or how browser(s) can > reliably enter data other than printable ASCII in a <form>; > it may very well depend on browser and locale settings. > For simplicity if you want to interoperate with this PBKDF2 > implementation I would therefore limit both salt and password > to printable ASCII 0x20-0x7E. (32 chars of salt, even restricted > to 5 or 6 bits entropy each, is far more than needed, especially > if you are deriving a 40-bit key as your code indicates.) > >> #include <stdio.h> >> #include <openssl/rand.h> >> #include <types.h> >> #include <string.h> >> #include <stdio.h> >> #include <string.h> >> #include <stdlib.h> >> >> #include <malloc.h> >> >> #include <openssl/hmac.h> >> #include <openssl/evp.h> >> #include <openssl/engine.h> >> #include <openssl/aes.h> >> > Asides: malloc.h is not standard or portable; standardly > malloc() and related functions are in stdlib.h. > types.h is not standard C (though sys/types.h is POSIX). > Repeating string.h is clutter and may waste time. > I would group openssl/rand.h with the other openssl/*. > >> #include <proto.h> >> #define KEY_LEN 32// 32 bytes - 256 bits >> #define KEK_KEY_LEN 5 >> #define ITERATION 1000 >> >> //unsigned char salt_value[32]={"5d85947b4292ea6463faf6893451232"}; >> unsigned char salt_value[KEY_LEN]; >> unsigned char AESkey[KEY_LEN]; >> unsigned char XTSkey[KEY_LEN]; >> u8 fuse_key[KEY_LEN]; >> > Aside: using KEY_LEN as the length of the salt (which is not a key > of any kind) is somewhat confusing; suggest SALT_LEN instead. > KEK_KEY_LEN is redundant, like "CPU unit"; suggest KEK_LEN. >> >> void main() > > main returning void is not standard and never has been, > and has no advantage whatsoever over the standard, int. > >> { >> >> s32 i=0; >> s32 len =0; >> u8 *out; >> u8 *rspHMAC; >> const s8 pwd[] = "test"; >> s8 rspPKCS5[KEK_KEY_LEN * 2]; >> s32 ret; >> > Note: these types are not standard or portable. C99 > (still not implemented everywhere, even though C11 has > just come out) *may* have types of the form int8_t etc. > However, below you treat pwd and rspPKCS5 below as arrays > of 'plain' char. 'Plain' char is unsigned on some systems, > so you would either have to make 's8' unsigned which is > confusing and likely to lead to bugs, or leave s8 signed > but convert all your accesses to be unsigned, which is > a good deal of extra work and easy to get wrong. > >> rspHMAC = (unsigned char *) malloc(sizeof(char) * KEY_LEN); >> out = (unsigned char *) malloc(sizeof(char) * KEK_KEY_LEN); >> > The return from malloc never needs to be cast in valid C; in C++ > it does but in C++ you generally shouldn't use malloc at all. > For these small fixed sizes, dynamic allocation is a waste of > effort and clutter. sizeof(char) is always 1 so it isn't needed, > although if you consistently follow the pattern of N*sizeof(E) > for all types it doesn't hurt to be consistent here. > >> RAND_bytes(salt_value, KEY_LEN); >> >> >> printf("\n salt_value[0] = %x; salt_value[31]= %x", salt_value[0], >> salt_value[31]); >> printf("\n strlen(salt_value) = %d; sizeof(salt_value) = %d\n", >> strlen(salt_value), sizeof(salt_value)); >> //printf("\n salt_value = %s", salt_value); >> > As I said before, RAND_bytes generates random bytes, > which can include null and then strlen() is too low; > while your buffer didn't include a null terminator (nor room > for one) so in general strlen() could be too high -- although > here salt_value is file-scope static and very likely to be > followed in memory by the next file-scope static here AESkey > which appears to be unused and thus still zero, although some > implementations may follow salt_value by the next _referenced_ > external static and that may well contain nonnull bytes. > > If you want a constant length, use a constant for length. > If you want variable length, determine it and remember it. > > But as above if you want to interoperate with the Javascript > on that website, it's probably easiest to limit yourself to > bytes which are printable ASCII characters. The simplest way > is just use columns 4 and 5 (0x40-0x5F). For that do: > if( RAND_bytes (salt_value,N) <= 0 ) /* ERROR! */ > for( i = 0; i < N; i ++ ) > salt_value[i] = (salt_value[i] & 0x1F) | 0x40; > // parens redundant but shown for clarity > As above, 32 chars of 5 bits entropy is more than needed > for security; 50-100 bits (10-20 x 5) is usually plenty > and usually more than the actual strength of the password. > >> for(i = 0; i < KEY_LEN; i++) { >> printf("%02x", salt_value[i]); >> > Here you correctly use the constant length KEY_LEN, > to convert to hex. But for the Javascript above, > you don't want hex, you want actual bytes. > >> } >> >> ret = PKCS5_PBKDF2_HMAC_SHA1(pwd, strlen(pwd), salt_value, >> strlen(salt_value), ITERATION, KEK_KEY_LEN, out); >> printf("\n PKCS#5 :"); >> > As above for strlen(salt_value). strlen(pwd) is okay > given you chose pwd to be valid C string (and further > a string of printable ASCII, good for that Javascript). > In real use the password should not be hardcoded, nor > a single dictionary word or other easily guessable value; > I assume this code is just an example. > >> for(len = 0; len < KEK_KEY_LEN; len++){ >> printf("%02x", out[len]); >> /* o/p of PKCS5 is stored in buf "out". This cannot be >> used directly >> as each out[len] will have 2 char >> but for key gen, we need to consider each char of out >> as a value. - >> Needs sentence reframing >> */ >> sprintf(&rspPKCS5[len * 2], "%02x", out[len]); >> } >> > This is unsafe as written. You KEK_KEY_LEN=5 bytes into > rspPKCS5[KEK_KEY_LEN*2] as two hex chars each, _plus > a null terminator_. Increase it by 1 (at least). > >> printf("\n"); >> } >> >> Sample O/P: >> >> salt_value[0] = e2; salt_value[31]= 12 >> strlen(salt_value) = 32; sizeof(salt_value) = 32 >> e258017933f3e629a4166cece78f3162a3b0b7edb2e94c93d76fe6c38198ea12 >> PKCS#5 :7d7ec9f411 >> >> Website result: >> The derived 40-bit key is: a5caf6a0d3 >> >> >> > > ______________________________________________________________________ > OpenSSL Project http://www.openssl.org > User Support Mailing List openssl-users@openssl.org > Automated List Manager majord...@openssl.org > > -- View this message in context: http://old.nabble.com/How-to-use-PKCS5_PBKDF2_HMAC_SHA1%28%29-tp33529423p33536514.html Sent from the OpenSSL - User mailing list archive at Nabble.com. ______________________________________________________________________ OpenSSL Project http://www.openssl.org User Support Mailing List openssl-users@openssl.org Automated List Manager majord...@openssl.org