# Is this a proper PBKDF2 key derivation function algorithm?

I've started implementing PBKDF2 algorithm recently and since I'm new in crypto, I would like to ask if my implementation is good.
I looked up some documentations and I tried to follow many of them and now I am really confused.

Documentations I've followed:
https://en.wikipedia.org/wiki/PBKDF2
https://en.wikipedia.org/wiki/Hash-based_message_authentication_code
crackstation(.)net/hashing-security.htm#properhashing // (Sorry, I can't post more than 2 links.) And many more to which I no more have got links.

Here is my C/C++ code:

typedef unsigned long UL;
volatile class KDF2
{
#define hLenSz 32 // Block size of sha256 in bytes
public:
KDF2()
{
}

//Password-Based Key Derivation Function 2
std::string PBKDF2(string Password, string Salt, int c, int dkLen)
{
//Restrict max 128 bytes of Derivated Key
if(dkLen > 128)
{
dkLen = 128;
}

const int BlockSize = hLenSz / sizeof(UL); // 8 bytes

UL T = {}; // Holds DK in 4 byte chunks
UL L[BlockSize] = {};
UL H[BlockSize] = {};
string hash = "";
string innerSalt = Salt + (char)dkLen;

int l = ceil((float)dkLen / (float)hLenSz); // Compute the number of passes needed to get the desired DK length

for(int i = 0; i < l; i++)
{
memset(L, 0, sizeof(L));

//Iterate c times
for(int j = 0; j < c; j++)
{
hash = HMAC(innerSalt, Password);
innerSalt = hash;

HexToLong(hash, H, BlockSize);
//XOR function
for(int p = 0; p < BlockSize; p++)
{
L[p] = L[p] ^ H[p];
}
}

for(int x = 0; x < BlockSize; x++)
{
T[BlockSize * i + x] = L[x];
}
}

std::string output = "";
for(int i = 0; i < dkLen / sizeof(UL); i++) // dkLen / 4 - unsigned long has 4 bytes
{
// hexify takes sizeof(T) and converts it to hex bytes
output += hexify<UL>(T[i]);
}
return output;
}

private:
//Hash-based message authentication code
std::string HMAC(string Salt, string Password)
{
char c;
string s;
UL Key = {0};
UL X = {0};
UL Y = {0};
UL ipad = 0x36363636; // 0x36 = 54 = '6'
UL opad = 0x5c5c5c5c; // 0x5c = 92 = '\'
int k;
s = "";

//Process string key into sub-key
//Hash key in case it is less than 64 bytes
if(Password.length() > 64)
{
string tmp = sha256(Password);

HexToLong(tmp, Key, 5);
}
else
{
for(int i = 0; i < 16; i++)
{
for(int j = 0; j < 4; j++)
{
if(4 * i + j <= Password.length())
{
k = Password[4 * i + j];
}
else
{
k = 0;
}
if(k < 0)
{
k = k + 256;
}
Key[i] += +k*pow(256, (double)3 - j);
}
}
}

for(int i = 0; i < 16; i++)
{
X[i] = Key[i] ^ ipad;
Y[i] = Key[i] ^ opad;
}

//Turn X-Array into a String
for(int i = 0; i < 16; i++)
{
for(int j = 0; j < 4; j++)
{
c = ((X[i] >> 8 * (3 - j)) % 256);
s += c;
}
}

//Append text to string
s += Salt;

string tmp = sha256(s);
HexToLong(tmp, Key, 5);

s = "";

//Convert Y array to a string
for(int i = 0; i < 16; i++)
{
for(int j = 0; j < 4; j++)
{
c = ((Y[i] >> 8 * (3 - j)) % 256);
s += c;
}
}

for(int i = 0; i < 5; i++)
{
for(int j = 0; j < 4; j++)
{
c = ((Key[i] >> 8 * (3 - j)) % 256);
s += c;
}
}

//Hash final aggregated string
return sha256(s);
}

UL f(UL B, UL C, UL D, int t)
{
if(t < 20)
{
return ((B & C) ^ ((~B) & D));
}
if((t > 19) & (t < 40))
{
return (B ^ C ^ D);
}
if((t > 39) & (t < 60))
{
return ((B & C) ^ (B & D) ^ (C & D));
}
if(t > 59)
{
return (B ^ C ^ D);
}
}

template< typename T >
std::string hexify(T i)
{
std::stringbuf buf;
std::ostream os(&buf);

os << std::setfill('0') << std::setw(sizeof(T) * 2) << std::hex << i;

return buf.str().c_str();
}

void HexToLong(string input, unsigned long* output, int outSize)
{
char hx = {};

for(int i = 0; i < outSize; i++)
{
for(int j = 0; j < 8; j++)
{
hx[j] = input[j + (8 * i)];
}
output[i] = strtoul(hx, nullptr, 16);
}
}
};


The class is volatile because sometimes I ran into a optimization problem. I haven't yet figured out where the problem might be.

So to make it clear, my final questions are:

• Is this a proper PBKDF2 algorithm?

• Should PBKDF2 contain HMAC function or just iterate some hash over and over again with given No. iterations?

• How can I enhance the system?

• Why don't you test your implementation – Maarten Bodewes Sep 14 '15 at 23:11
• This would be better placed at code review. It's not a question about crypto, except Q2, which I think we'll not answer. – Maarten Bodewes Sep 14 '15 at 23:15
• As I said, I'm new to crypto, I didn't know that I can test my implementation. Why can't you answer the second question? – ProXicT Sep 14 '15 at 23:21
• @MaartenBodewes As I'm looking at the implementation test, that's not going to wrork for me. I'm using SHA256 instead of SHA1 and I've implemented some other things, that will make the final output different. – ProXicT Sep 14 '15 at 23:24
• There seems to be some confusion about the term PBKDF2. A PBKDF is a generic term, meaning password based key derivation function. PBKDF1 and 2 are PBKDFs and so are bcrypt and scrypt. PBKDF2 on the other hand is a specific algorithm which has a single specification which you cannot deviate from. Now do you want to create your own PBKDF or do you want to implement PBKDF2? – Maarten Bodewes Sep 15 '15 at 0:09

## 1 Answer

It appears there are no official test vectors for PBKDF2-HMAC-SHA256. A StackOverflow user has posted some test vectors that others have validated. Here are the test vectors for HMAC-SHA2 which you should also be running.

That said, if you have "implemented some other things that will make the final output different", then you do not have PBKDF2. PBKDF2 is a standard. If you deviate from the standard, you do not have PBKDF2. You should never deviate from the standard unless you really know what you are doing and have a very good reason to do so.

How can I enhance the system?

Depends on what your goals are. If you want to try to enhance the security of PBKDF2, you first have to define where you think PBKDF2 is not sufficient for your needs.

• Those are HMAC test vectors :) I think the implementation requires those too, but you might want to make this explicit in your answer. – Maarten Bodewes Sep 15 '15 at 0:05
• Our sister site has the missing PBKDF2 / SHA-256 test vectors. – Maarten Bodewes Sep 15 '15 at 0:52
• @MaartenBodewes, your first comment just finally clicked. Oops. – mikeazo Sep 15 '15 at 0:53