diff --git a/common/SHA1.cpp b/common/SHA1.cpp new file mode 100644 index 0000000..8384a2a --- /dev/null +++ b/common/SHA1.cpp @@ -0,0 +1,192 @@ +#include "common/SHA1.hpp" +#include + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +#if defined(__BIG_ENDIAN__) +#define blk0(i) block->l[i] +#else +#define blk0(i) (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) | (rol(block->l[i], 8) & 0x00FF00FF)) +#endif + +#define blk(i) (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] ^ block->l[(i + 2) & 15] ^ block->l[i & 15], 1)) + +#define R0(v, w, x, y, z, i) \ + z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \ + w = rol(w, 30); +#define R1(v, w, x, y, z, i) \ + z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \ + w = rol(w, 30); +#define R2(v, w, x, y, z, i) \ + z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \ + w = rol(w, 30); +#define R3(v, w, x, y, z, i) \ + z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \ + w = rol(w, 30); +#define R4(v, w, x, y, z, i) \ + z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \ + w = rol(w, 30); + +void SHA1_Final(uint8_t* const digest, SHA1_CONTEXT* context) { + uint8_t finalcount[8]; + for (uint32_t i = 0; i < 8; i++) { + finalcount[i] = static_cast((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); + } + + SHA1_Update(context, reinterpret_cast("\200"), 1); + + while ((context->count[0] & 504) != 448) { + SHA1_Update(context, reinterpret_cast("\0"), 1); + } + + SHA1_Update(context, finalcount, 8); + + for (uint32_t i = 0; i < SHA1_DIGEST_SIZE; i++) { + digest[i] = static_cast((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); + } + + memset(context->buffer, 0, sizeof(context->buffer)); + memset(context->state, 0, sizeof(context->state)); + memset(context->count, 0, sizeof(context->count)); + memset(finalcount, 0, sizeof(finalcount)); +} + +void SHA1_Init(SHA1_CONTEXT* context) { + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = 0; + context->count[1] = 0; +} + +void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]) { + uint32_t a, b, c, d, e; + typedef union { + uint8_t c[64]; + uint32_t l[16]; + } CHAR64LONG16; + CHAR64LONG16* block; + + block = reinterpret_cast(const_cast(buffer)); + + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + + R0(a, b, c, d, e, 0); + R0(e, a, b, c, d, 1); + R0(d, e, a, b, c, 2); + R0(c, d, e, a, b, 3); + R0(b, c, d, e, a, 4); + R0(a, b, c, d, e, 5); + R0(e, a, b, c, d, 6); + R0(d, e, a, b, c, 7); + R0(c, d, e, a, b, 8); + R0(b, c, d, e, a, 9); + R0(a, b, c, d, e, 10); + R0(e, a, b, c, d, 11); + R0(d, e, a, b, c, 12); + R0(c, d, e, a, b, 13); + R0(b, c, d, e, a, 14); + R0(a, b, c, d, e, 15); + R1(e, a, b, c, d, 16); + R1(d, e, a, b, c, 17); + R1(c, d, e, a, b, 18); + R1(b, c, d, e, a, 19); + R2(a, b, c, d, e, 20); + R2(e, a, b, c, d, 21); + R2(d, e, a, b, c, 22); + R2(c, d, e, a, b, 23); + R2(b, c, d, e, a, 24); + R2(a, b, c, d, e, 25); + R2(e, a, b, c, d, 26); + R2(d, e, a, b, c, 27); + R2(c, d, e, a, b, 28); + R2(b, c, d, e, a, 29); + R2(a, b, c, d, e, 30); + R2(e, a, b, c, d, 31); + R2(d, e, a, b, c, 32); + R2(c, d, e, a, b, 33); + R2(b, c, d, e, a, 34); + R2(a, b, c, d, e, 35); + R2(e, a, b, c, d, 36); + R2(d, e, a, b, c, 37); + R2(c, d, e, a, b, 38); + R2(b, c, d, e, a, 39); + R3(a, b, c, d, e, 40); + R3(e, a, b, c, d, 41); + R3(d, e, a, b, c, 42); + R3(c, d, e, a, b, 43); + R3(b, c, d, e, a, 44); + R3(a, b, c, d, e, 45); + R3(e, a, b, c, d, 46); + R3(d, e, a, b, c, 47); + R3(c, d, e, a, b, 48); + R3(b, c, d, e, a, 49); + R3(a, b, c, d, e, 50); + R3(e, a, b, c, d, 51); + R3(d, e, a, b, c, 52); + R3(c, d, e, a, b, 53); + R3(b, c, d, e, a, 54); + R3(a, b, c, d, e, 55); + R3(e, a, b, c, d, 56); + R3(d, e, a, b, c, 57); + R3(c, d, e, a, b, 58); + R3(b, c, d, e, a, 59); + R4(a, b, c, d, e, 60); + R4(e, a, b, c, d, 61); + R4(d, e, a, b, c, 62); + R4(c, d, e, a, b, 63); + R4(b, c, d, e, a, 64); + R4(a, b, c, d, e, 65); + R4(e, a, b, c, d, 66); + R4(d, e, a, b, c, 67); + R4(c, d, e, a, b, 68); + R4(b, c, d, e, a, 69); + R4(a, b, c, d, e, 70); + R4(e, a, b, c, d, 71); + R4(d, e, a, b, c, 72); + R4(c, d, e, a, b, 73); + R4(b, c, d, e, a, 74); + R4(a, b, c, d, e, 75); + R4(e, a, b, c, d, 76); + R4(d, e, a, b, c, 77); + R4(c, d, e, a, b, 78); + R4(b, c, d, e, a, 79); + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; +} + +void SHA1_Update(SHA1_CONTEXT* context, const uint8_t* data, uint32_t len) { + uint32_t i, j; + + j = (context->count[0] >> 3) & 63; + if ((context->count[0] += len << 3) < (len << 3)) { + context->count[1]++; + } + + context->count[1] += (len >> 29); + + if ((j + len) > 63) { + memcpy(&context->buffer[j], data, (i = 64 - j)); + SHA1_Transform(context->state, reinterpret_cast(context->buffer)); + + for (; i + 63 < len; i += 64) { + SHA1_Transform(context->state, data + i); + } + + j = 0; + } else { + i = 0; + } + + memcpy(&context->buffer[j], &data[i], len - i); +} diff --git a/common/SHA1.hpp b/common/SHA1.hpp new file mode 100644 index 0000000..56606a9 --- /dev/null +++ b/common/SHA1.hpp @@ -0,0 +1,20 @@ +#ifndef COMMON_SHA1_HPP +#define COMMON_SHA1_HPP + +#include + +#define SHA1_DIGEST_SIZE 20 + +typedef struct { + uint32_t state[5]; + uint32_t count[2]; + char buffer[64]; +} SHA1_CONTEXT; + +void SHA1_Final(uint8_t* const digest, SHA1_CONTEXT* context); + +void SHA1_Init(SHA1_CONTEXT* context); + +void SHA1_Update(SHA1_CONTEXT* context, const uint8_t* data, uint32_t len); + +#endif diff --git a/test/SHA1.cpp b/test/SHA1.cpp new file mode 100644 index 0000000..5d3847e --- /dev/null +++ b/test/SHA1.cpp @@ -0,0 +1,57 @@ +#include "common/SHA1.hpp" +#include "test/Test.hpp" +#include + +TEST_CASE("SHA1_Final", "[util]") { + SECTION("correctly computes digest of empty string") { + auto input = ""; + uint8_t digest[SHA1_DIGEST_SIZE]; + uint8_t expected[SHA1_DIGEST_SIZE] = { 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09 }; + + SHA1_CONTEXT ctx; + SHA1_Init(&ctx); + SHA1_Update(&ctx, reinterpret_cast(input), strlen(input)); + SHA1_Final(digest, &ctx); + + REQUIRE(memcmp(digest, expected, sizeof(digest)) == 0); + } + + SECTION("correctly computes digest of 'abc'") { + auto input = "abc"; + uint8_t digest[SHA1_DIGEST_SIZE]; + uint8_t expected[SHA1_DIGEST_SIZE] = { 0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a, 0xba, 0x3e, 0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c, 0x9c, 0xd0, 0xd8, 0x9d }; + + SHA1_CONTEXT ctx; + SHA1_Init(&ctx); + SHA1_Update(&ctx, reinterpret_cast(input), strlen(input)); + SHA1_Final(digest, &ctx); + + REQUIRE(memcmp(digest, expected, sizeof(digest)) == 0); + } + + SECTION("correctly computes digest of 'test'") { + auto input = "test"; + uint8_t digest[SHA1_DIGEST_SIZE]; + uint8_t expected[SHA1_DIGEST_SIZE] = { 0xa9, 0x4a, 0x8f, 0xe5, 0xcc, 0xb1, 0x9b, 0xa6, 0x1c, 0x4c, 0x08, 0x73, 0xd3, 0x91, 0xe9, 0x87, 0x98, 0x2f, 0xbb, 0xd3 }; + + SHA1_CONTEXT ctx; + SHA1_Init(&ctx); + SHA1_Update(&ctx, reinterpret_cast(input), strlen(input)); + SHA1_Final(digest, &ctx); + + REQUIRE(memcmp(digest, expected, sizeof(digest)) == 0); + } + + SECTION("correctly computes digest of 0x53 0x51") { + uint8_t input[] = { 0x53, 0x51 }; + uint8_t digest[SHA1_DIGEST_SIZE]; + uint8_t expected[SHA1_DIGEST_SIZE] = { 0x0c, 0x3d, 0x7a, 0x19, 0xac, 0x7c, 0x62, 0x72, 0x90, 0xbf, 0x03, 0x1e, 0xc3, 0xdf, 0x76, 0x27, 0x7b, 0x0f, 0x7f, 0x75 }; + + SHA1_CONTEXT ctx; + SHA1_Init(&ctx); + SHA1_Update(&ctx, input, sizeof(input)); + SHA1_Final(digest, &ctx); + + REQUIRE(memcmp(digest, expected, sizeof(digest)) == 0); + } +}