13

我正在尝试使用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 
4

1 回答 1

19

首先,我们来看一个PBKDF2 HMAC-SHA1 的官方测试向量

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 将其解释为空终止符。因此,您可以手动跟踪大小(例如,您的 KEK_KEY_LEN 为您 malloc 的数组定义)或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;
}

(并注意 main 需要返回一个int,你应该释放你分配的内存)

gcc pkcs5.c -o pkcs5 -g -lcrypto -Wall
./pkcs5
pass: password
ITERATION: 1
salt: 73616c74
out: 0c60c80f961f0e71f3a9b524af6012062fe037a6
于 2012-03-20T05:51:33.773 回答