我正在尝试使用PKCS5_PBKDF2_HMAC_SHA1()
,以下是我的示例程序。我想确定PKCS5_PBKDF2_HMAC_SHA1()
的结果是否正确,所以我对网站http://anandam.name/pbkdf2/进行了相同的验证,我看到了不同的结果。我正确使用API吗?
我怀疑我是否正确地传递了盐值。
我在程序结束后粘贴了我的结果和网站结果。
请帮助我理解这一点。
#include <stdio.h>
#include <types.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>
#include <openssl/engine.h>
#include <openssl/aes.h>
#include <openssl/rand.h>
#include <proto.h>
#define KEY_LEN 32// 32 bytes - 256 bits
#define KEK_KEY_LEN 5
#define ITERATION 1000
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));
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]);
sprintf(&rspPKCS5[len * 2], "%02x", out[len]);
}
printf("\n");
}
示例输出:
salt_value[0] = e2; salt_value[31]= 12
strlen(salt_value) = 32; sizeof(salt_value) = 32
e258017933f3e629a4166cece78f3162a3b0b7edb2e94c93d76fe6c38198ea12
PKCS#5 :7d7ec9f411
网站结果:
The derived 40-bit key is: a5caf6a0d3
答案 0 :(得分:15)
首先,让我们看一下PBKDF2 HMAC-SHA1的official test vector:
Input:
P = "password" (8 octets)
S = "salt" (4 octets)
c = 1
dkLen = 20
Output:
DK = 0c 60 c8 0f 96 1f 0e 71
f3 a9 b5 24 af 60 12 06
2f e0 37 a6 (20 octets)
所以现在我们知道我们在网络和你的程序中拍摄的内容。因此,使用该信息,我们发现该网站希望您的salt作为ASCII字符串,然后将其转换为字节。这很重要,因为如果使用RAND_bytes
生成盐,就永远无法匹配网页的输出。
password
salt
1
20
0c60c80f961f0e71f3a9b524af6012062fe037a6
你正在使用不正确的盐。在注释行中,您将生成一个包含ASCII字符的字符串。如果要使用该盐,则必须将其声明为字节数组。另外,你错过了一个数字。
unsigned char salt_value[]= { 0x5d, 0x85, 0x94, 0x7b, … /* and so on */ };
在未注释的代码中,您生成一个字节数组,但将其视为字符串。您不在字节数组上调用strlen
,因为字节数组可以包含0,strlen将其解释为空终止符。因此,您可以手动跟踪大小(例如,您对malloc阵列的KEK_KEY_LEN定义),或者在适当时使用sizeof
。
PKCS5_PBKDF2_HMAC_SHA1(pwd, strlen(pwd), salt_value, sizeof(salt_value), ITERATION, KEK_KEY_LEN, out);
现在我们知道所有这些事情,我们可以整合一个完整的程序,与网站和官方测试向量的输出相匹配。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/evp.h>
#define KEY_LEN 32
#define KEK_KEY_LEN 20
#define ITERATION 1
int main()
{
size_t i;
unsigned char *out;
const char pwd[] = "password";
unsigned char salt_value[] = {'s','a','l','t'};
out = (unsigned char *) malloc(sizeof(unsigned char) * KEK_KEY_LEN);
printf("pass: %s\n", pwd);
printf("ITERATION: %u\n", ITERATION);
printf("salt: "); for(i=0;i<sizeof(salt_value);i++) { printf("%02x", salt_value[i]); } printf("\n");
if( PKCS5_PBKDF2_HMAC_SHA1(pwd, strlen(pwd), salt_value, sizeof(salt_value), ITERATION, KEK_KEY_LEN, out) != 0 )
{
printf("out: "); for(i=0;i<KEK_KEY_LEN;i++) { printf("%02x", out[i]); } printf("\n");
}
else
{
fprintf(stderr, "PKCS5_PBKDF2_HMAC_SHA1 failed\n");
}
free(out);
return 0;
}
(并注意主要需要返回int
并且你应该释放你分配的内存)
gcc pkcs5.c -o pkcs5 -g -lcrypto -Wall
./pkcs5
pass: password
ITERATION: 1
salt: 73616c74
out: 0c60c80f961f0e71f3a9b524af6012062fe037a6