Coder5546
31st July 2014, 20:43
Hi, we are trying to rewrite the function PasswordDeriveBytes from C#, but Microsoft function is not standard implementation of PKCS... it's extended...
We need this implementation to decode 3DES strings in new version of our application
C#:
String crc...
PasswordDeriveBytes passwordDeriveBytes = new PasswordDeriveBytes(crc, b);
byte[] u = passwordDeriveBytes.GetBytes(24);
byte[] iv = passwordDeriveBytes.GetBytes(8);
Qt:
QString crc..
Tools::PasswordDeriveBytes passwordDeriveBytes((byte *)crc.toUtf8().data(), b);
byte *key = passwordDeriveBytes.GetBytes(24);
byte *iv = passwordDeriveBytes.GetBytes(8);
PasswordDeriveBytes C++ Implementation found on web...
std::string Tools::PasswordDeriveBytes::convertInt(int number)
{
if (number == 0)
return "0";
std::string temp="";
std::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 Tools::PasswordDeriveBytes::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 Tools::PasswordDeriveBytes::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;
}
unsigned char *Tools::PasswordDeriveBytes::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)
{
std::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 Tools::PasswordDeriveBytes::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);
}
}
header
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 = 100)
{
Prepare(password, salt, iterations);
}
private:
std::string convertInt(int number);
void Prepare(unsigned char* password, unsigned char* salt, int iterations);
void Prepare(unsigned char* password, int pass_len, unsigned char* salt, int salt_len, int iterations);
public:
unsigned char* GetBytes(int cb);
void Reset();
};
and Mono version (C#)
https://raw.githubusercontent.com/mono/mono/master/mcs/class/corlib/System.Security.Cryptography/PasswordDeriveBytes.cs
returned byte arrays are not identical in the two implementations
We don't know how fix this problem..
Regards and thanks for any reply
We need this implementation to decode 3DES strings in new version of our application
C#:
String crc...
PasswordDeriveBytes passwordDeriveBytes = new PasswordDeriveBytes(crc, b);
byte[] u = passwordDeriveBytes.GetBytes(24);
byte[] iv = passwordDeriveBytes.GetBytes(8);
Qt:
QString crc..
Tools::PasswordDeriveBytes passwordDeriveBytes((byte *)crc.toUtf8().data(), b);
byte *key = passwordDeriveBytes.GetBytes(24);
byte *iv = passwordDeriveBytes.GetBytes(8);
PasswordDeriveBytes C++ Implementation found on web...
std::string Tools::PasswordDeriveBytes::convertInt(int number)
{
if (number == 0)
return "0";
std::string temp="";
std::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 Tools::PasswordDeriveBytes::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 Tools::PasswordDeriveBytes::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;
}
unsigned char *Tools::PasswordDeriveBytes::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)
{
std::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 Tools::PasswordDeriveBytes::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);
}
}
header
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 = 100)
{
Prepare(password, salt, iterations);
}
private:
std::string convertInt(int number);
void Prepare(unsigned char* password, unsigned char* salt, int iterations);
void Prepare(unsigned char* password, int pass_len, unsigned char* salt, int salt_len, int iterations);
public:
unsigned char* GetBytes(int cb);
void Reset();
};
and Mono version (C#)
https://raw.githubusercontent.com/mono/mono/master/mcs/class/corlib/System.Security.Cryptography/PasswordDeriveBytes.cs
returned byte arrays are not identical in the two implementations
We don't know how fix this problem..
Regards and thanks for any reply