相当于openssl中的PasswordDeriveBytes

时间:2010-10-04 13:11:19

标签: c# cryptography openssl

我有C#代码如下:


        private static string password = "Password";
        private static string salt = "SALT";
        private static string hashAlgorithm = "SHA1";
        private static int iterations = 2;

        var saltValueBytes = Encoding.UTF8.GetBytes(salt);
        var passwordKey = new PasswordDeriveBytes(password, saltValueBytes, hashAlgorithm, iterations)
...

我需要在Mac中实现相同的功能,我才知道Opnessl实现了相关的方法(即libcrypto)。

Opnessl对上述代码的等效方法是什么?

3 个答案:

答案 0 :(得分:3)

这显示了如何使用OpenSSL实现PBKDF1,根据文档是PasswordDeriveBytes使用的算法。

#include <string.h>
#include <stdlib.h>
#include <openssl/sha.h>

void pbkdf1(const char *password, const char *salt, long iter, unsigned char dk[SHA_DIGEST_LENGTH])
{
    size_t pwlen = strlen(password);
    size_t dlen = pwlen + 8;
    unsigned char *buf;

    if (dlen > SHA_DIGEST_LENGTH)
        buf = malloc(dlen);
    else
        buf = malloc(SHA_DIGEST_LENGTH);

    memcpy(buf, password, pwlen);
    strncpy((char *)buf + pwlen, salt, 8);

    while (iter-- > 0)
    {
        SHA1(buf, dlen, buf);
        dlen = SHA_DIGEST_LENGTH;
    }

    memcpy(dk, buf, SHA_DIGEST_LENGTH);
    free(buf);
}

答案 1 :(得分:1)

OpenSSL实现了PBKDF2,.NET公开为Rfc2898DeriveBytesPasswordDeriveBytes使用(根据the .NET 4 docs)“PBKDF1算法的扩展”。 OpenSSL不会暴露PBKDF1(谁知道问题的'扩展'可能是什么)。

如果可能的话,使用PBKDF2(又名Rfc2898DeriveBytes)可以为您节省很多问题。

答案 2 :(得分:1)

这是执行GetBytes(X)的mono source code的c ++快速而脏的转换,其中X可能大于散列的大小。如您所见,我只实现了SHA1版本......

#include <iostream>
#include <string.h>
#include <openssl/sha.h>

#define SHA1_BYTES_LEN 20

using namespace std;

namespace DeriveKeys
{
class PasswordDeriveBytes
{

private:
    unsigned char* password;
    int pass_len;
    unsigned char* salt;
    int salt_len;
    int IterationCount;
    int state;
    unsigned char* initial;
    unsigned char* output;
    unsigned int output_len;
    unsigned int position;
    int hashnumber;
public:


    PasswordDeriveBytes(unsigned char* password, unsigned char* salt, int iterations)
    {
    Prepare(password, salt, iterations);
    }


private:
    string convertInt(int number)
    {
    if (number == 0)
        return "0";
    string temp="";
    string returnvalue="";
    while (number>0)
    {
        temp+=number%10+48;
        number/=10;
    }
    for (unsigned int i=0; i<temp.length(); i++)
        returnvalue+=temp[temp.length()-i-1];
    return returnvalue;
    }

    void Prepare(unsigned char* password, unsigned char* salt, int iterations)
    {
    if (password == NULL)
        return;

    Prepare(password, strlen((const char*)password), salt, strlen((const char*)salt), iterations);
    }

    void Prepare(unsigned char* password, int pass_len, unsigned char* salt, int salt_len, int iterations)
    {
    if (password == NULL)
        return;

    this->password = new unsigned char[pass_len];
    memcpy(this->password,password,pass_len);
    //memcpy((char *)this->password, (const char*)password, pass_len);
    this->pass_len = pass_len;
    //(unsigned char*)password.Clone();

    this->salt = new unsigned char[salt_len];
    //strncpy((char *)this->salt, (const char*)salt, salt_len);
    memcpy(this->salt,salt,salt_len);
    this->salt_len = salt_len;

    this->IterationCount = iterations;
    state = 0;
    }

public:
    unsigned char* GetBytes(int cb)
    {
    if (cb < 1)
        return NULL;

    if (state == 0)
    {
        // it's now impossible to change the HashName, Salt
        // and IterationCount
        Reset();
        state = 1;
    }

    unsigned char* result = new unsigned char[cb];
    int cpos = 0;
    // the initial hash (in reset) + at least one iteration
    int iter = IterationCount-1;
    if (iter < 1)
    {
        iter = 1;
    }

    // start with the PKCS5 key
    if (this->output == NULL)
    {
        // calculate the PKCS5 key
        this->output = initial;
        this->output_len = SHA1_BYTES_LEN;

        // generate new key material
        for (int i = 0; i < iter - 1; i++)
        {
            SHA1((const unsigned char*)this->output,this->output_len,this->output);
            this->output_len = SHA1_BYTES_LEN;
        }
    }

    while (cpos < cb)
    {
        unsigned char* output2 = new unsigned char[SHA1_BYTES_LEN];
        unsigned int output2_len = SHA1_BYTES_LEN;
        if (hashnumber == 0)
        {
            SHA1((const unsigned char*)this->output,this->output_len,output2);
            output2_len = SHA1_BYTES_LEN;
        }
        else if (hashnumber < 1000)
        {
            string n = convertInt(hashnumber);
            output2 = new unsigned char[this->output_len + n.length()];
            output2_len = this->output_len + n.length();
            for (unsigned int j = 0; j < n.length(); j++)
                output2[j] = (unsigned char)(n[j]);

            memcpy(output2 + n.length(),this->output,this->output_len);
            SHA1((const unsigned char*)output2,output2_len,output2);
            output2_len = SHA1_BYTES_LEN;
        }
        else
        {
            return NULL;
        }

        int rem = this->output_len - this->position;
        int l = cb - cpos;
        if (l > rem)
        {
            l = rem;
        }
        memcpy(result + cpos, output2 + this->position, l);
        cpos += l;
        this->position += l;
        while (this->position >= output2_len)
        {
            this->position -= output2_len;
            this->hashnumber++;
        }
    }
    return result;
    }

    void Reset()
    {
    this->state = 0;
    this->position = 0;
    this->hashnumber = 0;
    this->initial = new unsigned char[SHA1_BYTES_LEN];
    this->output = NULL;
    this->output_len = 0;
    if (this->salt != NULL)
    {
        unsigned char* rv = new unsigned char[this->pass_len + this->salt_len];
        memcpy(rv,this->password, this->pass_len);
        memcpy(rv + this->pass_len, this->salt, this->salt_len);
        SHA1((const unsigned char*)rv,this->pass_len + this->salt_len, initial);

    }
    else
    {
        SHA1((const unsigned char*)this->password,this->pass_len,initial);
    }
    }
};
}