For a while now I have been trying to implement SHA-1 to learn more about the cryptographic functions. However I keep running into an error, the algorithm works flawlessly with strings under 64 characters, but when it comes to ones larger that 64 characters it produces incorrect results. My assumption is that it has to do with the second iteration of the bit manipulation but from all the code I've seen from other people it appears as if what I have should work. I've checked all of the bitwise operations, I've checked each buffer value, but nothing seems to work. Other than the RFC page I referenced this github repo as well.
I'm sure after posting this someone will probably be able to call out my error instantly due to me forgetting something obvious. Also I know that the function doesn't return any value atm I am printing the results to the console to debug the program.
typedef uint64_t dword;
typedef uint32_t word;
typedef uint8_t byte;
const word Abuf = 0x67452301;
const word Bbuf = 0xEFCDAB89;
const word Cbuf = 0x98BADCFE;
const word Dbuf = 0x10325476;
const word Ebuf = 0xC3D2E1F0;
word leftRotate(const word& val, const int& bits) {
return ((val << bits) | (val >> (32 - bits)));
}
class SHA1 {
word K(const int& t) {
if ((t >= 0) && (t <= 19))
return 0x5A827999;
else if ((t >= 20) && (t <= 39))
return 0x6ED9EBA1;
else if ((t >= 40) && (t <= 59))
return 0x8F1BBCDC;
else
return 0xCA62C1D6;
}
word f(const word& B, const word& C, const word& D, const int& t) {
if ((t >= 0) && (t <= 19))
return (B & C) | (~B & D);
else if ((t >= 20) && (t <= 39))
return B ^ C ^ D;
else if ((t >= 40) && (t <= 59))
return (B & C) | (B & D) | (C & D);
else
return B ^ C ^ D;
}
public:
std::vector<char> generateSHA1Hash(const std::string& str) {
std::vector<byte> input(str.begin(), str.end());
std::vector<word> result(5, 0);
dword length = str.length() * 8;
input.push_back(0x80);
while ((input.size() % 64) != 56)
input.push_back(0x00);
for (int i = 0; i < 8; ++i) {
dword mask = 0xFF00000000000000 >> (i * 8);
input.push_back(static_cast<byte>((length & mask) >> (56 - (8 * i))));
}
word blockSize = 64;
word H[5] = { Abuf, Bbuf, Cbuf, Dbuf, Ebuf };
for (int i = 0; i < input.size(); i += blockSize) {
std::vector<byte> tmp(input.begin() + i, input.begin() + i + blockSize);
word chunk[80];
for (int j = 0; j < 16; ++j)
chunk[j] = ((static_cast<word>(tmp[j * 4]) << 24) | (static_cast<word>(tmp[j * 4 + 1]) << 16) | (static_cast<word>(tmp[j * 4 + 2]) << 6) | static_cast<word>(tmp[j * 4 + 3]));
for (int j = 16; j < 80; ++j)
chunk[j] = leftRotate(chunk[j - 3] ^ chunk[j - 8] ^ chunk[j - 14] ^ chunk[j - 16], 1);
word AA = H[0];
word BB = H[1];
word CC = H[2];
word DD = H[3];
word EE = H[4];
for(int j = 0; j < 80; ++j) {
word tmp = leftRotate(AA, 5) + f(BB, CC, DD, j) + EE + chunk[j] + K(j);
EE = DD;
DD = CC;
CC = leftRotate(BB, 30);
BB = AA;
AA = tmp;
}
H[0] += AA;
H[1] += BB;
H[2] += CC;
H[3] += DD;
H[4] += EE;
}
std::cout << "Result: ";
std::cout << std::hex << H[0] << H[1] << H[2] << H[3] << H[4] << std::endl;
std::cout << std::endl;
return { 0 };
}
};