Equivalent to PasswordDeriveBytes in openssl

陌路散爱 提交于 2019-12-21 23:42:34

问题


I have C# code as below:


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

I need to implement the same in Mac, I came to know that Opnessl implements related methods(i.e. libcrypto).

What is the equivalent method in Opnessl to above code?


回答1:


This shows how to implement PBKDF1 with OpenSSL, which according to the documentation is the algorithm used by 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);
}



回答2:


OpenSSL implements PBKDF2, which .NET exposes as Rfc2898DeriveBytes. PasswordDeriveBytes uses (according to the .NET 4 docs) "an extension of the PBKDF1 algorithm". PBKDF1 is not exposed by OpenSSL (and who knows what the 'extension' in question may be).

Using PBKDF2 (aka Rfc2898DeriveBytes) if possible will save you a lot of problems here.




回答3:


This is a c++ quick and dirty translation of the mono source code to perform GetBytes(X) where X can be greater than the size of the hash. As you can see I'v implemented only the SHA1 version...

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


来源:https://stackoverflow.com/questions/3855526/equivalent-to-passwordderivebytes-in-openssl

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!