sha1: cleanup and fix test cases
This commit is contained in:
parent
21b2b2368c
commit
fc935863ef
127
hash/sha1.cpp
127
hash/sha1.cpp
@ -20,6 +20,7 @@
|
||||
#include "sha1.hpp"
|
||||
|
||||
#include "bitwise.hpp"
|
||||
#include "debug.hpp"
|
||||
#include "endian.hpp"
|
||||
#include "types.hpp"
|
||||
#include "types/casts.hpp"
|
||||
@ -64,15 +65,16 @@ static const uint32_t K_40 = 0x8F1BBCDC;
|
||||
static const uint32_t K_60 = 0xCA62C1D6;
|
||||
|
||||
|
||||
static const uint32_t DEFAULT_H0 = 0x67452301;
|
||||
static const uint32_t DEFAULT_H1 = 0xEFCDAB89;
|
||||
static const uint32_t DEFAULT_H2 = 0x98BADCFE;
|
||||
static const uint32_t DEFAULT_H3 = 0x10325476;
|
||||
static const uint32_t DEFAULT_H4 = 0xC3D2E1F0;
|
||||
|
||||
|
||||
static const size_t BLOCK_SIZE = 16;
|
||||
static const uint32_t DEFAULT_H[] = {
|
||||
0x67452301,
|
||||
0xEFCDAB89,
|
||||
0x98BADCFE,
|
||||
0x10325476,
|
||||
0xC3D2E1F0
|
||||
};
|
||||
|
||||
static const size_t BLOCK_WORDS = 16;
|
||||
static const size_t BLOCK_BYTES = BLOCK_WORDS * sizeof (uint32_t);
|
||||
|
||||
SHA1::SHA1()
|
||||
{
|
||||
@ -83,53 +85,49 @@ SHA1::SHA1()
|
||||
void
|
||||
SHA1::reset (void) {
|
||||
total = 0;
|
||||
|
||||
H[0] = DEFAULT_H0;
|
||||
H[1] = DEFAULT_H1;
|
||||
H[2] = DEFAULT_H2;
|
||||
H[3] = DEFAULT_H3;
|
||||
H[4] = DEFAULT_H4;
|
||||
|
||||
std::fill (begin (W), end (W), 0);
|
||||
|
||||
state = READY;
|
||||
|
||||
std::copy (std::begin (DEFAULT_H), std::end (DEFAULT_H), H);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SHA1::update (const uint8_t *data, size_t size) {
|
||||
assert (state == READY);
|
||||
assert (numeric_limits<decltype(total)>::max () - total >= size);
|
||||
|
||||
CHECK_EQ (state, READY);
|
||||
CHECK_GE (numeric_limits<decltype(total)>::max () - total, size);
|
||||
|
||||
while (size > 0) {
|
||||
size_t offset = total % BLOCK_SIZE;
|
||||
size_t tocopy = std::min (BLOCK_SIZE - offset, size);
|
||||
// Copy the data into the remaining available buffer slots
|
||||
const size_t offset = total % BLOCK_BYTES;
|
||||
const size_t chunk = std::min (BLOCK_BYTES - offset, size);
|
||||
|
||||
for (size_t i = 0; i < tocopy; ++i) {
|
||||
size_t octet = sizeof(W[0]) - (offset + i) % sizeof (W[0]);
|
||||
size_t index = (offset / sizeof (W[0]) + i) / sizeof (W[0]);
|
||||
std::copy (data, data + chunk, c + offset);
|
||||
|
||||
size_t shift = (octet - 1) * 8u;
|
||||
uint32_t byte = *data++;
|
||||
total += chunk;
|
||||
|
||||
W[index] |= byte << shift;
|
||||
}
|
||||
|
||||
total += tocopy;
|
||||
|
||||
if (total % BLOCK_SIZE == 0) {
|
||||
// Attempt to process if full
|
||||
if (total % BLOCK_BYTES == 0)
|
||||
process ();
|
||||
std::fill (begin (W), end (W), 0);
|
||||
}
|
||||
size -= tocopy;
|
||||
|
||||
size -= chunk;
|
||||
data += chunk;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SHA1::process (void) {
|
||||
// Shuffle the work buffer a bit and initialise the state variables
|
||||
CHECK_EQ (total % BLOCK_BYTES, 0);
|
||||
|
||||
// Byteswap the raw input we have buffered ready for arithmetic
|
||||
std::transform (std::begin (W),
|
||||
std::end (W),
|
||||
std::begin (W),
|
||||
[] (uint32_t x) {
|
||||
return ntoh (x);
|
||||
});
|
||||
|
||||
// Initialise the work buffer and the state variables
|
||||
for (size_t t = 16; t < 80; ++t)
|
||||
W[t] = rotatel (W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1);
|
||||
|
||||
@ -154,7 +152,7 @@ SHA1::process (void) {
|
||||
for (size_t t = 40; t < 60; ++t) ROTATE_STATE(40);
|
||||
for (size_t t = 60; t < 80; ++t) ROTATE_STATE(60);
|
||||
|
||||
// Save out the intermediate hash again
|
||||
// Update the resulting hash state
|
||||
H[0] += A;
|
||||
H[1] += B;
|
||||
H[2] += C;
|
||||
@ -165,34 +163,37 @@ SHA1::process (void) {
|
||||
|
||||
void
|
||||
SHA1::finish (void) {
|
||||
size_t index = (total / sizeof (W[0])) % BLOCK_SIZE;
|
||||
size_t octet = sizeof (W[0]) - total % sizeof (W[0]) - 1;
|
||||
size_t offset = total % BLOCK_BYTES;
|
||||
size_t used = total * 8;
|
||||
|
||||
W[index] |= 0x80u << octet * 8u;
|
||||
if (index >= BLOCK_SIZE - 2) {
|
||||
W[elems(W) - 2] = 0;
|
||||
W[elems(W) - 1] = 0;
|
||||
process();
|
||||
std::fill (begin (W), end (W), 0);
|
||||
index = 0;
|
||||
} else {
|
||||
++index;
|
||||
// Append a single one bit
|
||||
c[offset++] = 0x80;
|
||||
total += 1;
|
||||
|
||||
// Zero fill if we can't append length
|
||||
size_t chunk = BLOCK_BYTES - offset;
|
||||
if (chunk < sizeof (total)) {
|
||||
std::fill_n (c + offset, chunk, 0);
|
||||
total += chunk;
|
||||
|
||||
process ();
|
||||
|
||||
chunk = BLOCK_BYTES;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
std::fill (begin (W) + index, end (W), 0);
|
||||
// Zero fill and append total length
|
||||
std::fill_n (c + offset, chunk - sizeof (total), 0);
|
||||
c[BLOCK_BYTES - 1] = used & 0xFF; used >>= 8;
|
||||
c[BLOCK_BYTES - 2] = used & 0xFF; used >>= 8;
|
||||
c[BLOCK_BYTES - 3] = used & 0xFF; used >>= 8;
|
||||
c[BLOCK_BYTES - 4] = used & 0xFF; used >>= 8;
|
||||
c[BLOCK_BYTES - 5] = used & 0xFF; used >>= 8;
|
||||
c[BLOCK_BYTES - 6] = used & 0xFF; used >>= 8;
|
||||
c[BLOCK_BYTES - 7] = used & 0xFF; used >>= 8;
|
||||
c[BLOCK_BYTES - 8] = used & 0xFF; used >>= 8;
|
||||
|
||||
union {
|
||||
uint32_t full;
|
||||
uint8_t part[4];
|
||||
} swapper;
|
||||
|
||||
swapper.full = 0;
|
||||
swapper.part[3] = uint8_t(total);
|
||||
|
||||
total *= 8;
|
||||
|
||||
W[BLOCK_SIZE - 2] = 0x00000000;
|
||||
W[BLOCK_SIZE - 1] = total << 24;
|
||||
total += chunk;
|
||||
process ();
|
||||
|
||||
state = FINISHED;
|
||||
@ -201,7 +202,7 @@ SHA1::finish (void) {
|
||||
|
||||
SHA1::digest_t
|
||||
SHA1::digest (void) const {
|
||||
assert (state == FINISHED);
|
||||
CHECK_EQ (state, FINISHED);
|
||||
|
||||
return { {
|
||||
size_cast<uint8_t> ((H[0] >> 24u) & 0xFF),
|
||||
|
@ -53,7 +53,7 @@ namespace util {
|
||||
|
||||
union {
|
||||
uint8_t c[16*4+64*4];
|
||||
uint32_t W[16+64];
|
||||
uint32_t W[16 +64 ];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "../hash/sha1.hpp"
|
||||
|
||||
#include "../debug.hpp"
|
||||
#include "../types.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
@ -38,21 +39,22 @@ main (int, char**) {
|
||||
0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, 0xE5, 0x46, 0x70, 0xF1 } }
|
||||
},
|
||||
|
||||
{ "a",
|
||||
{ { 0x34, 0xAA, 0x97, 0x3C, 0xD4, 0xC4, 0xDA, 0xA4, 0xF6, 0x1E,
|
||||
0xEB, 0x2B, 0xDB, 0xAD, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6F } }
|
||||
},
|
||||
// 1'000'000 * 'a'
|
||||
//{ "a",
|
||||
// { { 0x34, 0xAA, 0x97, 0x3C, 0xD4, 0xC4, 0xDA, 0xA4, 0xF6, 0x1E,
|
||||
// 0xEB, 0x2B, 0xDB, 0xAD, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6F } }
|
||||
//},
|
||||
|
||||
{ "0123456701234567012345670123456701234567012345670123456701234567",
|
||||
{ { 0xDE, 0xA3, 0x56, 0xA2, 0xCD, 0xDD, 0x90, 0xC7, 0xA7, 0xEC,
|
||||
0xED, 0xC5, 0xEB, 0xB5, 0x63, 0x93, 0x4F, 0x46, 0x04, 0x52 } }
|
||||
}
|
||||
// 80 repetitions of 01234567
|
||||
//{ "0123456701234567012345670123456701234567012345670123456701234567",
|
||||
// { { 0xDE, 0xA3, 0x56, 0xA2, 0xCD, 0xDD, 0x90, 0xC7, 0xA7, 0xEC,
|
||||
// 0xED, 0xC5, 0xEB, 0xB5, 0x63, 0x93, 0x4F, 0x46, 0x04, 0x52 } }
|
||||
//}
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < elems (TESTS); ++i) {
|
||||
for (auto i: TESTS) {
|
||||
util::hash::SHA1 obj;
|
||||
obj.update (reinterpret_cast<const uint8_t*> (TESTS[i].input),
|
||||
strlen (TESTS[i].input));
|
||||
obj.update (reinterpret_cast<const uint8_t*> (i.input), strlen (i.input));
|
||||
obj.finish ();
|
||||
|
||||
for (uint8_t c: obj.digest ()) {
|
||||
@ -62,6 +64,8 @@ main (int, char**) {
|
||||
std::cout << std::hex << hi << lo << " ";
|
||||
}
|
||||
std::cout << "\n";
|
||||
|
||||
CHECK (obj.digest () == i.output);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user