Equivalent to PasswordDeriveBytes in openssl
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?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);
}
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.
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);
}
}
};
}
精彩评论