Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to use PKCS5_PBKDF2_HMAC_SHA1()

429 views
Skip to first unread message

pkumarn

unread,
Mar 19, 2012, 3:05:45 AM3/19/12
to

Hi,

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...

I have pasted my result and website result after the program...

Please guide me to understand this...




===================================================

#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>

#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];


void main()
{

s32 i=0;
s32 len =0;
u8 *out;
u8 *rspHMAC;
const s8 pwd[] = "test";
s8 rspPKCS5[KEK_KEY_LEN * 2];
s32 ret;

rspHMAC = (unsigned char *) malloc(sizeof(char) * KEY_LEN);
out = (unsigned char *) malloc(sizeof(char) * KEK_KEY_LEN);

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);

for(i = 0; i < KEY_LEN; i++) {
printf("%02x", salt_value[i]);

}

ret = PKCS5_PBKDF2_HMAC_SHA1(pwd, strlen(pwd), salt_value,
strlen(salt_value), ITERATION, KEK_KEY_LEN, out);
printf("\n PKCS#5 :");

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]);
}

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



--
View this message in context: http://old.nabble.com/How-to-use-PKCS5_PBKDF2_HMAC_SHA1%28%29-tp33529423p33529423.html
Sent from the OpenSSL - User mailing list archive at Nabble.com.

______________________________________________________________________
OpenSSL Project http://www.openssl.org
User Support Mailing List openss...@openssl.org
Automated List Manager majo...@openssl.org

Dave Thompson

unread,
Mar 19, 2012, 9:30:31 PM3/19/12
to
> From: owner-ope...@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
>
>
>

pkumarn

unread,
Mar 20, 2012, 12:35:35 AM3/20/12
to

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?
--
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.

pkumarn

unread,
Mar 21, 2012, 1:45:56 AM3/21/12
to

Firstly i am really thankful for you to being patient and throwing some light
on basic... even thought i was aware of few things, it was like a refresh
course :) ... thanks for that...

Coming to the usage, i really don't want to use HEX for the
PKCS5_PBKDF2_HMAC_SHA1(). I just want to input the values i got from
RAND_byes().

Here is what i am going to do, correct me if i am wrong
1. unsgined char rand[32]
2. RAND_bytes(rand, 32)

I will direcrtly use rand() in PKCS5_PBKDF2_HMAC_SHA1() and assume i have
got the correct result.

One of my engineer is asking me how do i know if PKCS5_PBKDF2_HMAC_SHA1()
has produced he right result.... he wants some other alternative tool to
verify my result... this is where i am stuck and found out the website but i
feel it is not going to be useful... any thoughts on this?




Dave Thompson-5 wrote:
>
>> From: owner-ope...@openssl.org On Behalf Of pkumarn
>> Sent: Tuesday, 20 March, 2012 00:36
>
>> 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. ...
>>
> Use the correct input to _PBKDF2_ and you get the correct
> output. Or more exactly, since there are a huge number of
> possible input sets (pw + salt + niter) and corresponding
> output key values, make sure that decrypt uses the *same*
> derivation inputs as encrypt did.
>
> You seem to be not understanding some of my answers;
> either you are using standard terminology differently,
> or misunderstanding how characters work in C. So let me
> start from the basics, even if this may be repetitive.
>
> 'char' in C or its variants 'signed char' and 'unsigned char'
> are actually a byte of storage, which is at least 8 bits and
> on current-day machines you are likely to program (like PCs
> and Macs) exactly 8 bits. It can contain a small integer:
> 0..255 for unsigned 8 bits or -128..-127 for signed 8 bits
> two's complement. (C also allows ones' complement and
> sign-and-magnitude, but no machines you will use do so.)
> This small integer *optionally* can be and *usually* is the
> codepoint for a character in a character code like ASCII.
> (C doesn't require ASCII, but the machines you will use do
> have either ASCII or much more likely a superset of ASCII
> like Windows-1252 or ISO-8859-1.) In C a string is an array
> of char, each element containing a codepoint, terminated by
> null. For example on a typical ASCII-based machine:
> char xyz [4] = "Dog";
> creates an array of 4 bytes, where
> xyz[0] = 68 = 0x44 // which is the ASCII codepoint for D
> xyz[1] = 111 = 0x6F // ditto o
> xyz[2] = 103 = 0x63 // ditto g
> xyz[3] = 0 // which is a null terminating byte/character
>
> C doesn't require that all byte values be codepoints for
> a character, and most commonly used codes have codepoints
> that either are totally unassigned or (now more common)
> aren't visible/displayable characters called graphics.
> (Space is displayable/printable but not a graphic.)
>
> Thus if you have arbitrary byte values, such as from
> RAND_bytes(a,n), they rarely (all) have meaning as ASCII
> graphics; they more often but not always have meaning
> as Windows-1252 or 8859-* graphics. To display such data
> 'losslessly' -- so that you can recover the exact bytes --
> you need some conversion. You mention 'conversion to ASCII'
> as if there were one such conversion; there are many, and
> you want a conversion to the graphic subset of ASCII, not
> the several invisible control codes (aka control chars).
> The most common are hexadecimal (abbreviated hex) and base64
> (with at least two major variants); you appear to want hex.
>
> If you convert 32 arbitrary bytes (your case) to hex, it
> is 64 characters (each of which is a hex digit). If you
> put that in a C string it also needs a null terminator.
> If you write it to a (text) file it may need a newline,
> and in some message formats it needs a tag or label etc.
>
> This converted hex string is different from the original
> data, and therefore using it for _PBKDF2_ will produce
> different (and wrong) output.
>
> Thus in general there are three approaches:
>
> - use arbitrary byte values for salt, in an environment where
> arbitrary values are okay. For example, in C you can write
> them to a disk file opened in binary mode and read them back
> unchanged. Some data formats, especially those using ASN.1
> like PCKS#7/CMS and PKCS#12, can handle arbitrary bytes.
>
> - use arbitrary byte values for salt, convert them to a safe
> representation such as hex for transmission and/or storage,
> *and* convert back to the arbitrary bytes when re-used.
>
> - use byte values for salt that are restricted so they are
> *already* valid character codepoints. In my previous post
> I gave the simple example of 0x40-0x5F for ASCII. As I said
> this reduces the entropy of your salt, but it's still much
> more than needed and much more than plausible passwords.
>
> Choose one.
>
> *If* you want compability with the Javascript on the website
> you pointed to, as-is that apparently requires choice 3,
> although I think it can be modified to do hex for choice 2.
> I think Javascript itself can handle arbitrary bytes in
> strings but as far as I can tell they can't be input using
> a browser form as that code does, ruling out choice 1.
>
>
> ______________________________________________________________________
> OpenSSL Project http://www.openssl.org
> User Support Mailing List openss...@openssl.org
> Automated List Manager majo...@openssl.org
>
>

--
View this message in context: http://old.nabble.com/How-to-use-PKCS5_PBKDF2_HMAC_SHA1%28%29-tp33529423p33543595.html
0 new messages