-
Notifications
You must be signed in to change notification settings - Fork 541
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
391 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
/****************************************************************************** | ||
* ____ _ _____ * | ||
* / ___| / \ | ___| C++ * | ||
* | | / _ \ | |_ Actor * | ||
* | |___ / ___ \| _| Framework * | ||
* \____/_/ \_|_| * | ||
* * | ||
* Copyright 2011-2020 Dominik Charousset * | ||
* * | ||
* Distributed under the terms and conditions of the BSD 3-Clause License or * | ||
* (at your option) under the terms and conditions of the Boost Software * | ||
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. * | ||
* * | ||
* If you did not receive a copy of the license files, see * | ||
* http://opensource.org/licenses/BSD-3-Clause and * | ||
* http://www.boost.org/LICENSE_1_0.txt. * | ||
******************************************************************************/ | ||
|
||
#pragma once | ||
|
||
#include "caf/byte.hpp" | ||
#include "caf/detail/ieee_754.hpp" | ||
#include "caf/save_inspector_base.hpp" | ||
#include "caf/span.hpp" | ||
#include "caf/string_view.hpp" | ||
#include "caf/type_id.hpp" | ||
|
||
#include <array> | ||
|
||
namespace caf::hash { | ||
|
||
/// US Secure Hash Algorithm 1 (SHA1) as defined in RFC 3174. | ||
class sha1 : public save_inspector_base<sha1> { | ||
public: | ||
/// Hash size in bytes. | ||
static constexpr size_t hash_size = 20; | ||
|
||
/// Array type for storing a 160-bit hash. | ||
using result_type = std::array<byte, hash_size>; | ||
|
||
sha1() noexcept; | ||
|
||
static constexpr bool has_human_readable_format() noexcept { | ||
return false; | ||
} | ||
|
||
constexpr bool begin_object(string_view) { | ||
return true; | ||
} | ||
|
||
constexpr bool end_object() { | ||
return true; | ||
} | ||
|
||
bool begin_field(string_view) { | ||
return true; | ||
} | ||
|
||
bool begin_field(string_view, bool is_present) { | ||
return value(static_cast<uint8_t>(is_present)); | ||
} | ||
|
||
bool begin_field(string_view, span<const type_id_t>, size_t index) { | ||
return value(index); | ||
} | ||
|
||
bool begin_field(string_view, bool is_present, span<const type_id_t>, | ||
size_t index) { | ||
value(static_cast<uint8_t>(is_present)); | ||
if (is_present) | ||
value(index); | ||
return true; | ||
} | ||
|
||
constexpr bool end_field() { | ||
return true; | ||
} | ||
|
||
constexpr bool begin_tuple(size_t) { | ||
return true; | ||
} | ||
|
||
constexpr bool end_tuple() { | ||
return true; | ||
} | ||
|
||
constexpr bool begin_key_value_pair() { | ||
return true; | ||
} | ||
|
||
constexpr bool end_key_value_pair() { | ||
return true; | ||
} | ||
|
||
constexpr bool begin_sequence(size_t) { | ||
return true; | ||
} | ||
|
||
constexpr bool end_sequence() { | ||
return true; | ||
} | ||
|
||
constexpr bool begin_associative_array(size_t) { | ||
return true; | ||
} | ||
|
||
constexpr bool end_associative_array() { | ||
return true; | ||
} | ||
|
||
template <class Integral> | ||
std::enable_if_t<std::is_integral<Integral>::value, bool> | ||
value(Integral x) noexcept { | ||
auto begin = reinterpret_cast<const uint8_t*>(&x); | ||
append(begin, begin + sizeof(Integral)); | ||
return true; | ||
} | ||
|
||
bool value(bool x) noexcept { | ||
auto tmp = static_cast<uint8_t>(x); | ||
return value(tmp); | ||
} | ||
|
||
bool value(float x) noexcept { | ||
return value(detail::pack754(x)); | ||
} | ||
|
||
bool value(double x) noexcept { | ||
return value(detail::pack754(x)); | ||
} | ||
|
||
bool value(string_view x) noexcept { | ||
auto begin = reinterpret_cast<const uint8_t*>(x.data()); | ||
append(begin, begin + x.size()); | ||
return true; | ||
} | ||
|
||
bool value(span<const byte> x) noexcept { | ||
auto begin = reinterpret_cast<const uint8_t*>(x.data()); | ||
append(begin, begin + x.size()); | ||
return true; | ||
} | ||
|
||
/// Seals this SHA-1 context and returns the 160-bit message digest. | ||
result_type result() noexcept; | ||
|
||
/// Convenience function for computing a SHA-1 hash value for given arguments | ||
/// in one shot. | ||
template <class... Ts> | ||
static result_type compute(Ts&&... xs) noexcept { | ||
using detail::as_mutable_ref; | ||
sha1 f; | ||
auto unused = f.apply_objects(xs...); | ||
static_cast<void>(unused); // Always true. | ||
return f.result(); | ||
} | ||
|
||
private: | ||
bool append(const uint8_t* begin, const uint8_t* end) noexcept; | ||
|
||
void process_message_block(); | ||
|
||
void pad_message(); | ||
|
||
/// Stores whether `result()` has been called. | ||
bool sealed_ = 0; | ||
|
||
/// Stores the message digest so far. | ||
std::array<uint32_t, hash_size / 4> intermediate_; | ||
|
||
/// Stores the message length in bits. | ||
uint64_t length_ = 0; | ||
|
||
/// Stores the current index in `message_block_`. | ||
int_least16_t message_block_index_ = 0; | ||
|
||
/// Stores 512-bit message blocks. | ||
std::array<uint8_t, 64> message_block_; | ||
}; | ||
|
||
} // namespace caf::hash |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
/****************************************************************************** | ||
* ____ _ _____ * | ||
* / ___| / \ | ___| C++ * | ||
* | | / _ \ | |_ Actor * | ||
* | |___ / ___ \| _| Framework * | ||
* \____/_/ \_|_| * | ||
* * | ||
* Copyright 2011-2020 Dominik Charousset * | ||
* * | ||
* Distributed under the terms and conditions of the BSD 3-Clause License or * | ||
* (at your option) under the terms and conditions of the Boost Software * | ||
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. * | ||
* * | ||
* If you did not receive a copy of the license files, see * | ||
* http://opensource.org/licenses/BSD-3-Clause and * | ||
* http://www.boost.org/LICENSE_1_0.txt. * | ||
******************************************************************************/ | ||
|
||
#include "caf/hash/sha1.hpp" | ||
|
||
#include <cstring> | ||
|
||
#define SHA1CircularShift(bits, word) \ | ||
(((word) << (bits)) | ((word) >> (32 - (bits)))) | ||
|
||
namespace caf::hash { | ||
|
||
sha1::sha1() noexcept { | ||
intermediate_[0] = 0x67452301; | ||
intermediate_[1] = 0xEFCDAB89; | ||
intermediate_[2] = 0x98BADCFE; | ||
intermediate_[3] = 0x10325476; | ||
intermediate_[4] = 0xC3D2E1F0; | ||
memset(message_block_.data(), 0, message_block_.size()); | ||
} | ||
|
||
sha1::result_type sha1::result() noexcept { | ||
if (!sealed_) { | ||
pad_message(); | ||
memset(message_block_.data(), 0, message_block_.size()); | ||
length_ = 0; | ||
sealed_ = true; | ||
} | ||
std::array<byte, sha1::hash_size> buf; | ||
for (size_t i = 0; i < hash_size; ++i) { | ||
auto tmp = intermediate_[i >> 2] >> 8 * (3 - (i & 0x03)); | ||
buf[i] = static_cast<byte>(tmp); | ||
} | ||
return buf; | ||
} | ||
|
||
bool sha1::append(const uint8_t* begin, const uint8_t* end) noexcept { | ||
if (sealed_) { | ||
emplace_error(sec::runtime_error, | ||
"cannot append to a sealed SHA-1 context"); | ||
return false; | ||
} | ||
for (auto i = begin; i != end; ++i) { | ||
if (length_ >= std::numeric_limits<uint64_t>::max() - 8) { | ||
emplace_error(sec::runtime_error, "SHA-1 message too long"); | ||
return false; | ||
} | ||
message_block_[message_block_index_++] = *i; | ||
length_ += 8; | ||
if (message_block_index_ == 64) | ||
process_message_block(); | ||
} | ||
return true; | ||
} | ||
|
||
void sha1::process_message_block() { | ||
const uint32_t K[] = { | ||
0x5A827999, | ||
0x6ED9EBA1, | ||
0x8F1BBCDC, | ||
0xCA62C1D6, | ||
}; | ||
uint32_t W[80]; // Word sequence. | ||
uint32_t A, B, C, D, E; // Word buffers. | ||
for (auto t = 0; t < 16; t++) { | ||
W[t] = message_block_[t * 4] << 24; | ||
W[t] |= message_block_[t * 4 + 1] << 16; | ||
W[t] |= message_block_[t * 4 + 2] << 8; | ||
W[t] |= message_block_[t * 4 + 3]; | ||
} | ||
|
||
for (auto t = 16; t < 80; t++) { | ||
W[t] = SHA1CircularShift(1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]); | ||
} | ||
A = intermediate_[0]; | ||
B = intermediate_[1]; | ||
C = intermediate_[2]; | ||
D = intermediate_[3]; | ||
E = intermediate_[4]; | ||
for (auto t = 0; t < 20; t++) { | ||
auto tmp = SHA1CircularShift(5, A) + ((B & C) | ((~B) & D)) + E + W[t] | ||
+ K[0]; | ||
E = D; | ||
D = C; | ||
C = SHA1CircularShift(30, B); | ||
B = A; | ||
A = tmp; | ||
} | ||
for (auto t = 20; t < 40; t++) { | ||
auto tmp = SHA1CircularShift(5, A) + (B ^ C ^ D) + E + W[t] + K[1]; | ||
E = D; | ||
D = C; | ||
C = SHA1CircularShift(30, B); | ||
B = A; | ||
A = tmp; | ||
} | ||
for (auto t = 40; t < 60; t++) { | ||
auto tmp = SHA1CircularShift(5, A) + ((B & C) | (B & D) | (C & D)) + E | ||
+ W[t] + K[2]; | ||
E = D; | ||
D = C; | ||
C = SHA1CircularShift(30, B); | ||
B = A; | ||
A = tmp; | ||
} | ||
for (auto t = 60; t < 80; t++) { | ||
auto tmp = SHA1CircularShift(5, A) + (B ^ C ^ D) + E + W[t] + K[3]; | ||
E = D; | ||
D = C; | ||
C = SHA1CircularShift(30, B); | ||
B = A; | ||
A = tmp; | ||
} | ||
intermediate_[0] += A; | ||
intermediate_[1] += B; | ||
intermediate_[2] += C; | ||
intermediate_[3] += D; | ||
intermediate_[4] += E; | ||
message_block_index_ = 0; | ||
} | ||
|
||
void sha1::pad_message() { | ||
if (message_block_index_ > 55) { | ||
message_block_[message_block_index_++] = 0x80; | ||
while (message_block_index_ < 64) | ||
message_block_[message_block_index_++] = 0; | ||
process_message_block(); | ||
while (message_block_index_ < 56) | ||
message_block_[message_block_index_++] = 0; | ||
} else { | ||
message_block_[message_block_index_++] = 0x80; | ||
while (message_block_index_ < 56) | ||
message_block_[message_block_index_++] = 0; | ||
} | ||
message_block_[56] = static_cast<uint8_t>(length_ >> 56); | ||
message_block_[57] = static_cast<uint8_t>(length_ >> 48); | ||
message_block_[58] = static_cast<uint8_t>(length_ >> 40); | ||
message_block_[59] = static_cast<uint8_t>(length_ >> 32); | ||
message_block_[60] = static_cast<uint8_t>(length_ >> 24); | ||
message_block_[61] = static_cast<uint8_t>(length_ >> 16); | ||
message_block_[62] = static_cast<uint8_t>(length_ >> 8); | ||
message_block_[63] = static_cast<uint8_t>(length_); | ||
process_message_block(); | ||
} | ||
|
||
} // namespace caf::hash |
Oops, something went wrong.