Add SHA1 implementation
This commit is contained in:
parent
7099c9bc50
commit
9bdc50df3c
@ -48,6 +48,8 @@ UTIL_FILES = \
|
|||||||
hash/md4.hpp \
|
hash/md4.hpp \
|
||||||
hash/md5.cpp \
|
hash/md5.cpp \
|
||||||
hash/md5.hpp \
|
hash/md5.hpp \
|
||||||
|
hash/sha1.cpp \
|
||||||
|
hash/sha1.hpp \
|
||||||
image.cpp \
|
image.cpp \
|
||||||
image.hpp \
|
image.hpp \
|
||||||
io.cpp \
|
io.cpp \
|
||||||
|
228
hash/sha1.cpp
Normal file
228
hash/sha1.cpp
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of libgim.
|
||||||
|
*
|
||||||
|
* libgim is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* libgim is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with libgim. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Copyright 2013 Danny Robson <danny@nerdcruft.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "sha1.hpp"
|
||||||
|
|
||||||
|
#include "bitwise.hpp"
|
||||||
|
#include "endian.hpp"
|
||||||
|
#include "types.hpp"
|
||||||
|
#include "types/casts.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
|
||||||
|
using util::hash::SHA1;
|
||||||
|
using std::numeric_limits;
|
||||||
|
using std::begin;
|
||||||
|
using std::end;
|
||||||
|
|
||||||
|
|
||||||
|
// Logical function for sequence of rounds
|
||||||
|
static inline uint32_t
|
||||||
|
f_00 (uint32_t B, uint32_t C, uint32_t D)
|
||||||
|
{ return (B & C) | (~B & D); }
|
||||||
|
|
||||||
|
|
||||||
|
static inline uint32_t
|
||||||
|
f_20 (uint32_t B, uint32_t C, uint32_t D)
|
||||||
|
{ return B ^ C ^ D; }
|
||||||
|
|
||||||
|
|
||||||
|
static inline uint32_t
|
||||||
|
f_40 (uint32_t B, uint32_t C, uint32_t D)
|
||||||
|
{ return (B & C) | (B & D) | (C & D); }
|
||||||
|
|
||||||
|
|
||||||
|
static inline uint32_t
|
||||||
|
f_60 (uint32_t B, uint32_t C, uint32_t D)
|
||||||
|
{ return B ^ C ^ D; }
|
||||||
|
|
||||||
|
|
||||||
|
// Constant words for sequence of rounds
|
||||||
|
static const uint32_t K_00 = 0x5A827999;
|
||||||
|
static const uint32_t K_20 = 0x6ED9EBA1;
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
SHA1::SHA1()
|
||||||
|
{
|
||||||
|
reset ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SHA1::update (const uint8_t *data, size_t size) {
|
||||||
|
assert (state == READY);
|
||||||
|
assert (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);
|
||||||
|
|
||||||
|
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]);
|
||||||
|
|
||||||
|
size_t shift = (octet - 1) * 8u;
|
||||||
|
uint32_t byte = *data++;
|
||||||
|
|
||||||
|
W[index] |= byte << shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
total += tocopy;
|
||||||
|
|
||||||
|
if (total % BLOCK_SIZE == 0) {
|
||||||
|
process ();
|
||||||
|
std::fill (begin (W), end (W), 0);
|
||||||
|
}
|
||||||
|
size -= tocopy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SHA1::process (void) {
|
||||||
|
// Shuffle the work buffer a bit and initialise 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);
|
||||||
|
|
||||||
|
uint32_t A = H[0],
|
||||||
|
B = H[1],
|
||||||
|
C = H[2],
|
||||||
|
D = H[3],
|
||||||
|
E = H[4];
|
||||||
|
|
||||||
|
// Perform each of the four rounds
|
||||||
|
#define ROTATE_STATE(i) do { \
|
||||||
|
uint32_t temp = rotatel (A, 5) + f_##i (B, C, D) + E + W[t] + K_##i; \
|
||||||
|
E = D; \
|
||||||
|
D = C; \
|
||||||
|
C = rotatel (B, 30); \
|
||||||
|
B = A; \
|
||||||
|
A = temp; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
for (size_t t = 0; t < 20; ++t) ROTATE_STATE(00);
|
||||||
|
for (size_t t = 20; t < 40; ++t) ROTATE_STATE(20);
|
||||||
|
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
|
||||||
|
H[0] += A;
|
||||||
|
H[1] += B;
|
||||||
|
H[2] += C;
|
||||||
|
H[3] += D;
|
||||||
|
H[4] += E;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SHA1::finish (void) {
|
||||||
|
size_t index = (total / sizeof (W[0])) % BLOCK_SIZE;
|
||||||
|
size_t octet = sizeof (W[0]) - total % sizeof (W[0]) - 1;
|
||||||
|
|
||||||
|
W[index] |= 0x80 << octet * 8;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::fill (begin (W) + index, end (W), 0);
|
||||||
|
|
||||||
|
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;
|
||||||
|
process ();
|
||||||
|
|
||||||
|
state = FINISHED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SHA1::digest_t
|
||||||
|
SHA1::digest (void) const {
|
||||||
|
assert (state == FINISHED);
|
||||||
|
|
||||||
|
return { {
|
||||||
|
size_cast<uint8_t> ((H[0] >> 24u) & 0xFF),
|
||||||
|
size_cast<uint8_t> ((H[0] >> 16u) & 0xFF),
|
||||||
|
size_cast<uint8_t> ((H[0] >> 8u) & 0xFF),
|
||||||
|
size_cast<uint8_t> ((H[0] ) & 0xFF),
|
||||||
|
size_cast<uint8_t> ((H[1] >> 24u) & 0xFF),
|
||||||
|
size_cast<uint8_t> ((H[1] >> 16u) & 0xFF),
|
||||||
|
size_cast<uint8_t> ((H[1] >> 8u) & 0xFF),
|
||||||
|
size_cast<uint8_t> ((H[1] ) & 0xFF),
|
||||||
|
size_cast<uint8_t> ((H[2] >> 24u) & 0xFF),
|
||||||
|
size_cast<uint8_t> ((H[2] >> 16u) & 0xFF),
|
||||||
|
size_cast<uint8_t> ((H[2] >> 8u) & 0xFF),
|
||||||
|
size_cast<uint8_t> ((H[2] ) & 0xFF),
|
||||||
|
size_cast<uint8_t> ((H[3] >> 24u) & 0xFF),
|
||||||
|
size_cast<uint8_t> ((H[3] >> 16u) & 0xFF),
|
||||||
|
size_cast<uint8_t> ((H[3] >> 8u) & 0xFF),
|
||||||
|
size_cast<uint8_t> ((H[3] ) & 0xFF),
|
||||||
|
size_cast<uint8_t> ((H[4] >> 24u) & 0xFF),
|
||||||
|
size_cast<uint8_t> ((H[4] >> 16u) & 0xFF),
|
||||||
|
size_cast<uint8_t> ((H[4] >> 8u) & 0xFF),
|
||||||
|
size_cast<uint8_t> ((H[4] ) & 0xFF)
|
||||||
|
} };
|
||||||
|
}
|
62
hash/sha1.hpp
Normal file
62
hash/sha1.hpp
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of libgim.
|
||||||
|
*
|
||||||
|
* libgim is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* libgim is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with libgim. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Copyright 2013 Danny Robson <danny@nerdcruft.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __UTIL_HASH_SHA1_HPP
|
||||||
|
#define __UTIL_HASH_SHA1_HPP
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
|
||||||
|
namespace util {
|
||||||
|
namespace hash {
|
||||||
|
class SHA1 {
|
||||||
|
public:
|
||||||
|
typedef std::array<uint8_t,20> digest_t;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SHA1();
|
||||||
|
|
||||||
|
void update (const uint8_t *, size_t);
|
||||||
|
void finish (void);
|
||||||
|
digest_t digest (void) const;
|
||||||
|
void reset (void);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void process (void);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
READY,
|
||||||
|
FINISHED
|
||||||
|
} state;
|
||||||
|
|
||||||
|
uint64_t total;
|
||||||
|
uint32_t H[5];
|
||||||
|
|
||||||
|
union {
|
||||||
|
uint8_t c[16*4+64*4];
|
||||||
|
uint32_t W[16+64];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
3
test/.gitignore
vendored
3
test/.gitignore
vendored
@ -10,11 +10,12 @@
|
|||||||
/*.log
|
/*.log
|
||||||
/maths*
|
/maths*
|
||||||
/matrix*
|
/matrix*
|
||||||
/md[24]*
|
/md[245]*
|
||||||
/option
|
/option
|
||||||
/pool*
|
/pool*
|
||||||
/range*
|
/range*
|
||||||
/region*
|
/region*
|
||||||
|
/sha1*
|
||||||
/signal*
|
/signal*
|
||||||
/*.trs
|
/*.trs
|
||||||
/version*
|
/version*
|
||||||
|
@ -25,6 +25,7 @@ TEST_BIN = \
|
|||||||
range \
|
range \
|
||||||
region \
|
region \
|
||||||
signal \
|
signal \
|
||||||
|
sha1 \
|
||||||
version
|
version
|
||||||
|
|
||||||
TESTS = $(TEST_BIN) json.pl
|
TESTS = $(TEST_BIN) json.pl
|
||||||
@ -83,5 +84,8 @@ region_SOURCES = region.cpp
|
|||||||
signal_LDADD = $(builddir)/../libutil.la
|
signal_LDADD = $(builddir)/../libutil.la
|
||||||
signal_SOURCES = signal.cpp
|
signal_SOURCES = signal.cpp
|
||||||
|
|
||||||
|
sha1_LDADD = $(builddir)/../libutil.la
|
||||||
|
sha1_SOURCES = sha1.cpp
|
||||||
|
|
||||||
version_LDADD = $(builddir)/../libutil.la
|
version_LDADD = $(builddir)/../libutil.la
|
||||||
version_SOURCES = version.cpp
|
version_SOURCES = version.cpp
|
||||||
|
68
test/sha1.cpp
Normal file
68
test/sha1.cpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#include "../hash/sha1.hpp"
|
||||||
|
|
||||||
|
#include "../types.hpp"
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
|
using util::hash::SHA1;
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int, char**) {
|
||||||
|
static const struct {
|
||||||
|
const char *input;
|
||||||
|
SHA1::digest_t output;
|
||||||
|
} TESTS[] = {
|
||||||
|
{ "",
|
||||||
|
{ { 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55,
|
||||||
|
0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09 } }
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"a",
|
||||||
|
{ { 0x86, 0xf7, 0xe4, 0x37, 0xfa, 0xa5, 0xa7, 0xfc, 0xe1, 0x5d,
|
||||||
|
0x1d, 0xdc, 0xb9, 0xea, 0xea, 0xea, 0x37, 0x76, 0x67, 0xb8 } }
|
||||||
|
},
|
||||||
|
|
||||||
|
{ "abc",
|
||||||
|
{ { 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E,
|
||||||
|
0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D } }
|
||||||
|
},
|
||||||
|
|
||||||
|
{ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
|
||||||
|
{ { 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, 0xBA, 0xAE,
|
||||||
|
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 } }
|
||||||
|
},
|
||||||
|
|
||||||
|
{ "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) {
|
||||||
|
util::hash::SHA1 obj;
|
||||||
|
obj.update (reinterpret_cast<const uint8_t*> (TESTS[i].input),
|
||||||
|
strlen (TESTS[i].input));
|
||||||
|
obj.finish ();
|
||||||
|
|
||||||
|
for (uint8_t c: obj.digest ()) {
|
||||||
|
unsigned hi = c >> 4u;
|
||||||
|
unsigned lo = c & 0xF;
|
||||||
|
|
||||||
|
std::cout << std::hex << hi << lo << " ";
|
||||||
|
}
|
||||||
|
std::cout << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user