Skip to content

Commit

Permalink
Add SHA1 hash implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
Neverlord committed Sep 16, 2020
1 parent ac0f23b commit 5dcbf6d
Show file tree
Hide file tree
Showing 5 changed files with 391 additions and 3 deletions.
3 changes: 2 additions & 1 deletion libcaf_core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS}
src/detail/thread_safe_actor_clock.cpp
src/detail/tick_emitter.cpp
src/detail/token_based_credit_controller.cpp
src/detail/token_based_credit_controller.cpp
src/detail/type_id_list_builder.cpp
src/downstream_manager.cpp
src/downstream_manager_base.cpp
Expand All @@ -118,6 +117,7 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS}
src/group.cpp
src/group_manager.cpp
src/group_module.cpp
src/hash/sha1.cpp
src/inbound_path.cpp
src/init_global_meta_objects.cpp
src/intrusive/inbox_result_strings.cpp
Expand Down Expand Up @@ -272,6 +272,7 @@ caf_add_test_suites(caf-core-test
fused_downstream_manager
handles
hash.fnv
hash.sha1
intrusive.drr_cached_queue
intrusive.drr_queue
intrusive.fifo_inbox
Expand Down
2 changes: 0 additions & 2 deletions libcaf_core/caf/hash/fnv.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ class fnv : public save_inspector_base<fnv<T>> {
public:
static_assert(sizeof(T) == 4 || sizeof(T) == 8);

using super = save_inspector;

constexpr fnv() noexcept : result(init()) {
// nop
}
Expand Down
181 changes: 181 additions & 0 deletions libcaf_core/caf/hash/sha1.hpp
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
161 changes: 161 additions & 0 deletions libcaf_core/src/hash/sha1.cpp
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
Loading

0 comments on commit 5dcbf6d

Please sign in to comment.