forked from Mirrors/openclonk
215 lines
5.7 KiB
C++
215 lines
5.7 KiB
C++
/*
|
|
|
|
Copyright 2007 Andy Tompkins.
|
|
|
|
Boost Software License - Version 1.0 - August 17th, 2003
|
|
|
|
Permission is hereby granted, free of charge, to any person or organization
|
|
obtaining a copy of the software and accompanying documentation covered by
|
|
this license (the "Software") to use, reproduce, display, distribute,
|
|
execute, and transmit the Software, and to prepare derivative works of the
|
|
Software, and to permit third-parties to whom the Software is furnished to
|
|
do so, all subject to the following:
|
|
|
|
The copyright notices in the Software and this entire statement, including
|
|
the above license grant, this restriction and the following disclaimer,
|
|
must be included in all copies of the Software, in whole or in part, and
|
|
all derivative works of the Software, unless such copies or derivative
|
|
works are solely in the form of machine-executable object code generated by
|
|
a source language processor.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
|
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
|
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
// This is a byte oriented implementation
|
|
// Note: this implementation does not handle message longer than
|
|
// 2^32 bytes.
|
|
|
|
#ifndef LIB_SHA1_H
|
|
#define LIB_SHA1_H
|
|
|
|
#include <cstddef>
|
|
|
|
static_assert(sizeof(unsigned char)*8 == 8, "Please reboot the C universe.");
|
|
static_assert(sizeof(unsigned int)*8 == 32, "sizeof(unsigned int) == 4");
|
|
|
|
#define SHA_DIGEST_LENGTH 20
|
|
|
|
class sha1
|
|
{
|
|
public:
|
|
typedef unsigned int(&digest_type)[5];
|
|
public:
|
|
sha1();
|
|
|
|
void reset();
|
|
|
|
void process_byte(unsigned char byte);
|
|
void process_block(void const* bytes_begin, void const* bytes_end);
|
|
void process_bytes(void const* buffer, std::size_t byte_count);
|
|
|
|
void get_digest(digest_type digest);
|
|
|
|
private:
|
|
void process_block();
|
|
static unsigned int left_rotate(unsigned int x, std::size_t n)
|
|
{
|
|
return (x<<n) ^ (x>> (32-n));
|
|
}
|
|
|
|
private:
|
|
unsigned int h_[5];
|
|
|
|
unsigned char block_[64];
|
|
|
|
std::size_t block_byte_index_;
|
|
std::size_t byte_count_;
|
|
};
|
|
|
|
inline sha1::sha1()
|
|
{
|
|
reset();
|
|
}
|
|
|
|
inline void sha1::reset()
|
|
{
|
|
h_[0] = 0x67452301;
|
|
h_[1] = 0xEFCDAB89;
|
|
h_[2] = 0x98BADCFE;
|
|
h_[3] = 0x10325476;
|
|
h_[4] = 0xC3D2E1F0;
|
|
|
|
block_byte_index_ = 0;
|
|
byte_count_ = 0;
|
|
}
|
|
|
|
inline void sha1::process_byte(unsigned char byte)
|
|
{
|
|
block_[block_byte_index_++] = byte;
|
|
++byte_count_;
|
|
if (block_byte_index_ == 64) {
|
|
block_byte_index_ = 0;
|
|
process_block();
|
|
}
|
|
}
|
|
|
|
inline void sha1::process_block(void const* bytes_begin, void const* bytes_end)
|
|
{
|
|
unsigned char const* begin = static_cast<unsigned char const*>(bytes_begin);
|
|
unsigned char const* end = static_cast<unsigned char const*>(bytes_end);
|
|
for(; begin != end; ++begin) {
|
|
process_byte(*begin);
|
|
}
|
|
}
|
|
|
|
inline void sha1::process_bytes(void const* buffer, std::size_t byte_count)
|
|
{
|
|
unsigned char const* b = static_cast<unsigned char const*>(buffer);
|
|
process_block(b, b+byte_count);
|
|
}
|
|
|
|
inline void sha1::process_block()
|
|
{
|
|
unsigned int w[80];
|
|
for (std::size_t i=0; i<16; ++i) {
|
|
w[i] = (block_[i*4 + 0] << 24);
|
|
w[i] |= (block_[i*4 + 1] << 16);
|
|
w[i] |= (block_[i*4 + 2] << 8);
|
|
w[i] |= (block_[i*4 + 3]);
|
|
}
|
|
for (std::size_t i=16; i<80; ++i) {
|
|
w[i] = left_rotate((w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]), 1);
|
|
}
|
|
|
|
unsigned int a = h_[0];
|
|
unsigned int b = h_[1];
|
|
unsigned int c = h_[2];
|
|
unsigned int d = h_[3];
|
|
unsigned int e = h_[4];
|
|
|
|
for (std::size_t i=0; i<80; ++i) {
|
|
unsigned int f;
|
|
unsigned int k;
|
|
|
|
if (i<20) {
|
|
f = (b & c) | (~b & d);
|
|
k = 0x5A827999;
|
|
} else if (i<40) {
|
|
f = b ^ c ^ d;
|
|
k = 0x6ED9EBA1;
|
|
} else if (i<60) {
|
|
f = (b & c) | (b & d) | (c & d);
|
|
k = 0x8F1BBCDC;
|
|
} else {
|
|
f = b ^ c ^ d;
|
|
k = 0xCA62C1D6;
|
|
}
|
|
|
|
unsigned temp = left_rotate(a, 5) + f + e + k + w[i];
|
|
e = d;
|
|
d = c;
|
|
c = left_rotate(b, 30);
|
|
b = a;
|
|
a = temp;
|
|
}
|
|
|
|
h_[0] += a;
|
|
h_[1] += b;
|
|
h_[2] += c;
|
|
h_[3] += d;
|
|
h_[4] += e;
|
|
}
|
|
|
|
inline void sha1::get_digest(digest_type digest)
|
|
{
|
|
std::size_t bit_count = byte_count_*8;
|
|
|
|
// append the bit '1' to the message
|
|
process_byte(0x80);
|
|
|
|
// append k bits '0', where k is the minimum number >= 0
|
|
// such that the resulting message length is congruent to 56 (mod 64)
|
|
// check if there is enough space for padding and bit_count
|
|
if (block_byte_index_ > 56) {
|
|
// finish this block
|
|
while (block_byte_index_ != 0) {
|
|
process_byte(0);
|
|
}
|
|
|
|
// one more block
|
|
while (block_byte_index_ < 56) {
|
|
process_byte(0);
|
|
}
|
|
} else {
|
|
while (block_byte_index_ < 56) {
|
|
process_byte(0);
|
|
}
|
|
}
|
|
|
|
// append length of message (before pre-processing)
|
|
// as a 64-bit big-endian integer
|
|
process_byte(0);
|
|
process_byte(0);
|
|
process_byte(0);
|
|
process_byte(0);
|
|
process_byte( static_cast<unsigned char>((bit_count>>24) & 0xFF));
|
|
process_byte( static_cast<unsigned char>((bit_count>>16) & 0xFF));
|
|
process_byte( static_cast<unsigned char>((bit_count>>8 ) & 0xFF));
|
|
process_byte( static_cast<unsigned char>((bit_count) & 0xFF));
|
|
|
|
// get final digest
|
|
digest[0] = h_[0];
|
|
digest[1] = h_[1];
|
|
digest[2] = h_[2];
|
|
digest[3] = h_[3];
|
|
digest[4] = h_[4];
|
|
}
|
|
|
|
#endif
|