initial import from libcruft-util

This commit is contained in:
Danny Robson 2018-01-14 17:17:34 +11:00
commit 9fb5ff3136
45 changed files with 7099 additions and 0 deletions

96
CMakeLists.txt Normal file
View File

@ -0,0 +1,96 @@
###############################################################################
cmake_minimum_required(VERSION 3.7.0)
project(cruft-crypto CXX)
###############################################################################
if (NOT TARGET cruft-util)
message (FATAL_ERROR "cruft-util was not found")
endif ()
###############################################################################
list (APPEND sources
fwd.hpp
hash/md2.cpp
hash/md2.hpp
hash/md4.cpp
hash/md4.hpp
hash/md5.cpp
hash/md5.hpp
hash/ripemd.cpp
hash/ripemd.hpp
hash/sha1.cpp
hash/sha1.hpp
hash/sha2.cpp
hash/sha2.hpp
hash/hmac.cpp
hash/hmac.hpp
hash/hotp.cpp
hash/hotp.hpp
stream/rc4.cpp
stream/rc4.hpp
stream/salsa.cpp
stream/salsa.hpp
block/tea.cpp
block/tea.hpp
block/xtea.cpp
block/xtea.hpp
block/xxtea.cpp
block/xxtea.hpp
)
option (TESTS "enable unit testing" ON)
if (TESTS)
include (CTest)
enable_testing ()
list (APPEND tests
hash/md2
hash/md4
hash/md5
hash/ripemd
hash/sha1
hash/sha2
hash/hmac
hash/hotp
stream/rc4
stream/salsa
block/tea
block/xtea
block/xxtea
)
foreach (t ${tests})
string(REPLACE "/" "_" name "test/${t}")
add_executable(crypto_test_${name} test/${t}.cpp)
target_link_libraries(crypto_test_${name} PRIVATE cruft-crypto)
target_include_directories(crypto_test_${name} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
add_test(NAME crypto_test_${name} COMMAND crypto_test_${name})
endforeach()
endif ()
###############################################################################
add_library (cruft-crypto STATIC ${sources})
target_link_libraries (cruft-crypto INTERFACE cruft-util)
##-----------------------------------------------------------------------------
add_executable (crypto_hash tools/hash.cpp)
target_link_libraries (crypto_hash cruft-crypto)
###############################################################################
configure_file(libcruft-crypto.pc.in libcruft-crypto.pc)
configure_file(Doxyfile.in Doxyfile)

2384
Doxyfile.in Normal file

File diff suppressed because it is too large Load Diff

3
README Normal file
View File

@ -0,0 +1,3 @@
A naive C++17 implementation of several cryptography primitives.
Do not use this code for anything that needs security. They are deliberately not secure against many types of attack (such as cache timing attacks). Many were literally written between/during rounds of Overwatch or while watching Netflix...

86
block/tea.cpp Normal file
View File

@ -0,0 +1,86 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#include "tea.hpp"
#include <cstdint>
#include <stdexcept>
using cruft::crypto::block::TEA;
///////////////////////////////////////////////////////////////////////////////
static const std::uint32_t MAGIC = 0x9E3779B9;
// each iteration performs two feistel rounds, for a total of 64
static const unsigned ITERATIONS = 32;
///////////////////////////////////////////////////////////////////////////////
TEA::TEA (key_t _key):
m_key (_key)
{ ; }
//-----------------------------------------------------------------------------
void
TEA::encrypt (uint32_t *restrict data, size_t count)
{
if (count % 2)
throw std::invalid_argument ("TEA requires even data count");
auto last = data + count;
while (data < last) {
uint32_t sum = 0;
uint32_t v0 = data[0];
uint32_t v1 = data[1];
for (unsigned i = 0; i < ITERATIONS; ++i) {
sum += MAGIC;
v0 += ((v1 << 4) + m_key[0]) ^ (v1 + sum) ^ ((v1 >> 5) + m_key[1]);
v1 += ((v0 << 4) + m_key[2]) ^ (v0 + sum) ^ ((v0 >> 5) + m_key[3]);
}
*data++ = v0;
*data++ = v1;
}
}
//-----------------------------------------------------------------------------
void
TEA::decrypt (uint32_t *restrict data, size_t count)
{
if (count % 2)
throw std::invalid_argument ("TEA requires even data count");
auto last = data + count;
while (data < last) {
uint32_t sum = MAGIC << 5;
uint32_t v0 = data[0];
uint32_t v1 = data[1];
for (unsigned i = 0; i < ITERATIONS; ++i) {
v1 -= ((v0 << 4) + m_key[2]) ^ (v0 + sum) ^ ((v0 >> 5) + m_key[3]);
v0 -= ((v1 << 4) + m_key[0]) ^ (v1 + sum) ^ ((v1 >> 5) + m_key[1]);
sum -= MAGIC;
}
*data++ = v0;
*data++ = v1;
}
}

40
block/tea.hpp Normal file
View File

@ -0,0 +1,40 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#ifndef CRUFT_CRYPTO_BLOCK_TEA_HPP
#define CRUFT_CRYPTO_BLOCK_TEA_HPP
#include <array>
#include <cstdint>
#include <cstddef>
namespace cruft::crypto::block {
// http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm
class TEA {
public:
using key_t = std::array<uint32_t,4>;
explicit TEA (key_t);
void encrypt (uint32_t *restrict data, size_t count);
void decrypt (uint32_t *restrict data, size_t count);
private:
key_t m_key;
};
}
#endif

84
block/xtea.cpp Normal file
View File

@ -0,0 +1,84 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#include "xtea.hpp"
using cruft::crypto::block::XTEA;
///////////////////////////////////////////////////////////////////////////////
static const uint32_t MAGIC = 0x9E3779B9;
// each iteration performs two feistel rounds, for a total of 64
static const unsigned ITERATIONS = 32;
///////////////////////////////////////////////////////////////////////////////
XTEA::XTEA (key_t _key):
m_key (_key)
{ }
//-----------------------------------------------------------------------------
void
XTEA::encrypt (uint32_t *restrict data, size_t count)
{
if (count % 2)
throw std::invalid_argument ("XTEA requires even data count");
auto last = data + count;
while (data < last) {
uint32_t sum = 0;
uint32_t v0 = data[0];
uint32_t v1 = data[1];
for (unsigned i = 0; i < ITERATIONS; ++i) {
v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + m_key[sum & 3]);
sum += MAGIC;
v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + m_key[(sum >> 11) & 3]);
}
*data++ = v0;
*data++ = v1;
}
}
//-----------------------------------------------------------------------------
void
XTEA::decrypt (uint32_t *restrict data, size_t count)
{
if (count % 2)
throw std::invalid_argument ("XTEA requires even data count");
auto last = data + count;
while (data < last) {
uint32_t sum = ITERATIONS * MAGIC;
uint32_t v0 = data[0];
uint32_t v1 = data[1];
for (unsigned i = 0; i < ITERATIONS; ++i) {
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + m_key[(sum >> 11) & 3]);
sum -= MAGIC;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + m_key[sum & 3]);
}
*data++ = v0;
*data++ = v1;
}
}

40
block/xtea.hpp Normal file
View File

@ -0,0 +1,40 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#ifndef CRUFT_CRYPTO_BLOCK_XTEA_HPP
#define CRUFT_CRYPTO_BLOCK_XTEA_HPP
#include <array>
#include <cstdint>
#include <cstddef>
namespace cruft::crypto::block {
// http://en.wikipedia.org/wiki/XTEA
class XTEA {
public:
using key_t = std::array<uint32_t,4>;
explicit XTEA (key_t);
void encrypt (uint32_t *restrict data, size_t count);
void decrypt (uint32_t *restrict data, size_t count);
private:
key_t m_key;
};
}
#endif

106
block/xxtea.cpp Normal file
View File

@ -0,0 +1,106 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#include "xxtea.hpp"
#include <cstring>
// test vectors: http://www.cix.co.uk/~klockstone/teavect.htm
using cruft::crypto::block::XXTEA;
//-----------------------------------------------------------------------------
static const uint32_t MAGIC = 0x9E3779B9;
//-----------------------------------------------------------------------------
static constexpr
uint32_t
mix (uint32_t Z,
uint32_t Y,
uint32_t S,
size_t E,
size_t P,
const uint32_t *restrict K)
{
return ((Z >> 5 ^ Y << 2) + (Y >> 3 ^ Z << 4)) ^ ((S ^ Y) + (K[(P & 3) ^ E] ^ Z));
}
//-----------------------------------------------------------------------------
XXTEA::XXTEA (key_t _key):
m_key (_key)
{ ; }
//-----------------------------------------------------------------------------
void
XXTEA::encrypt (uint32_t *restrict data, size_t count)
{
if (count < 2)
throw std::invalid_argument ("minimum blocksize is 64 bits");
uint32_t sum = 0;
uint32_t z = data[count - 1];
uint32_t y, p;
unsigned rounds = 6 + 52 / count;
do {
sum += MAGIC;
uint32_t e = (sum >> 2) & 3;
for (p = 0; p < count - 1; p++) {
y = data[p + 1];
z = data[p] += mix (z, y, sum, e, p, m_key.data ());
}
y = data[0];
z = data[count - 1] += mix (z, y, sum, e, p, m_key.data ());
} while (--rounds);
}
//-----------------------------------------------------------------------------
void
XXTEA::decrypt (uint32_t *restrict data, size_t count)
{
if (count < 2)
throw std::invalid_argument ("minimum blocksize is 64 bits");
uint32_t y, z, sum;
uint32_t rounds;
size_t p;
rounds = 6 + 52 / count;
sum = rounds * MAGIC;
y = data[0];
do {
uint32_t e = (sum >> 2) & 3;
for (p = count - 1; p > 0; p--) {
z = data[p - 1];
y = data[p ] -= mix (z, y, sum, e, p, m_key.data ());
}
z = data[count - 1];
y = data[ 0] -= mix (z, y, sum, e, p, m_key.data ());
sum -= MAGIC;
} while (--rounds);
}

42
block/xxtea.hpp Normal file
View File

@ -0,0 +1,42 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#ifndef CRUFT_CRYPTO_BLOCKXXTEA_HPP
#define CRUFT_CRYPTO_BLOCKXXTEA_HPP
#include <array>
#include <cstdint>
#include <cstddef>
namespace cruft::crypto::block {
// http://en.wikipedia.org/wiki/XXTEA
// 'corrected' block TEA
class XXTEA {
public:
using key_t = std::array<uint32_t,4>;
explicit XXTEA (key_t);
void encrypt (uint32_t *restrict data, size_t count);
void decrypt (uint32_t *restrict data, size_t count);
private:
key_t m_key;
};
}
#endif

0
fwd.hpp Normal file
View File

20
hash/hmac.cpp Normal file
View File

@ -0,0 +1,20 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#include "hmac.hpp"
using cruft::crypto::hash::HMAC;

89
hash/hmac.hpp Normal file
View File

@ -0,0 +1,89 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#ifndef CRUFT_CRYPTO_HASH_HMAC_HPP
#define CRUFT_CRYPTO_HASH_HMAC_HPP
#include <cruft/util/debug.hpp>
#include <cruft/util/view.hpp>
#include <algorithm>
#include <utility>
namespace cruft::crypto::hash {
template <class HashT>
/// RFC 2104 key-hashing for message authentication
class HMAC {
public:
using digest_t = typename HashT::digest_t;
//---------------------------------------------------------------------
HMAC (util::view<const std::uint8_t*> key)
{
CHECK (!key.empty ());
static_assert (sizeof (m_ikey) == sizeof (m_okey), "key padding must match");
// If the key is larger than the blocklength, use the hash of the key
if (key.size () > HashT::BLOCK_SIZE) {
auto d = HashT{} (key);
auto tail = std::copy (d.begin (), d.end (), m_ikey.begin ());
std::fill (tail, std::end (m_ikey), 0);
// Use the key directly
} else {
auto tail = std::copy (key.begin (), key.end (), m_ikey.begin ());
std::fill (tail, m_ikey.end (), 0);
}
// copy and xor the key data to the okey
std::transform (
std::begin (m_ikey),
std::end (m_ikey),
std::begin (m_okey),
[] (auto v) { return v ^ OFILL; });
// just xor the ikey in place
std::transform (
m_ikey.begin (),
m_ikey.end (),
m_ikey.begin (),
[] (auto v) { return v ^ IFILL; });
}
//---------------------------------------------------------------------
template <typename ...DataT>
digest_t
operator() (DataT&&...data) const noexcept
{
HashT h;
return h (m_okey, h (m_ikey, std::forward<DataT> (data)...));
};
private:
//---------------------------------------------------------------------
static constexpr uint8_t IFILL = 0x36;
static constexpr uint8_t OFILL = 0x5C;
std::array<uint8_t,HashT::BLOCK_SIZE> m_ikey;
std::array<uint8_t,HashT::BLOCK_SIZE> m_okey;
};
}
#endif

65
hash/hotp.cpp Normal file
View File

@ -0,0 +1,65 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015-2018 Danny Robson <danny@nerdcruft.net>
*/
#include "hotp.hpp"
#include <cruft/util/endian.hpp>
#include <cstring>
using cruft::crypto::hash::HOTP;
///////////////////////////////////////////////////////////////////////////////
HOTP::HOTP (util::view<const char*> _key, uint64_t _counter):
m_counter (_counter),
m_hash (_key.template cast<const uint8_t> ())
{ ; }
//-----------------------------------------------------------------------------
unsigned
HOTP::value (void)
{
union {
uint64_t number;
uint8_t bytes[8];
};
number = util::htob (m_counter);
auto res = truncate (m_hash (util::make_cview (bytes)));
++m_counter;
return res % 1'000'000;
}
//-----------------------------------------------------------------------------
uint32_t
HOTP::truncate (SHA1::digest_t d)
{
// offset into the digest by the last 4 bits
size_t o= d[d.size () - 1] & 0x0F;
// mask the highest bit per the specification
uint32_t v = (d[o + 0] & 0x7f) << 24 |
(d[o + 1] & 0xff) << 16 |
(d[o + 2] & 0xff) << 8 |
(d[o + 3] & 0xff) << 0;
return v;
}

44
hash/hotp.hpp Normal file
View File

@ -0,0 +1,44 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015-2018 Danny Robson <danny@nerdcruft.net>
*/
#ifndef CRUFT_CRYPTO_HASH_HOTP_HPP
#define CRUFT_CRYPTO_HASH_HOTP_HPP
#include <cruft/util/view.hpp>
#include "hmac.hpp"
#include "sha1.hpp"
#include <cstdint>
namespace cruft::crypto::hash {
/// HMAC one-time password (RFC 4226)
class HOTP {
public:
HOTP (util::view<const char*> key, uint64_t counter);
unsigned value (void);
uint64_t counter (void) const;
private:
uint32_t truncate (SHA1::digest_t);
uint64_t m_counter;
HMAC<SHA1> m_hash;
};
}
#endif

123
hash/md2.cpp Normal file
View File

@ -0,0 +1,123 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2013 Danny Robson <danny@nerdcruft.net>
*/
#include "md2.hpp"
#include <cruft/util/debug.hpp>
#include <cruft/util/types.hpp>
#include <array>
#include <algorithm>
#include <cstring>
///////////////////////////////////////////////////////////////////////////////
using cruft::crypto::hash::MD2;
///////////////////////////////////////////////////////////////////////////////
static constexpr std::array<uint8_t,256> S = { {
41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, 19,
98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, 76, 130, 202,
30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, 138, 23, 229, 18,
190, 78, 196, 214, 218, 158, 222, 73, 160, 251, 245, 142, 187, 47, 238, 122,
169, 104, 121, 145, 21, 178, 7, 63, 148, 194, 16, 137, 11, 34, 95, 33,
128, 127, 93, 154, 90, 144, 50, 39, 53, 62, 204, 231, 191, 247, 151, 3,
255, 25, 48, 179, 72, 165, 181, 209, 215, 94, 146, 42, 172, 86, 170, 198,
79, 184, 56, 210, 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241,
69, 157, 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2,
27, 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, 234, 38,
44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, 129, 77, 82,
106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, 8, 12, 189, 177, 74,
120, 136, 149, 139, 227, 99, 232, 109, 233, 203, 213, 254, 59, 0, 29, 57,
242, 239, 183, 14, 102, 88, 208, 228, 166, 119, 114, 248, 235, 117, 75, 10,
49, 68, 80, 180, 143, 237, 31, 26, 219, 153, 141, 51, 159, 17, 131, 20,
} };
//-----------------------------------------------------------------------------
static const size_t M_OFFSET = 16;
static const size_t M_LENGTH = 16;
///////////////////////////////////////////////////////////////////////////////
static void
transform (std::array<uint8_t,16> &C, std::array<uint8_t,48> &X) noexcept
{
util::view M { X.data () + M_OFFSET, M_LENGTH };
// Update the checksum.
// XXX: I can't see why we need the xor-assign from the spec, but it's the
// only change keeping us from conforming to the test-cases. Pulled from a
// review of the reference implementation.
uint8_t L = C[15];
for (size_t i = 0; i < std::size (C); ++i)
L = C[i] ^= S[M[i] ^ L];
// Setup the blocks
for (size_t i = 0; i < 16; ++i)
X[32 + i] = X[16 + i] ^ X[i];
// Perform the processing rounds
for (size_t i = 0, t = 0; i < 18; ++i) {
for (size_t j = 0; j < 48; ++j)
t = X[j] ^= S[t];
t = (t + i) % 256;
}
}
///////////////////////////////////////////////////////////////////////////////
MD2::digest_t
MD2::operator() (const util::view<const uint8_t*> data) const noexcept
{
// zero initialise the state vectors, and create a simple window `M' into
// the middle of the `X' state vector.
std::array<uint8_t,16> C {};
std::array<uint8_t,48> X {};
const util::view M { std::begin (X) + M_OFFSET, M_LENGTH };
// process each complete block by copying to the window `M' and
// transforming X and C.
//
// leave the remainder of the data in `M' for subsequent padding.
auto remain = data;
while (remain.size () >= M_LENGTH) {
std::copy_n (std::begin (remain), M_LENGTH, std::begin (M));
transform (C, X);
remain = { remain.begin () + M_LENGTH, remain.end () };
};
// Copying the remaining data then append the padding bytes. Padding
// _must_ be performed even if we have an evenly divisible input buffer.
auto tail = std::copy (remain.begin (), remain.end (), std::begin (M));
auto unused = std::distance (tail, std::end (M));
std::fill (tail, std::end (M), unused);
transform (C, X);
// Append the checksum and transform once more.
std::copy (std::begin (C), std::end (C), std::begin (M));
transform (C, X);
// The final digest is the first `n' bytes of the state vector.
digest_t d;
std::copy_n (std::begin (X), d.size (), std::begin (d));
return d;
}

37
hash/md2.hpp Normal file
View File

@ -0,0 +1,37 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2013 Danny Robson <danny@nerdcruft.net>
*/
#ifndef CRUFT_CRYPTO_HASH_MD2_HPP
#define CRUFT_CRYPTO_HASH_MD2_HPP
#include <cruft/util/view.hpp>
#include <array>
#include <cstdint>
///////////////////////////////////////////////////////////////////////////////
namespace cruft::crypto::hash {
class MD2 {
public:
typedef std::array<uint8_t,16> digest_t;
public:
digest_t operator() (util::view<const uint8_t*>) const noexcept;
};
}
#endif

227
hash/md4.cpp Normal file
View File

@ -0,0 +1,227 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2013 Danny Robson <danny@nerdcruft.net>
*/
#include "md4.hpp"
#include <cruft/util/bitwise.hpp>
#include <cruft/util/debug.hpp>
#include <cstring>
using cruft::crypto::hash::MD4;
///////////////////////////////////////////////////////////////////////////////
// Auxiliary functions for each set of rounds
static inline constexpr
uint32_t
F (uint32_t X, uint32_t Y, uint32_t Z)
{
return (X & Y) | (~X & Z);
}
//-----------------------------------------------------------------------------
static inline constexpr
uint32_t
G (uint32_t X, uint32_t Y, uint32_t Z)
{
return (X & Y) | (X & Z) | (Y & Z);
}
//-----------------------------------------------------------------------------
static inline constexpr
uint32_t
H (uint32_t X, uint32_t Y, uint32_t Z)
{
return X ^ Y ^ Z;
}
//-----------------------------------------------------------------------------
static constexpr uint32_t INITIAL_A = 0x67452301;
static constexpr uint32_t INITIAL_B = 0xefcdab89;
static constexpr uint32_t INITIAL_C = 0x98badcfe;
static constexpr uint32_t INITIAL_D = 0x10325476;
///////////////////////////////////////////////////////////////////////////////
static void
transform (std::array<uint32_t,4> &ABCD, const std::array<uint32_t,16> &X) noexcept
{
uint32_t A = ABCD[0],
B = ABCD[1],
C = ABCD[2],
D = ABCD[3];
#define ROUND1(a,b,c,d,k,s) do { \
(a) += F((b), (c), (d)) + X[k]; \
(a) = util::rotatel ((a), (s)); \
} while (0)
ROUND1(A,B,C,D, 0, 3);
ROUND1(D,A,B,C, 1, 7);
ROUND1(C,D,A,B, 2, 11);
ROUND1(B,C,D,A, 3, 19);
ROUND1(A,B,C,D, 4, 3);
ROUND1(D,A,B,C, 5, 7);
ROUND1(C,D,A,B, 6, 11);
ROUND1(B,C,D,A, 7, 19);
ROUND1(A,B,C,D, 8, 3);
ROUND1(D,A,B,C, 9, 7);
ROUND1(C,D,A,B, 10, 11);
ROUND1(B,C,D,A, 11, 19);
ROUND1(A,B,C,D, 12, 3);
ROUND1(D,A,B,C, 13, 7);
ROUND1(C,D,A,B, 14, 11);
ROUND1(B,C,D,A, 15, 19);
#define ROUND2(a,b,c,d,k,s) do { \
(a) += G((b),(c),(d)) + X[k] + 0x5A827999u; \
(a) = util::rotatel ((a), (s)); \
} while (0)
ROUND2(A,B,C,D, 0, 3);
ROUND2(D,A,B,C, 4, 5);
ROUND2(C,D,A,B, 8, 9);
ROUND2(B,C,D,A, 12, 13);
ROUND2(A,B,C,D, 1, 3);
ROUND2(D,A,B,C, 5, 5);
ROUND2(C,D,A,B, 9, 9);
ROUND2(B,C,D,A, 13, 13);
ROUND2(A,B,C,D, 2, 3);
ROUND2(D,A,B,C, 6, 5);
ROUND2(C,D,A,B, 10, 9);
ROUND2(B,C,D,A, 14, 13);
ROUND2(A,B,C,D, 3, 3);
ROUND2(D,A,B,C, 7, 5);
ROUND2(C,D,A,B, 11, 9);
ROUND2(B,C,D,A, 15, 13);
#define ROUND3(a,b,c,d,k,s) do { \
(a) += H((b),(c),(d)) + X[k] + 0x6ED9EBA1u; \
(a) = util::rotatel ((a), (s)); \
} while (0)
ROUND3(A,B,C,D, 0, 3);
ROUND3(D,A,B,C, 8, 9);
ROUND3(C,D,A,B, 4, 11);
ROUND3(B,C,D,A, 12, 15);
ROUND3(A,B,C,D, 2, 3);
ROUND3(D,A,B,C, 10, 9);
ROUND3(C,D,A,B, 6, 11);
ROUND3(B,C,D,A, 14, 15);
ROUND3(A,B,C,D, 1, 3);
ROUND3(D,A,B,C, 9, 9);
ROUND3(C,D,A,B, 5, 11);
ROUND3(B,C,D,A, 13, 15);
ROUND3(A,B,C,D, 3, 3);
ROUND3(D,A,B,C, 11, 9);
ROUND3(C,D,A,B, 7, 11);
ROUND3(B,C,D,A, 15, 15);
ABCD[0] += A;
ABCD[1] += B;
ABCD[2] += C;
ABCD[3] += D;
}
///////////////////////////////////////////////////////////////////////////////
MD4::digest_t
MD4::operator() (util::view<const uint8_t*> data) noexcept
{
/* RESET */
uint64_t total = 0;
std::array<uint32_t,4> ABCD {
INITIAL_A,
INITIAL_B,
INITIAL_C,
INITIAL_D,
};
union {
std::array<uint32_t,16> X;
std::array<uint8_t, 64> Xb;
};
static_assert (sizeof (X) == sizeof (Xb));
static_assert (sizeof (ABCD) == sizeof (digest_t));
std::fill (std::begin (X), std::end (X), 0);
/* UPDATE */
{
auto remain = data;
while (remain.size () >= sizeof (Xb)) {
std::copy_n (std::begin (remain), sizeof (Xb), std::begin (Xb));
transform (ABCD, X);
remain = { remain.begin () + sizeof (Xb), remain.end () };
total += sizeof (Xb);
}
std::copy (std::begin (remain), std::end (remain), std::begin (Xb));
total += remain.size ();
}
uint64_t bits = total * 8;
/* FINISH */
{
// Pad with the mandatory 1 bit
size_t offset = total % sizeof (Xb);
Xb[offset] = 0x80;
}
{
// Pad the remainder with 0's, until 56 bytes
size_t offset = (total + 1) % sizeof (Xb);
size_t remain = (56 - offset % sizeof (Xb)) % sizeof (Xb);
if (offset > 56) {
std::fill_n (std::begin (Xb) + offset, sizeof (Xb) - offset, 0);
transform (ABCD, X);
remain -= sizeof (Xb) - offset;
offset = 0;
}
std::fill (std::begin (Xb) + offset, std::end (Xb), 0);
// Put in the length (in bits) least significant first
for (size_t i = 0; i < sizeof (bits); ++i) {
Xb[56 + i] = bits & 0xFF;
bits >>= 8;
}
transform (ABCD, X);
}
/* DIGEEST */
digest_t d;
memcpy (d.data (), ABCD.data(), sizeof (ABCD));
return d;
}

36
hash/md4.hpp Normal file
View File

@ -0,0 +1,36 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2013 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_HASH_MD4_HPP
#define __UTIL_HASH_MD4_HPP
#include <cruft/util/view.hpp>
#include <array>
#include <cstdint>
///////////////////////////////////////////////////////////////////////////////
namespace cruft::crypto::hash {
class MD4 {
public:
using digest_t = std::array<uint8_t,16>;
digest_t operator() (util::view<const uint8_t*>) noexcept;
};
}
#endif

300
hash/md5.cpp Normal file
View File

@ -0,0 +1,300 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2013 Danny Robson <danny@nerdcruft.net>
*/
#include "md5.hpp"
#include <cruft/util/iterator.hpp>
#include <cruft/util/bitwise.hpp>
#include <cruft/util/debug.hpp>
#include <cstring>
using cruft::crypto::hash::MD5;
///////////////////////////////////////////////////////////////////////////////
// Per-round mixing functions
static constexpr
uint32_t
F (uint32_t x, uint32_t y, uint32_t z)
{
return z ^ (x & (y ^ z));
}
//-----------------------------------------------------------------------------
static constexpr
uint32_t
G (uint32_t x, uint32_t y, uint32_t z)
{
return F (z, x, y);
}
//-----------------------------------------------------------------------------
static constexpr
uint32_t
H (uint32_t x, uint32_t y, uint32_t z)
{
return x ^ y ^ z;
}
//-----------------------------------------------------------------------------
static constexpr
uint32_t
I (uint32_t x, uint32_t y, uint32_t z)
{
return y ^ (x | ~z);
}
///////////////////////////////////////////////////////////////////////////////
// Mixing constants for all rounds. They are defined as 'abs(sin(i)) * max_uint32', but we use the
// literals to avoid any stupid maths issues during compilation.
const std::array<uint32_t, 65> T = { {
0x00000000,
// Round 1
0xd76aa478u, 0xe8c7b756u, 0x242070dbu, 0xc1bdceeeu,
0xf57c0fafu, 0x4787c62au, 0xa8304613u, 0xfd469501u,
0x698098d8u, 0x8b44f7afu, 0xffff5bb1u, 0x895cd7beu,
0x6b901122u, 0xfd987193u, 0xa679438eu, 0x49b40821u,
// Round 2
0xf61e2562u, 0xc040b340u, 0x265e5a51u, 0xe9b6c7aau,
0xd62f105du, 0x02441453u, 0xd8a1e681u, 0xe7d3fbc8u,
0x21e1cde6u, 0xc33707d6u, 0xf4d50d87u, 0x455a14edu,
0xa9e3e905u, 0xfcefa3f8u, 0x676f02d9u, 0x8d2a4c8au,
// Round 3
0xfffa3942u, 0x8771f681u, 0x6d9d6122u, 0xfde5380cu,
0xa4beea44u, 0x4bdecfa9u, 0xf6bb4b60u, 0xbebfbc70u,
0x289b7ec6u, 0xeaa127fau, 0xd4ef3085u, 0x04881d05u,
0xd9d4d039u, 0xe6db99e5u, 0x1fa27cf8u, 0xc4ac5665u,
// Round 4
0xf4292244u, 0x432aff97u, 0xab9423a7u, 0xfc93a039u,
0x655b59c3u, 0x8f0ccc92u, 0xffeff47du, 0x85845dd1u,
0x6fa87e4fu, 0xfe2ce6e0u, 0xa3014314u, 0x4e0811a1u,
0xf7537e82u, 0xbd3af235u, 0x2ad7d2bbu, 0xeb86d391u
} };
//-----------------------------------------------------------------------------
static constexpr uint32_t INITIAL_A = 0x67452301;
static constexpr uint32_t INITIAL_B = 0xefcdab89;
static constexpr uint32_t INITIAL_C = 0x98badcfe;
static constexpr uint32_t INITIAL_D = 0x10325476;
///////////////////////////////////////////////////////////////////////////////
typename MD5::digest_t
MD5::operator() (util::view<const uint8_t*> a) const noexcept
{
return (*this)(a, nullptr);
}
//-----------------------------------------------------------------------------
typename MD5::digest_t
MD5::operator() (util::view<const uint8_t*> a, util::view<const uint8_t*> b) const noexcept
{
return (*this)(a, b, nullptr);
}
///////////////////////////////////////////////////////////////////////////////
typename MD5::digest_t
MD5::operator() (
const util::view<const uint8_t*> data_a,
const util::view<const uint8_t*> data_b,
const util::view<const uint8_t*> data_c
) const noexcept {
union {
std::array<uint32_t,16> w;
std::array<uint8_t, 64> b;
} X;
static_assert (sizeof (X.w) == BLOCK_SIZE);
static_assert (X.w.size () == DIGEST_SIZE);
static_assert (sizeof (X.b) == BLOCK_SIZE);
static_assert (X.b.size () == BLOCK_SIZE);
static_assert ((void*)&X.w == (void*)&X.b);
uint64_t m_total = 0;
std::array<uint32_t,4> ABCD = {
INITIAL_A,
INITIAL_B,
INITIAL_C,
INITIAL_D
};
// note we pass in a windowed view of the state block, not the whole
// thing.
util::transform_by_block (
util::view {X.b},
[&,this] (auto) { ABCD = transform (ABCD, X.w); },
data_a, data_b, data_c
);
m_total = data_a.size () + data_b.size () + data_c.size ();
uint64_t bits = m_total * 8;
// Pad with the mandatory 1 bit
X.b[m_total % BLOCK_SIZE] = 0x80;
{
// Pad the remainder with 0's, until 56 bytes
size_t offset = (m_total + 1) % BLOCK_SIZE;
size_t remain = (56 - offset % BLOCK_SIZE) % BLOCK_SIZE;
if (offset > 56) {
std::fill (&X.b[offset], X.b.end (), 0);
ABCD = transform (ABCD, X.w);
remain -= sizeof (X.b) - offset;
offset = 0;
}
memset (&X.b[offset], 0, remain);
// Put in the length (in bits) least significant first
for (size_t i = 0; i < sizeof (bits); ++i) {
X.b[56 + i] = bits & 0xFF;
bits >>= 8;
}
ABCD = transform (ABCD, X.w);
}
digest_t d;
memcpy (d.data (), ABCD.data (), sizeof (ABCD));
return d;
};
///////////////////////////////////////////////////////////////////////////////
std::array<uint32_t,4>
MD5::transform (
const std::array<uint32_t,4> &ABCD,
const std::array<uint32_t,16> &X) const noexcept
{
uint32_t A = ABCD[0],
B = ABCD[1],
C = ABCD[2],
D = ABCD[3];
#define ROUNDx(a,b,c,d,k,s,i,f) do { \
(a) += (f)((b), (c), (d)) + X[k] + T[i]; \
(a) = util::rotatel ((a), (s)); \
(a) += (b); \
} while (0)
// Round 1
ROUNDx(A,B,C,D, 0, 7, 1, F);
ROUNDx(D,A,B,C, 1, 12, 2, F);
ROUNDx(C,D,A,B, 2, 17, 3, F);
ROUNDx(B,C,D,A, 3, 22, 4, F);
ROUNDx(A,B,C,D, 4, 7, 5, F);
ROUNDx(D,A,B,C, 5, 12, 6, F);
ROUNDx(C,D,A,B, 6, 17, 7, F);
ROUNDx(B,C,D,A, 7, 22, 8, F);
ROUNDx(A,B,C,D, 8, 7, 9, F);
ROUNDx(D,A,B,C, 9, 12, 10, F);
ROUNDx(C,D,A,B, 10, 17, 11, F);
ROUNDx(B,C,D,A, 11, 22, 12, F);
ROUNDx(A,B,C,D, 12, 7, 13, F);
ROUNDx(D,A,B,C, 13, 12, 14, F);
ROUNDx(C,D,A,B, 14, 17, 15, F);
ROUNDx(B,C,D,A, 15, 22, 16, F);
// Round 2
ROUNDx(A,B,C,D, 1, 5, 17, G);
ROUNDx(D,A,B,C, 6, 9, 18, G);
ROUNDx(C,D,A,B, 11, 14, 19, G);
ROUNDx(B,C,D,A, 0, 20, 20, G);
ROUNDx(A,B,C,D, 5, 5, 21, G);
ROUNDx(D,A,B,C, 10, 9, 22, G);
ROUNDx(C,D,A,B, 15, 14, 23, G);
ROUNDx(B,C,D,A, 4, 20, 24, G);
ROUNDx(A,B,C,D, 9, 5, 25, G);
ROUNDx(D,A,B,C, 14, 9, 26, G);
ROUNDx(C,D,A,B, 3, 14, 27, G);
ROUNDx(B,C,D,A, 8, 20, 28, G);
ROUNDx(A,B,C,D, 13, 5, 29, G);
ROUNDx(D,A,B,C, 2, 9, 30, G);
ROUNDx(C,D,A,B, 7, 14, 31, G);
ROUNDx(B,C,D,A, 12, 20, 32, G);
// Round 3
ROUNDx(A,B,C,D, 5, 4, 33, H);
ROUNDx(D,A,B,C, 8, 11, 34, H);
ROUNDx(C,D,A,B, 11, 16, 35, H);
ROUNDx(B,C,D,A, 14, 23, 36, H);
ROUNDx(A,B,C,D, 1, 4, 37, H);
ROUNDx(D,A,B,C, 4, 11, 38, H);
ROUNDx(C,D,A,B, 7, 16, 39, H);
ROUNDx(B,C,D,A, 10, 23, 40, H);
ROUNDx(A,B,C,D, 13, 4, 41, H);
ROUNDx(D,A,B,C, 0, 11, 42, H);
ROUNDx(C,D,A,B, 3, 16, 43, H);
ROUNDx(B,C,D,A, 6, 23, 44, H);
ROUNDx(A,B,C,D, 9, 4, 45, H);
ROUNDx(D,A,B,C, 12, 11, 46, H);
ROUNDx(C,D,A,B, 15, 16, 47, H);
ROUNDx(B,C,D,A, 2, 23, 48, H);
// Round 4
ROUNDx(A,B,C,D, 0, 6, 49, I);
ROUNDx(D,A,B,C, 7, 10, 50, I);
ROUNDx(C,D,A,B, 14, 15, 51, I);
ROUNDx(B,C,D,A, 5, 21, 52, I);
ROUNDx(A,B,C,D, 12, 6, 53, I);
ROUNDx(D,A,B,C, 3, 10, 54, I);
ROUNDx(C,D,A,B, 10, 15, 55, I);
ROUNDx(B,C,D,A, 1, 21, 56, I);
ROUNDx(A,B,C,D, 8, 6, 57, I);
ROUNDx(D,A,B,C, 15, 10, 58, I);
ROUNDx(C,D,A,B, 6, 15, 59, I);
ROUNDx(B,C,D,A, 13, 21, 60, I);
ROUNDx(A,B,C,D, 4, 6, 61, I);
ROUNDx(D,A,B,C, 11, 10, 62, I);
ROUNDx(C,D,A,B, 2, 15, 63, I);
ROUNDx(B,C,D,A, 9, 21, 64, I);
return {
ABCD[0] + A,
ABCD[1] + B,
ABCD[2] + C,
ABCD[3] + D,
};
}

49
hash/md5.hpp Normal file
View File

@ -0,0 +1,49 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2013-2018 Danny Robson <danny@nerdcruft.net>
*/
#ifndef CRUFT_CRYPTO_HASH_MD5_HPP
#define CRUFT_CRYPTO_HASH_MD5_HPP
#include <cruft/util/view.hpp>
#include <array>
#include <cstdint>
#include <cstdlib>
///////////////////////////////////////////////////////////////////////////////
namespace cruft::crypto::hash {
class MD5 {
public:
using digest_t = std::array<uint8_t,16>;
static const size_t BLOCK_SIZE = 64;
static const size_t DIGEST_SIZE = 16;
public:
digest_t operator() (util::view<const uint8_t*>) const noexcept;
digest_t operator() (util::view<const uint8_t*>,util::view<const uint8_t*>) const noexcept;
digest_t operator() (util::view<const uint8_t*>,util::view<const uint8_t*>,util::view<const uint8_t*>) const noexcept;
private:
std::array<uint32_t,4>
transform (
const std::array<uint32_t,4> &ABCD,
const std::array<uint32_t,16> &X
) const noexcept;
};
}
#endif

409
hash/ripemd.cpp Normal file
View File

@ -0,0 +1,409 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright:
* 2014-2018, Danny Robson <danny@nerdcruft.net>
*/
#include "ripemd.hpp"
#include <cruft/util/debug.hpp>
#include <cruft/util/bitwise.hpp>
#include <cstring>
using cruft::crypto::hash::RIPEMD;
///////////////////////////////////////////////////////////////////////////////
static constexpr
uint32_t
f1 (uint32_t x, uint32_t y, uint32_t z)
{
return x ^ y ^ z;
}
//-----------------------------------------------------------------------------
static constexpr
uint32_t
f2 (uint32_t x, uint32_t y, uint32_t z)
{
return (x & y) | (~x & z);
}
//-----------------------------------------------------------------------------
static constexpr
uint32_t
f3 (uint32_t x, uint32_t y, uint32_t z)
{
return (x | ~y) ^ z;
}
//-----------------------------------------------------------------------------
static constexpr
uint32_t
f4 (uint32_t x, uint32_t y, uint32_t z)
{
return (x & z) | (y & ~z);
}
//-----------------------------------------------------------------------------
static constexpr
uint32_t
f5 (uint32_t x, uint32_t y, uint32_t z)
{
return x ^ (y | ~z);
}
///////////////////////////////////////////////////////////////////////////////
static void
transform (uint32_t state[5], const uint32_t d32[16])
{
// Use: boolean function f
// state parameters a, b, c, d, e
// offset value o
// input data value x
// shift length s
#define ROUND(f,a,b,c,d,e,o,x,s) { \
a += f(b, c, d); \
a += d32[x] + o; \
a = util::rotatel (a, s); \
a += e; \
c = util::rotatel (c, 10); \
}
#define R1a(a,b,c,d,e,x,s) ROUND(f1,a,b,c,d,e,0x00000000u,x,s)
#define R2a(a,b,c,d,e,x,s) ROUND(f2,a,b,c,d,e,0x5A827999u,x,s)
#define R3a(a,b,c,d,e,x,s) ROUND(f3,a,b,c,d,e,0x6ED9EBA1u,x,s)
#define R4a(a,b,c,d,e,x,s) ROUND(f4,a,b,c,d,e,0x8F1BBCDCu,x,s)
#define R5a(a,b,c,d,e,x,s) ROUND(f5,a,b,c,d,e,0xA953FD4Eu,x,s)
#define R1b(a,b,c,d,e,x,s) ROUND(f5,a,b,c,d,e,0x50A28BE6u,x,s)
#define R2b(a,b,c,d,e,x,s) ROUND(f4,a,b,c,d,e,0x5C4DD124u,x,s)
#define R3b(a,b,c,d,e,x,s) ROUND(f3,a,b,c,d,e,0x6D703EF3u,x,s)
#define R4b(a,b,c,d,e,x,s) ROUND(f2,a,b,c,d,e,0x7A6D76E9u,x,s)
#define R5b(a,b,c,d,e,x,s) ROUND(f1,a,b,c,d,e,0x00000000u,x,s)
uint32_t a1, b1, c1, d1, e1;
uint32_t a2, b2, c2, d2, e2;
a1 = a2 = state[0];
b1 = b2 = state[1];
c1 = c2 = state[2];
d1 = d2 = state[3];
e1 = e2 = state[4];
// Left round 1
R1a(a1, b1, c1, d1, e1, 0, 11);
R1a(e1, a1, b1, c1, d1, 1, 14);
R1a(d1, e1, a1, b1, c1, 2, 15);
R1a(c1, d1, e1, a1, b1, 3, 12);
R1a(b1, c1, d1, e1, a1, 4, 5);
R1a(a1, b1, c1, d1, e1, 5, 8);
R1a(e1, a1, b1, c1, d1, 6, 7);
R1a(d1, e1, a1, b1, c1, 7, 9);
R1a(c1, d1, e1, a1, b1, 8, 11);
R1a(b1, c1, d1, e1, a1, 9, 13);
R1a(a1, b1, c1, d1, e1, 10, 14);
R1a(e1, a1, b1, c1, d1, 11, 15);
R1a(d1, e1, a1, b1, c1, 12, 6);
R1a(c1, d1, e1, a1, b1, 13, 7);
R1a(b1, c1, d1, e1, a1, 14, 9);
R1a(a1, b1, c1, d1, e1, 15, 8);
// Left round 2
R2a(e1, a1, b1, c1, d1, 7, 7);
R2a(d1, e1, a1, b1, c1, 4, 6);
R2a(c1, d1, e1, a1, b1, 13, 8);
R2a(b1, c1, d1, e1, a1, 1, 13);
R2a(a1, b1, c1, d1, e1, 10, 11);
R2a(e1, a1, b1, c1, d1, 6, 9);
R2a(d1, e1, a1, b1, c1, 15, 7);
R2a(c1, d1, e1, a1, b1, 3, 15);
R2a(b1, c1, d1, e1, a1, 12, 7);
R2a(a1, b1, c1, d1, e1, 0, 12);
R2a(e1, a1, b1, c1, d1, 9, 15);
R2a(d1, e1, a1, b1, c1, 5, 9);
R2a(c1, d1, e1, a1, b1, 2, 11);
R2a(b1, c1, d1, e1, a1, 14, 7);
R2a(a1, b1, c1, d1, e1, 11, 13);
R2a(e1, a1, b1, c1, d1, 8, 12);
// Left round 3
R3a(d1, e1, a1, b1, c1, 3, 11);
R3a(c1, d1, e1, a1, b1, 10, 13);
R3a(b1, c1, d1, e1, a1, 14, 6);
R3a(a1, b1, c1, d1, e1, 4, 7);
R3a(e1, a1, b1, c1, d1, 9, 14);
R3a(d1, e1, a1, b1, c1, 15, 9);
R3a(c1, d1, e1, a1, b1, 8, 13);
R3a(b1, c1, d1, e1, a1, 1, 15);
R3a(a1, b1, c1, d1, e1, 2, 14);
R3a(e1, a1, b1, c1, d1, 7, 8);
R3a(d1, e1, a1, b1, c1, 0, 13);
R3a(c1, d1, e1, a1, b1, 6, 6);
R3a(b1, c1, d1, e1, a1, 13, 5);
R3a(a1, b1, c1, d1, e1, 11, 12);
R3a(e1, a1, b1, c1, d1, 5, 7);
R3a(d1, e1, a1, b1, c1, 12, 5);
// Left round 4
R4a(c1, d1, e1, a1, b1, 1, 11);
R4a(b1, c1, d1, e1, a1, 9, 12);
R4a(a1, b1, c1, d1, e1, 11, 14);
R4a(e1, a1, b1, c1, d1, 10, 15);
R4a(d1, e1, a1, b1, c1, 0, 14);
R4a(c1, d1, e1, a1, b1, 8, 15);
R4a(b1, c1, d1, e1, a1, 12, 9);
R4a(a1, b1, c1, d1, e1, 4, 8);
R4a(e1, a1, b1, c1, d1, 13, 9);
R4a(d1, e1, a1, b1, c1, 3, 14);
R4a(c1, d1, e1, a1, b1, 7, 5);
R4a(b1, c1, d1, e1, a1, 15, 6);
R4a(a1, b1, c1, d1, e1, 14, 8);
R4a(e1, a1, b1, c1, d1, 5, 6);
R4a(d1, e1, a1, b1, c1, 6, 5);
R4a(c1, d1, e1, a1, b1, 2, 12);
// Left round 5
R5a(b1, c1, d1, e1, a1, 4, 9);
R5a(a1, b1, c1, d1, e1, 0, 15);
R5a(e1, a1, b1, c1, d1, 5, 5);
R5a(d1, e1, a1, b1, c1, 9, 11);
R5a(c1, d1, e1, a1, b1, 7, 6);
R5a(b1, c1, d1, e1, a1, 12, 8);
R5a(a1, b1, c1, d1, e1, 2, 13);
R5a(e1, a1, b1, c1, d1, 10, 12);
R5a(d1, e1, a1, b1, c1, 14, 5);
R5a(c1, d1, e1, a1, b1, 1, 12);
R5a(b1, c1, d1, e1, a1, 3, 13);
R5a(a1, b1, c1, d1, e1, 8, 14);
R5a(e1, a1, b1, c1, d1, 11, 11);
R5a(d1, e1, a1, b1, c1, 6, 8);
R5a(c1, d1, e1, a1, b1, 15, 5);
R5a(b1, c1, d1, e1, a1, 13, 6);
// Right round 1
R1b(a2, b2, c2, d2, e2, 5, 8);
R1b(e2, a2, b2, c2, d2, 14, 9);
R1b(d2, e2, a2, b2, c2, 7, 9);
R1b(c2, d2, e2, a2, b2, 0, 11);
R1b(b2, c2, d2, e2, a2, 9, 13);
R1b(a2, b2, c2, d2, e2, 2, 15);
R1b(e2, a2, b2, c2, d2, 11, 15);
R1b(d2, e2, a2, b2, c2, 4, 5);
R1b(c2, d2, e2, a2, b2, 13, 7);
R1b(b2, c2, d2, e2, a2, 6, 7);
R1b(a2, b2, c2, d2, e2, 15, 8);
R1b(e2, a2, b2, c2, d2, 8, 11);
R1b(d2, e2, a2, b2, c2, 1, 14);
R1b(c2, d2, e2, a2, b2, 10, 14);
R1b(b2, c2, d2, e2, a2, 3, 12);
R1b(a2, b2, c2, d2, e2, 12, 6);
// Right round 2
R2b(e2, a2, b2, c2, d2, 6, 9);
R2b(d2, e2, a2, b2, c2, 11, 13);
R2b(c2, d2, e2, a2, b2, 3, 15);
R2b(b2, c2, d2, e2, a2, 7, 7);
R2b(a2, b2, c2, d2, e2, 0, 12);
R2b(e2, a2, b2, c2, d2, 13, 8);
R2b(d2, e2, a2, b2, c2, 5, 9);
R2b(c2, d2, e2, a2, b2, 10, 11);
R2b(b2, c2, d2, e2, a2, 14, 7);
R2b(a2, b2, c2, d2, e2, 15, 7);
R2b(e2, a2, b2, c2, d2, 8, 12);
R2b(d2, e2, a2, b2, c2, 12, 7);
R2b(c2, d2, e2, a2, b2, 4, 6);
R2b(b2, c2, d2, e2, a2, 9, 15);
R2b(a2, b2, c2, d2, e2, 1, 13);
R2b(e2, a2, b2, c2, d2, 2, 11);
// Right round 3
R3b(d2, e2, a2, b2, c2, 15, 9);
R3b(c2, d2, e2, a2, b2, 5, 7);
R3b(b2, c2, d2, e2, a2, 1, 15);
R3b(a2, b2, c2, d2, e2, 3, 11);
R3b(e2, a2, b2, c2, d2, 7, 8);
R3b(d2, e2, a2, b2, c2, 14, 6);
R3b(c2, d2, e2, a2, b2, 6, 6);
R3b(b2, c2, d2, e2, a2, 9, 14);
R3b(a2, b2, c2, d2, e2, 11, 12);
R3b(e2, a2, b2, c2, d2, 8, 13);
R3b(d2, e2, a2, b2, c2, 12, 5);
R3b(c2, d2, e2, a2, b2, 2, 14);
R3b(b2, c2, d2, e2, a2, 10, 13);
R3b(a2, b2, c2, d2, e2, 0, 13);
R3b(e2, a2, b2, c2, d2, 4, 7);
R3b(d2, e2, a2, b2, c2, 13, 5);
// Right round 4
R4b(c2, d2, e2, a2, b2, 8, 15);
R4b(b2, c2, d2, e2, a2, 6, 5);
R4b(a2, b2, c2, d2, e2, 4, 8);
R4b(e2, a2, b2, c2, d2, 1, 11);
R4b(d2, e2, a2, b2, c2, 3, 14);
R4b(c2, d2, e2, a2, b2, 11, 14);
R4b(b2, c2, d2, e2, a2, 15, 6);
R4b(a2, b2, c2, d2, e2, 0, 14);
R4b(e2, a2, b2, c2, d2, 5, 6);
R4b(d2, e2, a2, b2, c2, 12, 9);
R4b(c2, d2, e2, a2, b2, 2, 12);
R4b(b2, c2, d2, e2, a2, 13, 9);
R4b(a2, b2, c2, d2, e2, 9, 12);
R4b(e2, a2, b2, c2, d2, 7, 5);
R4b(d2, e2, a2, b2, c2, 10, 15);
R4b(c2, d2, e2, a2, b2, 14, 8);
// Right round 5
R5b(b2, c2, d2, e2, a2, 12 , 8);
R5b(a2, b2, c2, d2, e2, 15 , 5);
R5b(e2, a2, b2, c2, d2, 10 , 12);
R5b(d2, e2, a2, b2, c2, 4 , 9);
R5b(c2, d2, e2, a2, b2, 1 , 12);
R5b(b2, c2, d2, e2, a2, 5 , 5);
R5b(a2, b2, c2, d2, e2, 8 , 14);
R5b(e2, a2, b2, c2, d2, 7 , 6);
R5b(d2, e2, a2, b2, c2, 6 , 8);
R5b(c2, d2, e2, a2, b2, 2 , 13);
R5b(b2, c2, d2, e2, a2, 13 , 6);
R5b(a2, b2, c2, d2, e2, 14 , 5);
R5b(e2, a2, b2, c2, d2, 0 , 15);
R5b(d2, e2, a2, b2, c2, 3 , 13);
R5b(c2, d2, e2, a2, b2, 9 , 11);
R5b(b2, c2, d2, e2, a2, 11 , 11);
// Finalise state
d2 = state[1] + c1 + d2;
state[1] = state[2] + d1 + e2;
state[2] = state[3] + e1 + a2;
state[3] = state[4] + a1 + b2;
state[4] = state[0] + b1 + c2;
state[0] = d2;
}
///////////////////////////////////////////////////////////////////////////////
RIPEMD::digest_t
RIPEMD::operator() (const util::view<const uint8_t*> data)
{
struct {
union {
uint32_t d32[16];
uint8_t d08[64];
};
size_t size;
} m_buffer;
/* INIT */
uint32_t m_state[5] {
0x67452301u,
0xEFCDAB89u,
0x98BADCFEu,
0x10325476u,
0xC3D2E1F0u,
};
uint64_t m_length = 0;
m_buffer.size = 0;
/* UPDATE */
{
auto len = data.size ();
auto base = data.begin ();
size_t cursor = 0;
while (cursor < len) {
size_t width = sizeof (m_buffer.d08) - m_buffer.size;
size_t chunk = util::min (width, len - cursor);
memcpy (m_buffer.d08 + m_buffer.size, base + cursor, chunk);
m_length += chunk;
m_buffer.size += chunk;
if (m_buffer.size == sizeof (m_buffer.d08)) {
transform (m_state, m_buffer.d32);
m_buffer.size = 0;
}
cursor += chunk;
}
if (m_length >> sizeof (m_length) * 8 - 3 != 0)
panic ("exceeded maximum message length");
}
/* FINISH */
{
// Ensure the length wouldn't overflow if converted to bits. We need to
// grab this before there's a chance it gets overwritten.
CHECK_EQ (m_length >> sizeof(m_length) * 8 - 3, 0u);
uint64_t length = m_length * 8;
// Push a padding byte into the buffer
uint8_t padding = 0x80;
assert (m_buffer.size != sizeof (m_buffer.d08));
m_buffer.d08[m_buffer.size] = padding;
m_buffer.size++;
m_length++;
if (m_buffer.size == sizeof (m_buffer.d08)) {
transform (m_state, m_buffer.d32);
m_buffer.size = 0;
}
// Pad out the line if we couldn't fit a length at the end
size_t remaining = sizeof (m_buffer.d32) - m_buffer.size;
if (remaining < 8) {
std::fill_n (m_buffer.d08 + m_buffer.size, remaining, 0);
m_buffer.size += remaining;
transform (m_state, m_buffer.d32);
m_buffer.size = 0;
m_length += remaining;
CHECK_EQ (m_buffer.size, 0u);
remaining = sizeof (m_buffer.d08);
}
// Write the length to the end of the buffer
union {
uint32_t d32[16];
uint8_t d08[64];
};
std::fill (std::begin (d32), std::end (d32), 0);
d32[14] = length & 0xFFFFFFFF;
d32[15] = length >> 32u;
// Do the final update
size_t offset = sizeof(d08) - remaining;
std::copy_n (d08 + offset, remaining, m_buffer.d08 + offset);
m_length += remaining;
m_buffer.size += remaining;
transform (m_state, m_buffer.d32);
m_buffer.size = 0;
}
/* DIGEST */
digest_t d;
memcpy (d.data (), m_state, sizeof (m_state));
return d;
}

36
hash/ripemd.hpp Normal file
View File

@ -0,0 +1,36 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright:
* 2014-2018, Danny Robson <danny@nerdcruft.net>
*/
#ifndef CRUFT_CRYPTO_HASH_RIPEMD_HPP
#define CRUFT_CRYPTO_HASH_RIPEMD_HPP
#include <cruft/util/view.hpp>
#include <array>
///////////////////////////////////////////////////////////////////////////////
namespace cruft::crypto::hash {
class RIPEMD {
public:
typedef std::array<uint8_t,20> digest_t;
digest_t operator() (util::view<const uint8_t*>);
};
}
#endif

217
hash/sha1.cpp Normal file
View File

@ -0,0 +1,217 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2013 Danny Robson <danny@nerdcruft.net>
*/
#include "sha1.hpp"
#include <cruft/util/iterator.hpp>
#include <cruft/util/bitwise.hpp>
#include <cruft/util/debug.hpp>
#include <cruft/util/endian.hpp>
#include <cruft/util/cast.hpp>
#include <algorithm>
#include <cstdint>
#include <limits>
using cruft::crypto::hash::SHA1;
///////////////////////////////////////////////////////////////////////////////
// Constant words for sequence of rounds
static constexpr uint32_t K_00 = 0x5A827999;
static constexpr uint32_t K_20 = 0x6ED9EBA1;
static constexpr uint32_t K_40 = 0x8F1BBCDC;
static constexpr uint32_t K_60 = 0xCA62C1D6;
//-----------------------------------------------------------------------------
static constexpr
std::array<uint32_t,5> INITIAL_H = {
0x67452301,
0xEFCDAB89,
0x98BADCFE,
0x10325476,
0xC3D2E1F0
};
//-----------------------------------------------------------------------------
static constexpr size_t BLOCK_WORDS = 16;
static constexpr size_t BLOCK_BYTES = BLOCK_WORDS * sizeof (uint32_t);
///////////////////////////////////////////////////////////////////////////////
// Logical function for sequence of rounds
static constexpr
uint32_t
f_00 (uint32_t B, uint32_t C, uint32_t D)
{
return (B & C) | (~B & D);
}
//-----------------------------------------------------------------------------
static constexpr
uint32_t
f_20 (uint32_t B, uint32_t C, uint32_t D)
{
return B ^ C ^ D;
}
//-----------------------------------------------------------------------------
static constexpr
uint32_t
f_40 (uint32_t B, uint32_t C, uint32_t D)
{
return (B & C) | (B & D) | (C & D);
}
//-----------------------------------------------------------------------------
static constexpr
uint32_t
f_60 (uint32_t B, uint32_t C, uint32_t D)
{
return B ^ C ^ D;
}
///////////////////////////////////////////////////////////////////////////////
static void
process (std::array<uint32_t,5> &H, std::array<uint32_t,16+64> &W)
{
// Byteswap the raw input we have buffered ready for arithmetic
std::transform (std::begin (W),
std::end (W),
std::begin (W),
[] (uint32_t x) {
return util::ntoh (x);
});
// Initialise the work buffer and the state variables
for (size_t t = 16; t < 80; ++t)
W[t] = util::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 = util::rotatel (A, 5) + f_##i (B, C, D) + E + W[t] + K_##i; \
E = D; \
D = C; \
C = util::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);
// Update the resulting hash state
H[0] += A;
H[1] += B;
H[2] += C;
H[3] += D;
H[4] += E;
}
///////////////////////////////////////////////////////////////////////////////
SHA1::digest_t
SHA1::operator() (util::view<const uint8_t*> data) noexcept
{
return (*this) (data, nullptr);
}
//-----------------------------------------------------------------------------
SHA1::digest_t
SHA1::operator() (
util::view<const uint8_t*> data_a,
util::view<const uint8_t*> data_b
) noexcept {
/* RESET */
uint64_t total = 0;
union {
std::array<uint32_t,5> w;
std::array<uint8_t,20> b;
} H;
union {
std::array<uint8_t, 16*4+64*4> c;
std::array<uint32_t, 16 +64 > W;
} state;
H.w = INITIAL_H;
/* UPDATE */
transform_by_block (
util::view {state.c.data (), BLOCK_BYTES },
[&] (auto) { process (H.w, state.W); },
data_a, data_b
);
total += data_a.size () + data_b.size ();
/* FINISH */
{
size_t offset = total % BLOCK_BYTES;
size_t used = total * 8;
// Append a single one bit
state.c[offset++] = 0x80;
total += 1;
// Zero fill if we can't append length
size_t chunk = BLOCK_BYTES - offset;
if (chunk < sizeof (total)) {
std::fill_n (std::begin (state.c) + offset, chunk, 0);
total += chunk;
process (H.w, state.W);
chunk = BLOCK_BYTES;
offset = 0;
}
// Zero fill and append total length
std::fill_n (std::begin (state.c) + offset, chunk - sizeof (total), 0);
state.c[BLOCK_BYTES - 1] = used & 0xFF; used >>= 8;
state.c[BLOCK_BYTES - 2] = used & 0xFF; used >>= 8;
state.c[BLOCK_BYTES - 3] = used & 0xFF; used >>= 8;
state.c[BLOCK_BYTES - 4] = used & 0xFF; used >>= 8;
state.c[BLOCK_BYTES - 5] = used & 0xFF; used >>= 8;
state.c[BLOCK_BYTES - 6] = used & 0xFF; used >>= 8;
state.c[BLOCK_BYTES - 7] = used & 0xFF; used >>= 8;
state.c[BLOCK_BYTES - 8] = used & 0xFF;
total += chunk;
process (H.w, state.W);
}
/* DIGEST */
std::transform (std::begin (H.w), std::end (H.w), std::begin (H.w), util::hton<uint32_t>);
return H.b;
}

44
hash/sha1.hpp Normal file
View File

@ -0,0 +1,44 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2013-2018 Danny Robson <danny@nerdcruft.net>
*/
#ifndef CRUFT_CRYPTO_HASH_SHA1_HPP
#define CRUFT_CRYPTO_HASH_SHA1_HPP
#include <cruft/util/view.hpp>
#include <array>
#include <cstdint>
#include <cstdlib>
///////////////////////////////////////////////////////////////////////////////
namespace cruft::crypto::hash {
class SHA1 {
public:
using digest_t = std::array<uint8_t,20>;
static const size_t BLOCK_SIZE = 64;
static const size_t DIGEST_SIZE = 20;
//template <typename ...DataT>
//digest_t
//operator() (DataT&&...);
digest_t operator() (util::view<const uint8_t*>, util::view<const uint8_t*>) noexcept;
digest_t operator() (util::view<const uint8_t*>) noexcept;
};
}
#endif

314
hash/sha2.cpp Normal file
View File

@ -0,0 +1,314 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright:
* 2014, Danny Robson <danny@nerdcruft.net>
*/
#include "sha2.hpp"
#include <cruft/util/bitwise.hpp>
#include <cruft/util/debug.hpp>
#include <cruft/util/endian.hpp>
#include <algorithm>
using cruft::crypto::hash::SHA256;
// First 32 bits of the fractional parts
// of the cube roots
// of the first 64 prime numbers
static constexpr
uint32_t K_64[] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
};
// First 64 bits of the fractional parts
// of the cube roots
// of the first 80 prime numbers
static constexpr
uint64_t K_80[] = {
0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817,
};
///////////////////////////////////////////////////////////////////////////////
static constexpr
uint32_t
Ch (uint32_t x, uint32_t y, uint32_t z)
{
return (x & y) ^ (~x & z);
}
//-----------------------------------------------------------------------------
static constexpr
uint32_t
Maj (uint32_t x, uint32_t y, uint32_t z)
{
return (x & y) ^ (x & z) ^ (y & z);
}
///////////////////////////////////////////////////////////////////////////////
#define FUNC(NAME,r0,r1,r2) \
static constexpr \
uint32_t \
NAME (uint32_t x) \
{ \
return util::rotater (x, (r0)) ^ \
util::rotater (x, (r1)) ^ \
util::rotater (x, (r2)); \
}
FUNC(S0, 2, 13, 22)
FUNC(S1, 6, 11, 25)
#undef FUNC
///////////////////////////////////////////////////////////////////////////////
#define FUNC(NAME,r0,r1,s) \
static constexpr \
uint32_t \
NAME (uint32_t x) \
{ \
return util::rotater (x, (r0)) ^ \
util::rotater (x, (r1)) ^ \
(x >> (s)); \
}
FUNC(s0, 7, 18, 3)
FUNC(s1, 17, 19, 10)
#undef FUNC
///////////////////////////////////////////////////////////////////////////////
static constexpr
uint32_t
H_224[] = {
0xc1059ed8,
0x367cd507,
0x3070dd17,
0xf70e5939,
0xffc00b31,
0x68581511,
0x64f98fa7,
0xbefa4fa4,
};
//-----------------------------------------------------------------------------
static constexpr
uint32_t
H_256[] = {
0x6a09e667,
0xbb67ae85,
0x3c6ef372,
0xa54ff53a,
0x510e527f,
0x9b05688c,
0x1f83d9ab,
0x5be0cd19,
};
//-----------------------------------------------------------------------------
static constexpr
uint64_t
H_384[] = {
0xcbbb9d5dc1059ed8,
0x629a292a367cd507,
0x9159015a3070dd17,
0x152fecd8f70e5939,
0x67332667ffc00b31,
0x8eb44a8768581511,
0xdb0c2e0d64f98fa7,
0x47b5481dbefa4fa4,
};
//-----------------------------------------------------------------------------
static constexpr
uint64_t
H_512[] = {
0x6a09e667f3bcc908,
0xbb67ae8584caa73b,
0x3c6ef372fe94f82b,
0xa54ff53a5f1d36f1,
0x510e527fade682d1,
0x9b05688c2b3e6c1f,
0x1f83d9abfb41bd6b,
0x5be0cd19137e2179,
};
///////////////////////////////////////////////////////////////////////////////
SHA256::digest_t
SHA256::operator() (util::view<const uint8_t*> data) noexcept
{
(void)K_80;
(void)H_224;
(void)H_384;
(void)H_512;
/* INIT */
m_total = 0;
std::copy (std::begin (H_256), std::end (H_256), std::begin (H));
/* UPDATE */
{
auto cursor = data.begin ();
auto length = data.size ();
while (length) {
size_t buffered = m_total % sizeof (M);
size_t chunk = std::min (sizeof (M) - buffered, length);
std::copy (cursor, cursor + chunk, C.begin () + buffered);
length -= chunk;
m_total += chunk;
if (m_total % sizeof (M) == 0)
process ();
}
}
/* FINISH */
{
// Append a single 1 bit followed by 0s.
auto buffered = m_total % sizeof (M);
auto used = m_total * 8u;
C[buffered++] = 0x80;
++m_total;
// Pad out to 56 byte length
if (buffered > 56) {
size_t chunk = sizeof (M) - buffered;
std::fill_n (C.begin () + buffered, chunk, 0);
m_total += chunk;
process ();
buffered = 0;
}
size_t chunk = sizeof (M) - sizeof (uint64_t) - buffered;
std::fill_n (C.begin () + buffered, chunk, 0);
m_total += chunk;
// Finish with the m_total size
C[56] = (used >> 56) & 0xFF;
C[57] = (used >> 48) & 0xFF;
C[58] = (used >> 40) & 0xFF;
C[59] = (used >> 32) & 0xFF;
C[60] = (used >> 24) & 0xFF;
C[61] = (used >> 16) & 0xFF;
C[62] = (used >> 8) & 0xFF;
C[63] = (used >> 0) & 0xFF;
m_total += 8;
// Reprocess
process ();
}
/* DIGEST */
digest_t out;
auto cursor = out.begin ();
for (auto i: H) {
*cursor++ = (i >> 24) & 0xFF;
*cursor++ = (i >> 16) & 0xFF;
*cursor++ = (i >> 8) & 0xFF;
*cursor++ = (i >> 0) & 0xFF;
}
return out;
}
///////////////////////////////////////////////////////////////////////////////
void
SHA256::process (void)
{
CHECK_EQ (m_total % sizeof (M), 0u);
// Initialise the message schedule, W
uint32_t W[64];
std::transform (M.begin (), M.end (), std::begin (W), util::ntoh<uint32_t>);
for (size_t i = 16; i < 64; ++i)
W[i] = s1(W[i - 2]) + W[i - 7] + s0 (W[i - 15]) + W[i - 16];
// Working variables
uint32_t a = H[0],
b = H[1],
c = H[2],
d = H[3],
e = H[4],
f = H[5],
g = H[6],
h = H[7];
for (unsigned i = 0; i < 64; ++i) {
uint32_t t1 = h + S1 (e) + Ch (e, f, g) + K_64[i] + W[i];
uint32_t t2 = S0 (a) + Maj (a, b, c);
h = g;
g = f;
f = e;
e = d + t1;
d = c;
c = b;
b = a;
a = t1 + t2;
}
H[0] += a;
H[1] += b;
H[2] += c;
H[3] += d;
H[4] += e;
H[5] += f;
H[6] += g;
H[7] += h;
}

49
hash/sha2.hpp Normal file
View File

@ -0,0 +1,49 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright:
* 2014, Danny Robson <danny@nerdcruft.net>
*/
#ifndef CRUFT_CRYPTO_HASH_SHA2_HPP
#define CRUFT_CRYPTO_HASH_SHA2_HPP
#include <cruft/util/view.hpp>
#include <array>
#include <cstdint>
///////////////////////////////////////////////////////////////////////////////
namespace cruft::crypto::hash {
class SHA256 {
public:
typedef std::array<uint8_t,32> digest_t;
public:
digest_t operator() (util::view<const uint8_t*>) noexcept;
private:
void process (void);
uint64_t m_total;
std::array<uint32_t, 8> H;
union {
std::array<uint32_t, 16> M;
std::array<uint8_t, 64> C;
};
};
}
#endif

12
libcruft-crypto.pc.in Normal file
View File

@ -0,0 +1,12 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libcruft-noise
Description: A templated noise generation library
URL: http://nerdcruft.net/
Version: @VERSION@
Requires: libcruft-util libcruft-image
Libs: -L${libdir} -lcruft-noise
Cflags: -I${includedir}

66
stream/rc4.cpp Normal file
View File

@ -0,0 +1,66 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#include "rc4.hpp"
#include <algorithm>
#include <numeric>
using cruft::crypto::stream::RC4;
///////////////////////////////////////////////////////////////////////////////
RC4::RC4 (const uint8_t *restrict key, size_t len):
x (0),
y (0)
{
std::iota (S.begin (), S.end (), 0);
for (size_t i = 0, j = 0; i < 256; ++i) {
j = (j + S[i] + key[i % len]) % 256;
std::swap (S[i], S[j]);
}
}
//-----------------------------------------------------------------------------
void
RC4::discard (size_t len)
{
while (len--)
get ();
}
//-----------------------------------------------------------------------------
void
RC4::generate (uint8_t *restrict dst, size_t len)
{
std::generate_n (dst, len, [this] (void) { return get (); });
}
//-----------------------------------------------------------------------------
uint8_t
RC4::get (void)
{
x = (x + 1) % 256;
y = (y + S[x]) % 256;
std::swap (S[x], S[y]);
return S[(S[x] + S[y]) % 256];
}

40
stream/rc4.hpp Normal file
View File

@ -0,0 +1,40 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#ifndef CRUFT_CRYPTO_STREAM_RC4_HPP
#define CRUFT_CRYPTO_STREAM_RC4_HPP
#include <array>
#include <cstdint>
#include <cstddef>
namespace cruft::crypto::stream {
class RC4 {
public:
RC4 (const uint8_t *restrict key, size_t len);
void discard (size_t);
void generate (uint8_t *restrict dst, size_t len);
private:
uint8_t get (void);
size_t x, y;
std::array<uint8_t,256> S;
};
}
#endif

41
stream/salsa.cpp Normal file
View File

@ -0,0 +1,41 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2017-2018 Danny Robson <danny@nerdcruft.net>
*/
#include "./salsa.hpp"
///////////////////////////////////////////////////////////////////////////////
std::array<uint8_t,64>
cruft::crypto::stream::salsa20 (const std::array<uint8_t,64> bytes) noexcept
{
auto x = *reinterpret_cast<const std::array<uint32_t,16>*> (&bytes);
auto y = x;
for (auto &t: x)
t = util::ltoh (t);
for (int i = 0; i < 10; ++i)
x = salsa::doubleround (x);
for (size_t i = 0; i < std::size (y); ++i)
x[i] += y[i];
for (auto &t: x)
t = util::htol (t);
return *reinterpret_cast<std::array<uint8_t,64>*> (&x);
}

109
stream/salsa.hpp Normal file
View File

@ -0,0 +1,109 @@
/*
*
* #endif
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2017-2018 Danny Robson <danny@nerdcruft.net>
*/
#ifndef CRUFT_CRYPTO_STREAM_SALSA_HPP
#define CRUFT_CRYPTO_STREAM_SALSA_HPP
#include <cstdint>
#include <array>
#include <cruft/util/bitwise.hpp>
#include <cruft/util/endian.hpp>
namespace cruft::crypto::stream::salsa {
///////////////////////////////////////////////////////////////////////////
constexpr
uint32_t
R (uint32_t a, uint32_t b, uint32_t c, uint32_t k)
{
return b ^ util::rotatel (a + c, k);
}
///////////////////////////////////////////////////////////////////////////
constexpr
std::array<uint32_t,4>
quarter (std::array<uint32_t,4> y) noexcept
{
std::array<uint32_t,4> z {};
z[1] = R (y[0], y[1], y[3], 7);
z[2] = R (z[1], y[2], y[0], 9);
z[3] = R (z[2], y[3], z[1], 13);
z[0] = R (z[3], y[0], z[2], 18);
return z;
}
///////////////////////////////////////////////////////////////////////////
constexpr
std::array<uint32_t,16>
row (const std::array<uint32_t,16> y) noexcept
{
const auto [z00, z01, z02, z03] = quarter ({y[ 0], y[ 1], y[ 2], y[ 3]});
const auto [z05, z06, z07, z04] = quarter ({y[ 5], y[ 6], y[ 7], y[ 4]});
const auto [z10, z11, z08, z09] = quarter ({y[10], y[11], y[ 8], y[ 9]});
const auto [z15, z12, z13, z14] = quarter ({y[15], y[12], y[13], y[14]});
return {
z00, z01, z02, z03,
z04, z05, z06, z07,
z08, z09, z10, z11,
z12, z13, z14, z15
};
}
///////////////////////////////////////////////////////////////////////////
constexpr
std::array<uint32_t,16>
col (const std::array<uint32_t,16> x) noexcept
{
const auto [y00, y04, y08, y12] = quarter ({x[ 0], x[ 4], x[ 8], x[12]});
const auto [y05, y09, y13, y01] = quarter ({x[ 5], x[ 9], x[13], x[ 1]});
const auto [y10, y14, y02, y06] = quarter ({x[10], x[14], x[ 2], x[ 6]});
const auto [y15, y03, y07, y11] = quarter ({x[15], x[ 3], x[ 7], x[11]});
return {
y00, y01, y02, y03,
y04, y05, y06, y07,
y08, y09, y10, y11,
y12, y13, y14, y15,
};
}
///////////////////////////////////////////////////////////////////////////
constexpr
std::array<uint32_t,16>
doubleround (const std::array<uint32_t,16> x) noexcept
{
return row (col (x));
}
}
namespace cruft::crypto::stream {
///////////////////////////////////////////////////////////////////////////
std::array<uint8_t,64>
salsa20 (const std::array<uint8_t,64>) noexcept;
}
#endif

61
test/block/tea.cpp Normal file
View File

@ -0,0 +1,61 @@
#include "block/tea.hpp"
#include <cruft/util/tap.hpp>
#include <cruft/util/types.hpp>
using cruft::crypto::block::TEA;
int
main ()
{
// test vectors from 'TeaCrypt', by Logan J. Drews.
static const struct {
std::array<uint32_t,4> key;
std::array<uint32_t,2> dec;
std::array<uint32_t,2> enc;
} TESTS[] = {
{
{ 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0x00000000, 0x00000000 },
{ 0x41EA3A0A, 0x94BAA940 },
},
{
{ 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0x01020304, 0x05060708 },
{ 0x6A2F9CF3, 0xFCCF3C55 },
},
{
{ 0x00112233, 0x44556677, 0x8899AABB, 0xCCDDEEFF },
{ 0x01020304, 0x05060708 },
{ 0xDEB1C0A2, 0x7E745DB3 },
},
{
{ 0x00112233, 0x44556677, 0x8899AABB, 0xCCDDEEFF },
{ 0x01234567, 0x89ABCDEF },
{ 0x126C6B92, 0xC0653A3E },
},
};
util::TAP::logger tap;
for (size_t i = 0; i < std::size (TESTS); ++i) {
const auto &t = TESTS[i];
TEA gen (t.key);
std::array<uint32_t,2> enc (t.dec);
gen.encrypt (enc.data (), enc.size ());
std::array<uint32_t,2> dec (t.enc);
gen.decrypt (dec.data (), dec.size ());
tap.expect (enc == t.enc, "TEA_enc %zu", i);
tap.expect (dec == t.dec, "TEA_dec %zu", i);
}
return tap.status ();
}

59
test/block/xtea.cpp Normal file
View File

@ -0,0 +1,59 @@
#include "block/xtea.hpp"
#include <cruft/util/tap.hpp>
#include <cruft/util/types.hpp>
int
main ()
{
// test vectors from 'TeaCrypt', by Logan J. Drews.
static const struct {
std::array<uint32_t,4> key;
std::array<uint32_t,2> dec;
std::array<uint32_t,2> enc;
} TESTS[] = {
{
{0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x00000000, 0x00000000},
{0xDEE9D4D8, 0xF7131ED9},
},
{
{0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x01020304, 0x05060708},
{0x065C1B89, 0x75C6A816},
},
{
{0x00112233, 0x44556677, 0x8899AABB, 0xCCDDEEFF},
{0x01020304, 0x05060708},
{0xDCDD7ACD, 0xC1584B79},
},
{
{0x00112233, 0x44556677, 0x8899AABB, 0xCCDDEEFF},
{0x01234567, 0x89ABCDEF},
{0xB8BF2821, 0x622B5B30},
},
};
util::TAP::logger tap;
for (size_t i = 0; i < std::size (TESTS); ++i) {
const auto &t = TESTS[i];
cruft::crypto::block::XTEA gen (t.key);
std::array<uint32_t,2> enc (t.dec);
gen.encrypt (enc.data (), enc.size ());
std::array<uint32_t,2> dec (t.enc);
gen.decrypt (dec.data (), dec.size ());
tap.expect (enc == t.enc, "XTEA_enc %zu", i);
tap.expect (dec == t.dec, "XTEA_dec %zu", i);
}
return tap.status ();
}

117
test/block/xxtea.cpp Normal file
View File

@ -0,0 +1,117 @@
#include "block/xxtea.hpp"
#include <cruft/util/debug.hpp>
#include <cruft/util/tap.hpp>
#include <cruft/util/types.hpp>
#include <vector>
using cruft::crypto::block::XXTEA;
int
main ()
{
// test vectors from 'TeaCrypt', by Logan J. Drews.
static const struct {
std::array<uint32_t,4> key;
std::vector<uint32_t> dec;
std::vector<uint32_t> enc;
} TESTS[] = {
// 64 bit
{
{ 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0x00000000, 0x00000000 },
{ 0x053704AB, 0x575D8C80 }
},
{
{0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x01020304, 0x05060708},
{0xE6911910, 0x0C35DCDA},
},
{
{0x00112233, 0x44556677, 0x8899AABB, 0xCCDDEEFF},
{0x01020304, 0x05060708},
{0x961D49FC, 0x61FF12D6},
},
{
{0x00112233, 0x44556677, 0x8899AABB, 0xCCDDEEFF},
{0x01234567, 0x89ABCDEF},
{0x34354989, 0xDD7D1A7A},
},
// 96 bit
{
{0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x00000000, 0x00000000, 0x00000000},
{0x5E3CD3F0, 0xE109E3CE, 0x79D7C945},
},
{
{0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x00010203, 0x04050607, 0x08090A0B},
{0x5A545AAC, 0x684EB2CB, 0x3E1B8AA0},
},
{
{0x00112233, 0x44556677, 0x8899AABB, 0xCCDDEEFF},
{0x00010203, 0x04050607, 0x08090A0B},
{0x2E77CCEC, 0x674F5149, 0xA0E56496},
},
{
{0x00112233, 0x44556677, 0x8899AABB, 0xCCDDEEFF},
{0x01234567, 0x89ABCDEF, 0x01234567},
{0xEBC5DD46, 0xBE0FEE71, 0xC6BF7193},
},
// 128 bit
{
{0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0xE6C8D5FF, 0x070FB6E4, 0x98A534F7, 0xAC03E399},
},
{
{0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x00010203, 0x04050607, 0x08090A0B, 0x0C0D0E0F},
{0xAF5CFB0E, 0xAE73552B, 0x1D968A9F, 0x5CB94509},
},
{
{0x00112233, 0x44556677, 0x8899AABB, 0xCCDDEEFF},
{0x00010203, 0x04050607, 0x08090A0B, 0x0C0D0E0F},
{0x3EA0E16C, 0x9969535A, 0xE4796D50, 0xF217EEEA},
},
{
{0x00112233, 0x44556677, 0x8899AABB, 0xCCDDEEFF},
{0x01234567, 0x89ABCDEF, 0x01234567, 0x89ABCDEF},
{0x2B4AB1A4, 0x0E487B6D, 0x9A3AACC7, 0xE4132216},
},
};
util::TAP::logger tap;
for (size_t i = 0; i < std::size (TESTS); ++i) {
const auto &t = TESTS[i];
CHECK_EQ (t.dec.size (), t.enc.size ());
XXTEA gen (t.key);
std::vector<uint32_t> enc (t.dec);
gen.encrypt (enc.data (), enc.size ());
std::vector<uint32_t> dec (enc);
gen.decrypt (dec.data (), dec.size ());
tap.expect (enc == t.enc, "XXTEA_enc %zu", i);
tap.expect (dec == t.dec, "XXTEA_dec %zu", i);
}
return tap.status ();
}

285
test/hash/hmac.cpp Normal file
View File

@ -0,0 +1,285 @@
#include "hash/hmac.hpp"
#include "hash/md5.hpp"
#include "hash/sha1.hpp"
#include <cruft/util/debug.hpp>
#include <cruft/util/tap.hpp>
#include <cruft/util/types.hpp>
#include <cstring>
#include <iostream>
#include <vector>
using cruft::crypto::hash::MD5;
using cruft::crypto::hash::SHA1;
using cruft::crypto::hash::HMAC;
//-----------------------------------------------------------------------------
std::vector<uint8_t>
to_vector (const char *str)
{
return std::vector<uint8_t> (str, str + strlen (str));
}
//-----------------------------------------------------------------------------
template <class T>
bool
test_hmac (const std::vector<uint8_t> &key,
const std::vector<uint8_t> &dat,
const std::vector<uint8_t> &res)
{
HMAC<T> h (key);
const auto ours = h (dat);
return std::equal (ours.begin (), ours.end (), res.begin ());
}
typedef bool (*test_func) (const std::vector<uint8_t>&,
const std::vector<uint8_t>&,
const std::vector<uint8_t>&);
//-----------------------------------------------------------------------------
static const struct {
std::vector<uint8_t> key;
std::vector<uint8_t> dat;
std::vector<uint8_t> res;
test_func fun;
} TESTS[] = {
// 1: RFC 2104 test data, MD5
{
{ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b },
{ 'H', 'i', ' ', 'T', 'h', 'e', 'r', 'e' },
{ 0x92, 0x94, 0x72, 0x7a, 0x36, 0x38, 0xbb, 0x1c,
0x13, 0xf4, 0x8e, 0xf8, 0x15, 0x8b, 0xfc, 0x9d },
&test_hmac<MD5>
},
// 2:
{
to_vector ("Jefe"),
to_vector ("what do ya want for nothing?"),
{ 0x75, 0x0c, 0x78, 0x3e, 0x6a, 0xb0, 0xb5, 0x03,
0xea, 0xa8, 0x6e, 0x31, 0x0a, 0x5d, 0xb7, 0x38 },
&test_hmac<MD5>
},
// 3:
{
{ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA },
{ 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
0xDD, 0xDD },
{ 0x56, 0xbe, 0x34, 0x52, 0x1d, 0x14, 0x4c, 0x88,
0xdb, 0xb8, 0xc7, 0x33, 0xf0, 0xe8, 0xb3, 0xf6 },
&test_hmac<MD5>
},
// 4: RFC 2202 test data, MD5
{
{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
0x19 },
{ 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD,
0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD,
0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD,
0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD,
0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD,
0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD,
0xCD, 0xCD },
{ 0x69, 0x7e, 0xaf, 0x0a, 0xca, 0x3a, 0x3a, 0xea,
0x3a, 0x75, 0x16, 0x47, 0x46, 0xff, 0xaa, 0x79 },
&test_hmac<MD5>
},
// 5:
{
{ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c },
to_vector ("Test With Truncation"),
{ 0x56, 0x46, 0x1e, 0xf2, 0x34, 0x2e, 0xdc, 0x00,
0xf9, 0xba, 0xb9, 0x95, 0x69, 0x0e, 0xfd, 0x4c },
&test_hmac<MD5>
// digest-96: 0x56461ef2342edc00f9bab995
},
// 6:
{
{ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa },
to_vector ("Test Using Larger Than Block-Size Key - Hash Key First"),
{ 0x6b, 0x1a, 0xb7, 0xfe, 0x4b, 0xd7, 0xbf, 0x8f,
0x0b, 0x62, 0xe6, 0xce, 0x61, 0xb9, 0xd0, 0xcd },
&test_hmac<MD5>
},
// 7:
{
{ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa },
to_vector ("Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"),
{ 0x6f, 0x63, 0x0f, 0xad, 0x67, 0xcd, 0xa0, 0xee,
0x1f, 0xb1, 0xf5, 0x62, 0xdb, 0x3a, 0xa5, 0x3e },
&test_hmac<MD5>
},
// 8: RFC 2202 test data, SHA1
{
{ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b },
to_vector ("Hi There"),
{ 0xb6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64,
0xe2, 0x8b, 0xc0, 0xb6, 0xfb, 0x37, 0x8c, 0x8e,
0xf1, 0x46, 0xbe, 0x00 },
&test_hmac<SHA1>
},
{
to_vector ("Jefe"),
to_vector ("what do ya want for nothing?"),
{ 0xef, 0xfc, 0xdf, 0x6a, 0xe5, 0xeb, 0x2f, 0xa2,
0xd2, 0x74, 0x16, 0xd5, 0xf1, 0x84, 0xdf, 0x9c,
0x25, 0x9a, 0x7c, 0x79 },
&test_hmac<SHA1>
},
{
{ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa },
{ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
0xdd, 0xdd },
{ 0x12, 0x5d, 0x73, 0x42, 0xb9, 0xac, 0x11, 0xcd,
0x91, 0xa3, 0x9a, 0xf4, 0x8a, 0xa1, 0x7b, 0x4f,
0x63, 0xf1, 0x75, 0xd3 },
&test_hmac<SHA1>
},
{
{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
0x19 },
{ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
0xcd, 0xcd },
{ 0x4c, 0x90, 0x07, 0xf4, 0x02, 0x62, 0x50, 0xc6,
0xbc, 0x84, 0x14, 0xf9, 0xbf, 0x50, 0xc8, 0x6c,
0x2d, 0x72, 0x35, 0xda },
&test_hmac<SHA1>
},
{
{ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
0x0c, 0x0c, 0x0c, 0x0c },
to_vector ("Test With Truncation"),
{ 0x4c, 0x1a, 0x03, 0x42, 0x4b, 0x55, 0xe0, 0x7f,
0xe7, 0xf2, 0x7b, 0xe1, 0xd5, 0x8b, 0xb9, 0x32,
0x4a, 0x9a, 0x5a, 0x04 },
&test_hmac<SHA1>
},
{
{ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa },
to_vector ("Test Using Larger Than Block-Size Key - Hash Key First"),
{ 0xaa, 0x4a, 0xe5, 0xe1, 0x52, 0x72, 0xd0, 0x0e,
0x95, 0x70, 0x56, 0x37, 0xce, 0x8a, 0x3b, 0x55,
0xed, 0x40, 0x21, 0x12 },
&test_hmac<SHA1>
},
{
{ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa },
to_vector ("Test Using Larger Than Block-Size Key - Hash Key First"),
{ 0xaa, 0x4a, 0xe5, 0xe1, 0x52, 0x72, 0xd0, 0x0e,
0x95, 0x70, 0x56, 0x37, 0xce, 0x8a, 0x3b, 0x55,
0xed, 0x40, 0x21, 0x12 },
&test_hmac<SHA1>
},
{
{ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa },
to_vector ("Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"),
{ 0xe8, 0xe9, 0x9d, 0x0f, 0x45, 0x23, 0x7d, 0x78,
0x6d, 0x6b, 0xba, 0xa7, 0x96, 0x5c, 0x78, 0x08,
0xbb, 0xff, 0x1a, 0x91 },
&test_hmac<SHA1>
},
};
//-----------------------------------------------------------------------------
int
main (int, char**)
{
util::TAP::logger tap;
for (size_t i = 0; i < std::size (TESTS); ++i)
tap.expect (TESTS[i].fun (TESTS[i].key, TESTS[i].dat, TESTS[i].res), "standard test vector %zu", i);
return tap.status ();
}

35
test/hash/hotp.cpp Normal file
View File

@ -0,0 +1,35 @@
#include "hash/hotp.hpp"
#include <cruft/util/debug.hpp>
#include <cruft/util/tap.hpp>
#include <cruft/util/types.hpp>
using cruft::crypto::hash::HOTP;
int
main (int, char**)
{
HOTP h ("12345678901234567890", 0);
const unsigned EXPECTED[] = {
755224,
287082,
359152,
969429,
338314,
254676,
287922,
162583,
399871,
520489,
};
util::TAP::logger tap;
for (auto &i: EXPECTED)
tap.expect_eq (i, h.value (), "sequence");
return tap.status ();
}

60
test/hash/md2.cpp Normal file
View File

@ -0,0 +1,60 @@
#include "hash/md2.hpp"
#include <cruft/util/tap.hpp>
#include <cstring>
#include <iostream>
using cruft::crypto::hash::MD2;
int
main (int, char **) {
static const struct {
const char *input;
MD2::digest_t output;
} TESTS[] = {
{ "",
{ { 0x83, 0x50, 0xe5, 0xa3, 0xe2, 0x4c, 0x15, 0x3d,
0xf2, 0x27, 0x5c, 0x9f, 0x80, 0x69, 0x27, 0x73 } }
},
{ "a",
{ { 0x32, 0xec, 0x01, 0xec, 0x4a, 0x6d, 0xac, 0x72,
0xc0, 0xab, 0x96, 0xfb, 0x34, 0xc0, 0xb5, 0xd1 } }
},
{ "abc",
{ { 0xda, 0x85, 0x3b, 0x0d, 0x3f, 0x88, 0xd9, 0x9b,
0x30, 0x28, 0x3a, 0x69, 0xe6, 0xde, 0xd6, 0xbb } }
},
{ "message digest",
{ { 0xab, 0x4f, 0x49, 0x6b, 0xfb, 0x2a, 0x53, 0x0b,
0x21, 0x9f, 0xf3, 0x30, 0x31, 0xfe, 0x06, 0xb0 } }
},
{ "abcdefghijklmnopqrstuvwxyz",
{ { 0x4e, 0x8d, 0xdf, 0xf3, 0x65, 0x02, 0x92, 0xab,
0x5a, 0x41, 0x08, 0xc3, 0xaa, 0x47, 0x94, 0x0b } }
},
{ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
{ { 0xda, 0x33, 0xde, 0xf2, 0xa4, 0x2d, 0xf1, 0x39,
0x75, 0x35, 0x28, 0x46, 0xc3, 0x03, 0x38, 0xcd } }
},
{ "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
{ { 0xd5, 0x97, 0x6f, 0x79, 0xd8, 0x3d, 0x3a, 0x0d,
0xc9, 0x80, 0x6c, 0x3c, 0x66, 0xf3, 0xef, 0xd8 } }
}
};
bool success = true;
const MD2 h;
for (const auto &i: TESTS) {
if (h (util::view{i.input}.cast<const uint8_t> ()) != i.output) {
std::cerr << "Failed on " << i.input << "\n";
success = false;
}
}
util::TAP::logger tap;
tap.expect (success, "test vectors");
return tap.status ();
}

68
test/hash/md4.cpp Normal file
View File

@ -0,0 +1,68 @@
#include "hash/md4.hpp"
#include <cruft/util/tap.hpp>
#include <cstring>
#include <iostream>
using cruft::crypto::hash::MD4;
int
main (int, char**) {
static const struct {
const char *input;
MD4::digest_t output;
} TESTS[] = {
{
"",
{ { 0x31, 0xd6, 0xcf, 0xe0, 0xd1, 0x6a, 0xe9, 0x31,
0xb7, 0x3c, 0x59, 0xd7, 0xe0, 0xc0, 0x89, 0xc0 } }
},
{
"a",
{ { 0xbd, 0xe5, 0x2c, 0xb3, 0x1d, 0xe3, 0x3e, 0x46,
0x24, 0x5e, 0x05, 0xfb, 0xdb, 0xd6, 0xfb, 0x24 } }
},
{
"abc",
{ { 0xa4, 0x48, 0x01, 0x7a, 0xaf, 0x21, 0xd8, 0x52,
0x5f, 0xc1, 0x0a, 0xe8, 0x7a, 0xa6, 0x72, 0x9d } }
},
{
"message digest",
{ { 0xd9, 0x13, 0x0a, 0x81, 0x64, 0x54, 0x9f, 0xe8,
0x18, 0x87, 0x48, 0x06, 0xe1, 0xc7, 0x01, 0x4b } }
},
{
"abcdefghijklmnopqrstuvwxyz",
{ { 0xd7, 0x9e, 0x1c, 0x30, 0x8a, 0xa5, 0xbb, 0xcd,
0xee, 0xa8, 0xed, 0x63, 0xdf, 0x41, 0x2d, 0xa9 }, }
},
{
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
{ { 0x04, 0x3f, 0x85, 0x82, 0xf2, 0x41, 0xdb, 0x35,
0x1c, 0xe6, 0x27, 0xe1, 0x53, 0xe7, 0xf0, 0xe4 } }
},
{
"12345678901234567890123456789012345678901234567890123456789012345678901234567890",
{ { 0xe3, 0x3b, 0x4d, 0xdc, 0x9c, 0x38, 0xf2, 0x19,
0x9c, 0x3e, 0x7b, 0x16, 0x4f, 0xcc, 0x05, 0x36 } }
}
};
bool success = true;
MD4 h;
for (auto i: TESTS) {
if (h (util::view{i.input}.cast <const uint8_t> ()) != i.output) {
std::cerr << "Failed on '" << i.input << "'\n";
success = false;
}
}
util::TAP::logger tap;
tap.expect (success, "test vectors");
return tap.status ();
}

93
test/hash/md5.cpp Normal file
View File

@ -0,0 +1,93 @@
#include "hash/md5.hpp"
#include <cruft/util/tap.hpp>
#include <iostream>
#include <cstring>
using cruft::crypto::hash::MD5;
///////////////////////////////////////////////////////////////////////////////
std::vector<uint8_t>
operator"" _u8s (const char *str, size_t len)
{
std::vector<uint8_t> res;
res.resize (len);
std::copy_n (str, len, std::begin (res));
return res;
}
///////////////////////////////////////////////////////////////////////////////
int
main (int, char**) {
static const struct {
std::vector<uint8_t> input;
MD5::digest_t output;
const char *msg;
} TESTS[] = {
{ {},
{ { 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04,
0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e } },
"empty"
},
{ "a"_u8s,
{ { 0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8,
0x31, 0xc3, 0x99, 0xe2, 0x69, 0x77, 0x26, 0x61 } },
"1 byte"
},
{ "abc"_u8s,
{ { 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0,
0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72 } },
"3 bytes"
},
{ "message digest"_u8s,
{ { 0xf9, 0x6b, 0x69, 0x7d, 0x7c, 0xb7, 0x93, 0x8d,
0x52, 0x5a, 0x2f, 0x31, 0xaa, 0xf1, 0x61, 0xd0 } },
"14 bytes, text"
},
{ "abcdefghijklmnopqrstuvwxyz"_u8s,
{ { 0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00,
0x7d, 0xfb, 0x49, 0x6c, 0xca, 0x67, 0xe1, 0x3b } },
"14 bytes, alphabet"
},
{ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"_u8s,
{ { 0xd1, 0x74, 0xab, 0x98, 0xd2, 0x77, 0xd9, 0xf5,
0xa5, 0x61, 0x1c, 0x2c, 0x9f, 0x41, 0x9d, 0x9f } },
"62 bytes"
},
{ "12345678901234567890123456789012345678901234567890123456789012345678901234567890"_u8s,
{ { 0x57, 0xed, 0xf4, 0xa2, 0x2b, 0xe3, 0xc9, 0x55,
0xac, 0x49, 0xda, 0x2e, 0x21, 0x07, 0xb6, 0x7a } },
"80 bytes"
}
};
util::TAP::logger tap;
MD5 h;
for (const auto &t: TESTS)
tap.expect_eq (h (t.input), t.output, "%s", t.msg);
// check that appending or prepending an empty data view doesn't change
// the hash for a couple of data lengths
for (auto l: { 0, 1, 8, 64, 80}) {
std::vector<uint8_t> data (l);
std::iota (std::begin (data), std::end (data), 0);
tap.expect_eq (h (nullptr, data), h (data), "empty-full vs full hash equality, %! bytes", l);
tap.expect_eq (h (data, nullptr), h (data), "full-empty vs full hash equality, %! bytes", l);
}
for (auto l: { 2, 64, 80}) {
std::vector<uint8_t> data (l);
std::iota (std::begin (data), std::end (data), 0);
util::view root {data};
auto [a,b] = root.split (root.begin () + l / 2);
tap.expect_eq (h (a,b), h(root), "split data hash equality, %! bytes", l);
};
return tap.status ();
}

147
test/hash/ripemd.cpp Normal file
View File

@ -0,0 +1,147 @@
#include "hash/ripemd.hpp"
#include <cruft/util/tap.hpp>
#include <cruft/util/types.hpp>
#include <cstring>
using cruft::crypto::hash::RIPEMD;
///////////////////////////////////////////////////////////////////////////////
std::vector<uint8_t>
operator"" _u8s (const char *str, size_t len)
{
std::vector<uint8_t> res;
res.resize (len);
std::copy_n (str, len, std::begin (res));
return res;
}
///////////////////////////////////////////////////////////////////////////////
static const
struct {
const char *msg;
std::vector<uint8_t> data;
RIPEMD::digest_t output;
} TESTS[] = {
{
"empty",
""_u8s,
{ 0x9c, 0x11, 0x85, 0xa5, 0xc5, 0xe9, 0xfc, 0x54, 0x61, 0x28,
0x08, 0x97, 0x7e, 0xe8, 0xf5, 0x48, 0xb2, 0x25, 0x8d, 0x31 },
// 128: cdf26213a150dc3ecb610f18f6b38b46
// 160: 9c1185a5c5e9fc54612808977ee8f548b2258d31
// 256: 02ba4c4e5f8ecd1877fc52d64d30e37a2d9774fb1e5d026380ae0168e3c5522d
// 320: 22d65d5661536cdc75c1fdf5c6de7b41b9f27325ebc61e8557177d705a0ec880151c3a32a00899b8
},
{
"a",
"a"_u8s,
{ 0x0b, 0xdc, 0x9d, 0x2d, 0x25, 0x6b, 0x3e, 0xe9, 0xda, 0xae,
0x34, 0x7b, 0xe6, 0xf4, 0xdc, 0x83, 0x5a, 0x46, 0x7f, 0xfe },
// 128: 86be7afa339d0fc7cfc785e72f578d33
// 160: 0bdc9d2d256b3ee9daae347be6f4dc835a467ffe
// 256: f9333e45d857f5d90a91bab70a1eba0cfb1be4b0783c9acfcd883a9134692925
// 320: ce78850638f92658a5a585097579926dda667a5716562cfcf6fbe77f63542f99b04705d6970dff5d
},
{
"abc",
"abc"_u8s,
{ 0x8e, 0xb2, 0x08, 0xf7, 0xe0, 0x5d, 0x98, 0x7a, 0x9b, 0x04,
0x4a, 0x8e, 0x98, 0xc6, 0xb0, 0x87, 0xf1, 0x5a, 0x0b, 0xfc },
// 128: c14a12199c66e4ba84636b0f69144c77
// 160: 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc
// 256: afbd6e228b9d8cbbcef5ca2d03e6dba10ac0bc7dcbe4680e1e42d2e975459b65
// 320: de4c01b3054f8930a79d09ae738e92301e5a17085beffdc1b8d116713e74f82fa942d64cdbc4682d
},
{
"message digest",
"message digest"_u8s,
{ 0x5d, 0x06, 0x89, 0xef, 0x49, 0xd2, 0xfa, 0xe5, 0x72, 0xb8,
0x81, 0xb1, 0x23, 0xa8, 0x5f, 0xfa, 0x21, 0x59, 0x5f, 0x36 },
// 128: 9e327b3d6e523062afc1132d7df9d1b8
// 160: 5d0689ef49d2fae572b881b123a85ffa21595f36
// 256: 87e971759a1ce47a514d5c914c392c9018c7c46bc14465554afcdf54a5070c0e
// 320: 3a8e28502ed45d422f68844f9dd316e7b98533fa3f2a91d29f84d425c88d6b4eff727df66a7c0197
},
{
"26 characters",
"abcdefghijklmnopqrstuvwxyz"_u8s,
{ 0xf7, 0x1c, 0x27, 0x10, 0x9c, 0x69, 0x2c, 0x1b, 0x56, 0xbb,
0xdc, 0xeb, 0x5b, 0x9d, 0x28, 0x65, 0xb3, 0x70, 0x8d, 0xbc },
// 128: fd2aa607f71dc8f510714922b371834e
// 160: f71c27109c692c1b56bbdceb5b9d2865b3708dbc
// 256: 649d3034751ea216776bf9a18acc81bc7896118a5197968782dd1fd97d8d5133
// 320: cabdb1810b92470a2093aa6bce05952c28348cf43ff60841975166bb40ed234004b8824463e6b009
},
{
"57 characters",
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"_u8s,
{ 0x12, 0xa0, 0x53, 0x38, 0x4a, 0x9c, 0x0c, 0x88, 0xe4, 0x05,
0xa0, 0x6c, 0x27, 0xdc, 0xf4, 0x9a, 0xda, 0x62, 0xeb, 0x2b },
// 128: a1aa0689d0fafa2ddc22e88b49133a06
// 160: 12a053384a9c0c88e405a06c27dcf49ada62eb2b
// 256: 3843045583aac6c8c8d9128573e7a9809afb2a0f34ccc36ea9e72f16f6368e3f
// 320: d034a7950cf722021ba4b84df769a5de2060e259df4c9bb4a4268c0e935bbc7470a969c9d072a1ac
},
{
"63 characters",
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"_u8s,
{ 0xb0, 0xe2, 0x0b, 0x6e, 0x31, 0x16, 0x64, 0x02, 0x86, 0xed,
0x3a, 0x87, 0xa5, 0x71, 0x30, 0x79, 0xb2, 0x1f, 0x51, 0x89 },
// 128: d1e959eb179c911faea4624c60c5c702
// 160: b0e20b6e3116640286ed3a87a5713079b21f5189
// 256: 5740a408ac16b720b84424ae931cbb1fe363d1d0bf4017f1a89f7ea6de77a0b8
// 320: ed544940c86d67f250d232c30b7b3e5770e0c60c8cb9a4cafe3b11388af9920e1b99230b843c86a4
},
{
"81 digits",
"12345678901234567890123456789012345678901234567890123456789012345678901234567890"_u8s,
{ 0x9b, 0x75, 0x2e, 0x45, 0x57, 0x3d, 0x4b, 0x39, 0xf4, 0xdb,
0xd3, 0x32, 0x3c, 0xab, 0x82, 0xbf, 0x63, 0x32, 0x6b, 0xfb }
// 128: 3f45ef194732c2dbb2c4a2c769795fa3
// 160: 9b752e45573d4b39f4dbd3323cab82bf63326bfb
// 256: 06fdcc7a409548aaf91368c06a6275b553e3f099bf0ea4edfd6778df89a890dd
// 320: 557888af5f6d8ed62ab66945c6d2a0a47ecd5341e915eb8fea1d0524955f825dc717e4a008ab2d42
}
};
int
main(int, char**) {
util::TAP::logger tap;
// Check against simple test vectors
for (const auto &t: TESTS) {
RIPEMD obj;
tap.expect_eq (obj (t.data), t.output, "%s", t.msg);
}
// Perform 'million-a' check
RIPEMD obj;
// 1 million times "a"
// 128: 4a7f5723f954eba1216c9d8f6320431f
// 160: 52783243c1697bdbe16d37f97f68f08325dc1528
// 256: ac953744e10e31514c150d4d8d7b677342e33399788296e43ae4850ce4f97978
// 320: bdee37f4371e20646b8b0d862dda16292ae36f40965e8c8509e63d1dbddecc503e2b63eb9245bb66
std::vector<uint8_t> data (1'000'000, 'a');
static const RIPEMD::digest_t MILLION {
0x52, 0x78, 0x32, 0x43, 0xc1, 0x69, 0x7b, 0xdb, 0xe1, 0x6d,
0x37, 0xf9, 0x7f, 0x68, 0xf0, 0x83, 0x25, 0xdc, 0x15, 0x28
};
tap.expect_eq (obj (data), MILLION, "million 'a'");
return tap.status ();
}

111
test/hash/sha1.cpp Normal file
View File

@ -0,0 +1,111 @@
#include "hash/sha1.hpp"
#include <cruft/util/debug.hpp>
#include <cruft/util/tap.hpp>
#include <cruft/util/types.hpp>
#include <cstdlib>
#include <cstring>
#include <iostream>
using cruft::crypto::hash::SHA1;
///////////////////////////////////////////////////////////////////////////////
std::vector<uint8_t>
operator"" _u8s (const char *str, size_t len)
{
std::vector<uint8_t> res;
res.resize (len);
std::copy_n (str, len, std::begin (res));
return res;
}
///////////////////////////////////////////////////////////////////////////////
int
main (int, char**)
{
util::TAP::logger tap;
static const struct {
const char *msg;
std::vector<uint8_t> input;
SHA1::digest_t output;
} TESTS[] = {
{
"empty string",
""_u8s,
{ { 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55,
0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09 } }
},
{
"single a",
"a"_u8s,
{ { 0x86, 0xf7, 0xe4, 0x37, 0xfa, 0xa5, 0xa7, 0xfc, 0xe1, 0x5d,
0x1d, 0xdc, 0xb9, 0xea, 0xea, 0xea, 0x37, 0x76, 0x67, 0xb8 } }
},
{
"abc",
"abc"_u8s,
{ { 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E,
0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D } }
},
{
"abc...opq",
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"_u8s,
{ { 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, 0xBA, 0xAE,
0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, 0xE5, 0x46, 0x70, 0xF1 } }
},
{
"896 bit alphabet",
"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
"hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"_u8s,
{ 0xa4, 0x9b, 0x24, 0x46,
0xa0, 0x2c, 0x64, 0x5b,
0xf4, 0x19, 0xf9, 0x95,
0xb6, 0x70, 0x91, 0x25,
0x3a, 0x04, 0xa2, 0x59, }
}
// 1'000'000 * 'a'
//{ "a",
// { { 0x34, 0xAA, 0x97, 0x3C, 0xD4, 0xC4, 0xDA, 0xA4, 0xF6, 0x1E,
// 0xEB, 0x2B, 0xDB, 0xAD, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6F } }
//},
// 16'777'216 x "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno"
// about 1GiB of text
// 7789f0c9 ef7bfc40 d9331114 3dfbe69e 2017f592
// 80 repetitions of 01234567
//{ "0123456701234567012345670123456701234567012345670123456701234567",
// { { 0xDE, 0xA3, 0x56, 0xA2, 0xCD, 0xDD, 0x90, 0xC7, 0xA7, 0xEC,
// 0xED, 0xC5, 0xEB, 0xB5, 0x63, 0x93, 0x4F, 0x46, 0x04, 0x52 } }
//}
};
SHA1 obj;
for (const auto &t: TESTS)
tap.expect_eq (obj (t.input), t.output, "%s", t.msg);
{
std::vector<uint8_t> data (1'000'000, 0x61);
SHA1::digest_t result {
0x34, 0xaa, 0x97, 0x3c,
0xd4, 0xc4, 0xda, 0xa4,
0xf6, 0x1e, 0xeb, 0x2b,
0xdb, 0xad, 0x27, 0x31,
0x65, 0x34, 0x01, 0x6f,
};
tap.expect_eq (obj (data), result, "1'000'000 a's");
}
return tap.status ();
}

63
test/hash/sha2.cpp Normal file
View File

@ -0,0 +1,63 @@
#include "hash/sha2.hpp"
#include <cruft/util/tap.hpp>
#include <cstring>
using cruft::crypto::hash::SHA256;
static const struct {
const char *msg;
const char *input;
SHA256::digest_t output;
} TESTS[] = {
{
"empty",
"",
{ 0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24,
0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55 }
},
{
"single a",
"a",
{ 0xCA, 0x97, 0x81, 0x12, 0xCA, 0x1B, 0xBD, 0xCA, 0xFA, 0xC2, 0x31, 0xB3, 0x9A, 0x23, 0xDC, 0x4D,
0xA7, 0x86, 0xEF, 0xF8, 0x14, 0x7C, 0x4E, 0x72, 0xB9, 0x80, 0x77, 0x85, 0xAF, 0xEE, 0x48, 0xBB }
},
{
"abc",
"abc",
{ 0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA, 0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23,
0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C, 0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD },
},
{
"abc...opq",
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
{ 0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8, 0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E, 0x60, 0x39,
0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67, 0xF6, 0xEC, 0xED, 0xD4, 0x19, 0xDB, 0x06, 0xC1 }
},
{
"77 digits",
"0123456701234567012345670123456701234567012345670123456701234567",
{ 0x81, 0x82, 0xCA, 0xDB, 0x21, 0xAF, 0x0E, 0x37, 0xC0, 0x64, 0x14, 0xEC, 0xE0, 0x8E, 0x19, 0xC6,
0x5B, 0xDB, 0x22, 0xC3, 0x96, 0xD4, 0x8B, 0xA7, 0x34, 0x10, 0x12, 0xEE, 0xA9, 0xFF, 0xDF, 0xDD }
}
};
int
main (int, char **) {
util::TAP::logger tap;
for (const auto &i: TESTS) {
SHA256 obj;
tap.expect_eq (obj (util::view{i.input}.cast<const uint8_t> ()), i.output, "%s", i.msg);
}
return tap.status ();
}

398
test/stream/rc4.cpp Normal file
View File

@ -0,0 +1,398 @@
#include "stream/rc4.hpp"
#include <cruft/util/debug.hpp>
#include <cruft/util/tap.hpp>
#include <cruft/util/types.hpp>
#include <vector>
using cruft::crypto::stream::RC4;
int
main ()
{
util::TAP::logger tap;
// Test vectors from RFC 6229.
static const size_t OFFSETS[] = {
0, 16, 240, 256, 496, 512, 752, 768, 1008, 1024, 1520, 1536, 2032, 2048, 3056, 3072, 4080, 4096
};
struct {
std::vector<uint8_t> key;
const uint64_t data[std::size (OFFSETS)][16];
} TESTS[] = {
{
{ 1, 2, 3, 4, 5 },
{
{ 0xb2, 0x39, 0x63, 0x05, 0xf0, 0x3d, 0xc0, 0x27, 0xcc, 0xc3, 0x52, 0x4a, 0x0a, 0x11, 0x18, 0xa8 },
{ 0x69, 0x82, 0x94, 0x4f, 0x18, 0xfc, 0x82, 0xd5, 0x89, 0xc4, 0x03, 0xa4, 0x7a, 0x0d, 0x09, 0x19 },
{ 0x28, 0xcb, 0x11, 0x32, 0xc9, 0x6c, 0xe2, 0x86, 0x42, 0x1d, 0xca, 0xad, 0xb8, 0xb6, 0x9e, 0xae },
{ 0x1c, 0xfc, 0xf6, 0x2b, 0x03, 0xed, 0xdb, 0x64, 0x1d, 0x77, 0xdf, 0xcf, 0x7f, 0x8d, 0x8c, 0x93 },
{ 0x42, 0xb7, 0xd0, 0xcd, 0xd9, 0x18, 0xa8, 0xa3, 0x3d, 0xd5, 0x17, 0x81, 0xc8, 0x1f, 0x40, 0x41 },
{ 0x64, 0x59, 0x84, 0x44, 0x32, 0xa7, 0xda, 0x92, 0x3c, 0xfb, 0x3e, 0xb4, 0x98, 0x06, 0x61, 0xf6 },
{ 0xec, 0x10, 0x32, 0x7b, 0xde, 0x2b, 0xee, 0xfd, 0x18, 0xf9, 0x27, 0x76, 0x80, 0x45, 0x7e, 0x22 },
{ 0xeb, 0x62, 0x63, 0x8d, 0x4f, 0x0b, 0xa1, 0xfe, 0x9f, 0xca, 0x20, 0xe0, 0x5b, 0xf8, 0xff, 0x2b },
{ 0x45, 0x12, 0x90, 0x48, 0xe6, 0xa0, 0xed, 0x0b, 0x56, 0xb4, 0x90, 0x33, 0x8f, 0x07, 0x8d, 0xa5 },
{ 0x30, 0xab, 0xbc, 0xc7, 0xc2, 0x0b, 0x01, 0x60, 0x9f, 0x23, 0xee, 0x2d, 0x5f, 0x6b, 0xb7, 0xdf },
{ 0x32, 0x94, 0xf7, 0x44, 0xd8, 0xf9, 0x79, 0x05, 0x07, 0xe7, 0x0f, 0x62, 0xe5, 0xbb, 0xce, 0xea },
{ 0xd8, 0x72, 0x9d, 0xb4, 0x18, 0x82, 0x25, 0x9b, 0xee, 0x4f, 0x82, 0x53, 0x25, 0xf5, 0xa1, 0x30 },
{ 0x1e, 0xb1, 0x4a, 0x0c, 0x13, 0xb3, 0xbf, 0x47, 0xfa, 0x2a, 0x0b, 0xa9, 0x3a, 0xd4, 0x5b, 0x8b },
{ 0xcc, 0x58, 0x2f, 0x8b, 0xa9, 0xf2, 0x65, 0xe2, 0xb1, 0xbe, 0x91, 0x12, 0xe9, 0x75, 0xd2, 0xd7 },
{ 0xf2, 0xe3, 0x0f, 0x9b, 0xd1, 0x02, 0xec, 0xbf, 0x75, 0xaa, 0xad, 0xe9, 0xbc, 0x35, 0xc4, 0x3c },
{ 0xec, 0x0e, 0x11, 0xc4, 0x79, 0xdc, 0x32, 0x9d, 0xc8, 0xda, 0x79, 0x68, 0xfe, 0x96, 0x56, 0x81 },
{ 0x06, 0x83, 0x26, 0xa2, 0x11, 0x84, 0x16, 0xd2, 0x1f, 0x9d, 0x04, 0xb2, 0xcd, 0x1c, 0xa0, 0x50 },
{ 0xff, 0x25, 0xb5, 0x89, 0x95, 0x99, 0x67, 0x07, 0xe5, 0x1f, 0xbd, 0xf0, 0x8b, 0x34, 0xd8, 0x75 },
}
},
{
{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 },
{
{ 0x29, 0x3f, 0x02, 0xd4, 0x7f, 0x37, 0xc9, 0xb6, 0x33, 0xf2, 0xaf, 0x52, 0x85, 0xfe, 0xb4, 0x6b },
{ 0xe6, 0x20, 0xf1, 0x39, 0x0d, 0x19, 0xbd, 0x84, 0xe2, 0xe0, 0xfd, 0x75, 0x20, 0x31, 0xaf, 0xc1 },
{ 0x91, 0x4f, 0x02, 0x53, 0x1c, 0x92, 0x18, 0x81, 0x0d, 0xf6, 0x0f, 0x67, 0xe3, 0x38, 0x15, 0x4c },
{ 0xd0, 0xfd, 0xb5, 0x83, 0x07, 0x3c, 0xe8, 0x5a, 0xb8, 0x39, 0x17, 0x74, 0x0e, 0xc0, 0x11, 0xd5 },
{ 0x75, 0xf8, 0x14, 0x11, 0xe8, 0x71, 0xcf, 0xfa, 0x70, 0xb9, 0x0c, 0x74, 0xc5, 0x92, 0xe4, 0x54 },
{ 0x0b, 0xb8, 0x72, 0x02, 0x93, 0x8d, 0xad, 0x60, 0x9e, 0x87, 0xa5, 0xa1, 0xb0, 0x79, 0xe5, 0xe4 },
{ 0xc2, 0x91, 0x12, 0x46, 0xb6, 0x12, 0xe7, 0xe7, 0xb9, 0x03, 0xdf, 0xed, 0xa1, 0xda, 0xd8, 0x66 },
{ 0x32, 0x82, 0x8f, 0x91, 0x50, 0x2b, 0x62, 0x91, 0x36, 0x8d, 0xe8, 0x08, 0x1d, 0xe3, 0x6f, 0xc2 },
{ 0xf3, 0xb9, 0xa7, 0xe3, 0xb2, 0x97, 0xbf, 0x9a, 0xd8, 0x04, 0x51, 0x2f, 0x90, 0x63, 0xef, 0xf1 },
{ 0x8e, 0xcb, 0x67, 0xa9, 0xba, 0x1f, 0x55, 0xa5, 0xa0, 0x67, 0xe2, 0xb0, 0x26, 0xa3, 0x67, 0x6f },
{ 0xd2, 0xaa, 0x90, 0x2b, 0xd4, 0x2d, 0x0d, 0x7c, 0xfd, 0x34, 0x0c, 0xd4, 0x58, 0x10, 0x52, 0x9f },
{ 0x78, 0xb2, 0x72, 0xc9, 0x6e, 0x42, 0xea, 0xb4, 0xc6, 0x0b, 0xd9, 0x14, 0xe3, 0x9d, 0x06, 0xe3 },
{ 0xf4, 0x33, 0x2f, 0xd3, 0x1a, 0x07, 0x93, 0x96, 0xee, 0x3c, 0xee, 0x3f, 0x2a, 0x4f, 0xf0, 0x49 },
{ 0x05, 0x45, 0x97, 0x81, 0xd4, 0x1f, 0xda, 0x7f, 0x30, 0xc1, 0xbe, 0x7e, 0x12, 0x46, 0xc6, 0x23 },
{ 0xad, 0xfd, 0x38, 0x68, 0xb8, 0xe5, 0x14, 0x85, 0xd5, 0xe6, 0x10, 0x01, 0x7e, 0x3d, 0xd6, 0x09 },
{ 0xad, 0x26, 0x58, 0x1c, 0x0c, 0x5b, 0xe4, 0x5f, 0x4c, 0xea, 0x01, 0xdb, 0x2f, 0x38, 0x05, 0xd5 },
{ 0xf3, 0x17, 0x2c, 0xef, 0xfc, 0x3b, 0x3d, 0x99, 0x7c, 0x85, 0xcc, 0xd5, 0xaf, 0x1a, 0x95, 0x0c },
{ 0xe7, 0x4b, 0x0b, 0x97, 0x31, 0x22, 0x7f, 0xd3, 0x7c, 0x0e, 0xc0, 0x8a, 0x47, 0xdd, 0xd8, 0xb8 },
}
},
{
{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 },
{
{ 0x97, 0xab, 0x8a, 0x1b, 0xf0, 0xaf, 0xb9, 0x61, 0x32, 0xf2, 0xf6, 0x72, 0x58, 0xda, 0x15, 0xa8 },
{ 0x82, 0x63, 0xef, 0xdb, 0x45, 0xc4, 0xa1, 0x86, 0x84, 0xef, 0x87, 0xe6, 0xb1, 0x9e, 0x5b, 0x09 },
{ 0x96, 0x36, 0xeb, 0xc9, 0x84, 0x19, 0x26, 0xf4, 0xf7, 0xd1, 0xf3, 0x62, 0xbd, 0xdf, 0x6e, 0x18 },
{ 0xd0, 0xa9, 0x90, 0xff, 0x2c, 0x05, 0xfe, 0xf5, 0xb9, 0x03, 0x73, 0xc9, 0xff, 0x4b, 0x87, 0x0a },
{ 0x73, 0x23, 0x9f, 0x1d, 0xb7, 0xf4, 0x1d, 0x80, 0xb6, 0x43, 0xc0, 0xc5, 0x25, 0x18, 0xec, 0x63 },
{ 0x16, 0x3b, 0x31, 0x99, 0x23, 0xa6, 0xbd, 0xb4, 0x52, 0x7c, 0x62, 0x61, 0x26, 0x70, 0x3c, 0x0f },
{ 0x49, 0xd6, 0xc8, 0xaf, 0x0f, 0x97, 0x14, 0x4a, 0x87, 0xdf, 0x21, 0xd9, 0x14, 0x72, 0xf9, 0x66 },
{ 0x44, 0x17, 0x3a, 0x10, 0x3b, 0x66, 0x16, 0xc5, 0xd5, 0xad, 0x1c, 0xee, 0x40, 0xc8, 0x63, 0xd0 },
{ 0x27, 0x3c, 0x9c, 0x4b, 0x27, 0xf3, 0x22, 0xe4, 0xe7, 0x16, 0xef, 0x53, 0xa4, 0x7d, 0xe7, 0xa4 },
{ 0xc6, 0xd0, 0xe7, 0xb2, 0x26, 0x25, 0x9f, 0xa9, 0x02, 0x34, 0x90, 0xb2, 0x61, 0x67, 0xad, 0x1d },
{ 0x1f, 0xe8, 0x98, 0x67, 0x13, 0xf0, 0x7c, 0x3d, 0x9a, 0xe1, 0xc1, 0x63, 0xff, 0x8c, 0xf9, 0xd3 },
{ 0x83, 0x69, 0xe1, 0xa9, 0x65, 0x61, 0x0b, 0xe8, 0x87, 0xfb, 0xd0, 0xc7, 0x91, 0x62, 0xaa, 0xfb },
{ 0x0a, 0x01, 0x27, 0xab, 0xb4, 0x44, 0x84, 0xb9, 0xfb, 0xef, 0x5a, 0xbc, 0xae, 0x1b, 0x57, 0x9f },
{ 0xc2, 0xcd, 0xad, 0xc6, 0x40, 0x2e, 0x8e, 0xe8, 0x66, 0xe1, 0xf3, 0x7b, 0xdb, 0x47, 0xe4, 0x2c },
{ 0x26, 0xb5, 0x1e, 0xa3, 0x7d, 0xf8, 0xe1, 0xd6, 0xf7, 0x6f, 0xc3, 0xb6, 0x6a, 0x74, 0x29, 0xb3 },
{ 0xbc, 0x76, 0x83, 0x20, 0x5d, 0x4f, 0x44, 0x3d, 0xc1, 0xf2, 0x9d, 0xda, 0x33, 0x15, 0xc8, 0x7b },
{ 0xd5, 0xfa, 0x5a, 0x34, 0x69, 0xd2, 0x9a, 0xaa, 0xf8, 0x3d, 0x23, 0x58, 0x9d, 0xb8, 0xc8, 0x5b },
{ 0x3f, 0xb4, 0x6e, 0x2c, 0x8f, 0x0f, 0x06, 0x8e, 0xdc, 0xe8, 0xcd, 0xcd, 0x7d, 0xfc, 0x58, 0x62 },
}
},
{
{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a },
{
{ 0xed, 0xe3, 0xb0, 0x46, 0x43, 0xe5, 0x86, 0xcc, 0x90, 0x7d, 0xc2, 0x18, 0x51, 0x70, 0x99, 0x02, },
{ 0x03, 0x51, 0x6b, 0xa7, 0x8f, 0x41, 0x3b, 0xeb, 0x22, 0x3a, 0xa5, 0xd4, 0xd2, 0xdf, 0x67, 0x11, },
{ 0x3c, 0xfd, 0x6c, 0xb5, 0x8e, 0xe0, 0xfd, 0xde, 0x64, 0x01, 0x76, 0xad, 0x00, 0x00, 0x04, 0x4d, },
{ 0x48, 0x53, 0x2b, 0x21, 0xfb, 0x60, 0x79, 0xc9, 0x11, 0x4c, 0x0f, 0xfd, 0x9c, 0x04, 0xa1, 0xad, },
{ 0x3e, 0x8c, 0xea, 0x98, 0x01, 0x71, 0x09, 0x97, 0x90, 0x84, 0xb1, 0xef, 0x92, 0xf9, 0x9d, 0x86, },
{ 0xe2, 0x0f, 0xb4, 0x9b, 0xdb, 0x33, 0x7e, 0xe4, 0x8b, 0x8d, 0x8d, 0xc0, 0xf4, 0xaf, 0xef, 0xfe, },
{ 0x5c, 0x25, 0x21, 0xea, 0xcd, 0x79, 0x66, 0xf1, 0x5e, 0x05, 0x65, 0x44, 0xbe, 0xa0, 0xd3, 0x15, },
{ 0xe0, 0x67, 0xa7, 0x03, 0x19, 0x31, 0xa2, 0x46, 0xa6, 0xc3, 0x87, 0x5d, 0x2f, 0x67, 0x8a, 0xcb, },
{ 0xa6, 0x4f, 0x70, 0xaf, 0x88, 0xae, 0x56, 0xb6, 0xf8, 0x75, 0x81, 0xc0, 0xe2, 0x3e, 0x6b, 0x08, },
{ 0xf4, 0x49, 0x03, 0x1d, 0xe3, 0x12, 0x81, 0x4e, 0xc6, 0xf3, 0x19, 0x29, 0x1f, 0x4a, 0x05, 0x16, },
{ 0xbd, 0xae, 0x85, 0x92, 0x4b, 0x3c, 0xb1, 0xd0, 0xa2, 0xe3, 0x3a, 0x30, 0xc6, 0xd7, 0x95, 0x99, },
{ 0x8a, 0x0f, 0xed, 0xdb, 0xac, 0x86, 0x5a, 0x09, 0xbc, 0xd1, 0x27, 0xfb, 0x56, 0x2e, 0xd6, 0x0a, },
{ 0xb5, 0x5a, 0x0a, 0x5b, 0x51, 0xa1, 0x2a, 0x8b, 0xe3, 0x48, 0x99, 0xc3, 0xe0, 0x47, 0x51, 0x1a, },
{ 0xd9, 0xa0, 0x9c, 0xea, 0x3c, 0xe7, 0x5f, 0xe3, 0x96, 0x98, 0x07, 0x03, 0x17, 0xa7, 0x13, 0x39, },
{ 0x55, 0x22, 0x25, 0xed, 0x11, 0x77, 0xf4, 0x45, 0x84, 0xac, 0x8c, 0xfa, 0x6c, 0x4e, 0xb5, 0xfc, },
{ 0x7e, 0x82, 0xcb, 0xab, 0xfc, 0x95, 0x38, 0x1b, 0x08, 0x09, 0x98, 0x44, 0x21, 0x29, 0xc2, 0xf8, },
{ 0x1f, 0x13, 0x5e, 0xd1, 0x4c, 0xe6, 0x0a, 0x91, 0x36, 0x9d, 0x23, 0x22, 0xbe, 0xf2, 0x5e, 0x3c, },
{ 0x08, 0xb6, 0xbe, 0x45, 0x12, 0x4a, 0x43, 0xe2, 0xeb, 0x77, 0x95, 0x3f, 0x84, 0xdc, 0x85, 0x53, },
}
},
{
{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 },
{
{ 0x9a, 0xc7, 0xcc, 0x9a, 0x60, 0x9d, 0x1e, 0xf7, 0xb2, 0x93, 0x28, 0x99, 0xcd, 0xe4, 0x1b, 0x97, },
{ 0x52, 0x48, 0xc4, 0x95, 0x90, 0x14, 0x12, 0x6a, 0x6e, 0x8a, 0x84, 0xf1, 0x1d, 0x1a, 0x9e, 0x1c, },
{ 0x06, 0x59, 0x02, 0xe4, 0xb6, 0x20, 0xf6, 0xcc, 0x36, 0xc8, 0x58, 0x9f, 0x66, 0x43, 0x2f, 0x2b, },
{ 0xd3, 0x9d, 0x56, 0x6b, 0xc6, 0xbc, 0xe3, 0x01, 0x07, 0x68, 0x15, 0x15, 0x49, 0xf3, 0x87, 0x3f, },
{ 0xb6, 0xd1, 0xe6, 0xc4, 0xa5, 0xe4, 0x77, 0x1c, 0xad, 0x79, 0x53, 0x8d, 0xf2, 0x95, 0xfb, 0x11, },
{ 0xc6, 0x8c, 0x1d, 0x5c, 0x55, 0x9a, 0x97, 0x41, 0x23, 0xdf, 0x1d, 0xbc, 0x52, 0xa4, 0x3b, 0x89, },
{ 0xc5, 0xec, 0xf8, 0x8d, 0xe8, 0x97, 0xfd, 0x57, 0xfe, 0xd3, 0x01, 0x70, 0x1b, 0x82, 0xa2, 0x59, },
{ 0xec, 0xcb, 0xe1, 0x3d, 0xe1, 0xfc, 0xc9, 0x1c, 0x11, 0xa0, 0xb2, 0x6c, 0x0b, 0xc8, 0xfa, 0x4d, },
{ 0xe7, 0xa7, 0x25, 0x74, 0xf8, 0x78, 0x2a, 0xe2, 0x6a, 0xab, 0xcf, 0x9e, 0xbc, 0xd6, 0x60, 0x65, },
{ 0xbd, 0xf0, 0x32, 0x4e, 0x60, 0x83, 0xdc, 0xc6, 0xd3, 0xce, 0xdd, 0x3c, 0xa8, 0xc5, 0x3c, 0x16, },
{ 0xb4, 0x01, 0x10, 0xc4, 0x19, 0x0b, 0x56, 0x22, 0xa9, 0x61, 0x16, 0xb0, 0x01, 0x7e, 0xd2, 0x97, },
{ 0xff, 0xa0, 0xb5, 0x14, 0x64, 0x7e, 0xc0, 0x4f, 0x63, 0x06, 0xb8, 0x92, 0xae, 0x66, 0x11, 0x81, },
{ 0xd0, 0x3d, 0x1b, 0xc0, 0x3c, 0xd3, 0x3d, 0x70, 0xdf, 0xf9, 0xfa, 0x5d, 0x71, 0x96, 0x3e, 0xbd, },
{ 0x8a, 0x44, 0x12, 0x64, 0x11, 0xea, 0xa7, 0x8b, 0xd5, 0x1e, 0x8d, 0x87, 0xa8, 0x87, 0x9b, 0xf5, },
{ 0xfa, 0xbe, 0xb7, 0x60, 0x28, 0xad, 0xe2, 0xd0, 0xe4, 0x87, 0x22, 0xe4, 0x6c, 0x46, 0x15, 0xa3, },
{ 0xc0, 0x5d, 0x88, 0xab, 0xd5, 0x03, 0x57, 0xf9, 0x35, 0xa6, 0x3c, 0x59, 0xee, 0x53, 0x76, 0x23, },
{ 0xff, 0x38, 0x26, 0x5c, 0x16, 0x42, 0xc1, 0xab, 0xe8, 0xd3, 0xc2, 0xfe, 0x5e, 0x57, 0x2b, 0xf8, },
{ 0xa3, 0x6a, 0x4c, 0x30, 0x1a, 0xe8, 0xac, 0x13, 0x61, 0x0c, 0xcb, 0xc1, 0x22, 0x56, 0xca, 0xcc, },
}
},
{
{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18 },
{
{ 0x05, 0x95, 0xe5, 0x7f, 0xe5, 0xf0, 0xbb, 0x3c, 0x70, 0x6e, 0xda, 0xc8, 0xa4, 0xb2, 0xdb, 0x11, },
{ 0xdf, 0xde, 0x31, 0x34, 0x4a, 0x1a, 0xf7, 0x69, 0xc7, 0x4f, 0x07, 0x0a, 0xee, 0x9e, 0x23, 0x26, },
{ 0xb0, 0x6b, 0x9b, 0x1e, 0x19, 0x5d, 0x13, 0xd8, 0xf4, 0xa7, 0x99, 0x5c, 0x45, 0x53, 0xac, 0x05, },
{ 0x6b, 0xd2, 0x37, 0x8e, 0xc3, 0x41, 0xc9, 0xa4, 0x2f, 0x37, 0xba, 0x79, 0xf8, 0x8a, 0x32, 0xff, },
{ 0xe7, 0x0b, 0xce, 0x1d, 0xf7, 0x64, 0x5a, 0xdb, 0x5d, 0x2c, 0x41, 0x30, 0x21, 0x5c, 0x35, 0x22, },
{ 0x9a, 0x57, 0x30, 0xc7, 0xfc, 0xb4, 0xc9, 0xaf, 0x51, 0xff, 0xda, 0x89, 0xc7, 0xf1, 0xad, 0x22, },
{ 0x04, 0x85, 0x05, 0x5f, 0xd4, 0xf6, 0xf0, 0xd9, 0x63, 0xef, 0x5a, 0xb9, 0xa5, 0x47, 0x69, 0x82, },
{ 0x59, 0x1f, 0xc6, 0x6b, 0xcd, 0xa1, 0x0e, 0x45, 0x2b, 0x03, 0xd4, 0x55, 0x1f, 0x6b, 0x62, 0xac, },
{ 0x27, 0x53, 0xcc, 0x83, 0x98, 0x8a, 0xfa, 0x3e, 0x16, 0x88, 0xa1, 0xd3, 0xb4, 0x2c, 0x9a, 0x02, },
{ 0x93, 0x61, 0x0d, 0x52, 0x3d, 0x1d, 0x3f, 0x00, 0x62, 0xb3, 0xc2, 0xa3, 0xbb, 0xc7, 0xc7, 0xf0, },
{ 0x96, 0xc2, 0x48, 0x61, 0x0a, 0xad, 0xed, 0xfe, 0xaf, 0x89, 0x78, 0xc0, 0x3d, 0xe8, 0x20, 0x5a, },
{ 0x0e, 0x31, 0x7b, 0x3d, 0x1c, 0x73, 0xb9, 0xe9, 0xa4, 0x68, 0x8f, 0x29, 0x6d, 0x13, 0x3a, 0x19, },
{ 0xbd, 0xf0, 0xe6, 0xc3, 0xcc, 0xa5, 0xb5, 0xb9, 0xd5, 0x33, 0xb6, 0x9c, 0x56, 0xad, 0xa1, 0x20, },
{ 0x88, 0xa2, 0x18, 0xb6, 0xe2, 0xec, 0xe1, 0xe6, 0x24, 0x6d, 0x44, 0xc7, 0x59, 0xd1, 0x9b, 0x10, },
{ 0x68, 0x66, 0x39, 0x7e, 0x95, 0xc1, 0x40, 0x53, 0x4f, 0x94, 0x26, 0x34, 0x21, 0x00, 0x6e, 0x40, },
{ 0x32, 0xcb, 0x0a, 0x1e, 0x95, 0x42, 0xc6, 0xb3, 0xb8, 0xb3, 0x98, 0xab, 0xc3, 0xb0, 0xf1, 0xd5, },
{ 0x29, 0xa0, 0xb8, 0xae, 0xd5, 0x4a, 0x13, 0x23, 0x24, 0xc6, 0x2e, 0x42, 0x3f, 0x54, 0xb4, 0xc8, },
{ 0x3c, 0xb0, 0xf3, 0xb5, 0x02, 0x0a, 0x98, 0xb8, 0x2a, 0xf9, 0xfe, 0x15, 0x44, 0x84, 0xa1, 0x68, },
}
},
{
{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20 },
{
{ 0xea, 0xa6, 0xbd, 0x25, 0x88, 0x0b, 0xf9, 0x3d, 0x3f, 0x5d, 0x1e, 0x4c, 0xa2, 0x61, 0x1d, 0x91, },
{ 0xcf, 0xa4, 0x5c, 0x9f, 0x7e, 0x71, 0x4b, 0x54, 0xbd, 0xfa, 0x80, 0x02, 0x7c, 0xb1, 0x43, 0x80, },
{ 0x11, 0x4a, 0xe3, 0x44, 0xde, 0xd7, 0x1b, 0x35, 0xf2, 0xe6, 0x0f, 0xeb, 0xad, 0x72, 0x7f, 0xd8, },
{ 0x02, 0xe1, 0xe7, 0x05, 0x6b, 0x0f, 0x62, 0x39, 0x00, 0x49, 0x64, 0x22, 0x94, 0x3e, 0x97, 0xb6, },
{ 0x91, 0xcb, 0x93, 0xc7, 0x87, 0x96, 0x4e, 0x10, 0xd9, 0x52, 0x7d, 0x99, 0x9c, 0x6f, 0x93, 0x6b, },
{ 0x49, 0xb1, 0x8b, 0x42, 0xf8, 0xe8, 0x36, 0x7c, 0xbe, 0xb5, 0xef, 0x10, 0x4b, 0xa1, 0xc7, 0xcd, },
{ 0x87, 0x08, 0x4b, 0x3b, 0xa7, 0x00, 0xba, 0xde, 0x95, 0x56, 0x10, 0x67, 0x27, 0x45, 0xb3, 0x74, },
{ 0xe7, 0xa7, 0xb9, 0xe9, 0xec, 0x54, 0x0d, 0x5f, 0xf4, 0x3b, 0xdb, 0x12, 0x79, 0x2d, 0x1b, 0x35, },
{ 0xc7, 0x99, 0xb5, 0x96, 0x73, 0x8f, 0x6b, 0x01, 0x8c, 0x76, 0xc7, 0x4b, 0x17, 0x59, 0xbd, 0x90, },
{ 0x7f, 0xec, 0x5b, 0xfd, 0x9f, 0x9b, 0x89, 0xce, 0x65, 0x48, 0x30, 0x90, 0x92, 0xd7, 0xe9, 0x58, },
{ 0x40, 0xf2, 0x50, 0xb2, 0x6d, 0x1f, 0x09, 0x6a, 0x4a, 0xfd, 0x4c, 0x34, 0x0a, 0x58, 0x88, 0x15, },
{ 0x3e, 0x34, 0x13, 0x5c, 0x79, 0xdb, 0x01, 0x02, 0x00, 0x76, 0x76, 0x51, 0xcf, 0x26, 0x30, 0x73, },
{ 0xf6, 0x56, 0xab, 0xcc, 0xf8, 0x8d, 0xd8, 0x27, 0x02, 0x7b, 0x2c, 0xe9, 0x17, 0xd4, 0x64, 0xec, },
{ 0x18, 0xb6, 0x25, 0x03, 0xbf, 0xbc, 0x07, 0x7f, 0xba, 0xbb, 0x98, 0xf2, 0x0d, 0x98, 0xab, 0x34, },
{ 0x8a, 0xed, 0x95, 0xee, 0x5b, 0x0d, 0xcb, 0xfb, 0xef, 0x4e, 0xb2, 0x1d, 0x3a, 0x3f, 0x52, 0xf9, },
{ 0x62, 0x5a, 0x1a, 0xb0, 0x0e, 0xe3, 0x9a, 0x53, 0x27, 0x34, 0x6b, 0xdd, 0xb0, 0x1a, 0x9c, 0x18, },
{ 0xa1, 0x3a, 0x7c, 0x79, 0xc7, 0xe1, 0x19, 0xb5, 0xab, 0x02, 0x96, 0xab, 0x28, 0xc3, 0x00, 0xb9, },
{ 0xf3, 0xe4, 0xc0, 0xa2, 0xe0, 0x2d, 0x1d, 0x01, 0xf7, 0xf0, 0xa7, 0x46, 0x18, 0xaf, 0x2b, 0x48, },
}
},
{
{ 0x83, 0x32, 0x22, 0x77, 0x2a },
{
{ 0x80, 0xad, 0x97, 0xbd, 0xc9, 0x73, 0xdf, 0x8a, 0x2e, 0x87, 0x9e, 0x92, 0xa4, 0x97, 0xef, 0xda, },
{ 0x20, 0xf0, 0x60, 0xc2, 0xf2, 0xe5, 0x12, 0x65, 0x01, 0xd3, 0xd4, 0xfe, 0xa1, 0x0d, 0x5f, 0xc0, },
{ 0xfa, 0xa1, 0x48, 0xe9, 0x90, 0x46, 0x18, 0x1f, 0xec, 0x6b, 0x20, 0x85, 0xf3, 0xb2, 0x0e, 0xd9, },
{ 0xf0, 0xda, 0xf5, 0xba, 0xb3, 0xd5, 0x96, 0x83, 0x98, 0x57, 0x84, 0x6f, 0x73, 0xfb, 0xfe, 0x5a, },
{ 0x1c, 0x7e, 0x2f, 0xc4, 0x63, 0x92, 0x32, 0xfe, 0x29, 0x75, 0x84, 0xb2, 0x96, 0x99, 0x6b, 0xc8, },
{ 0x3d, 0xb9, 0xb2, 0x49, 0x40, 0x6c, 0xc8, 0xed, 0xff, 0xac, 0x55, 0xcc, 0xd3, 0x22, 0xba, 0x12, },
{ 0xe4, 0xf9, 0xf7, 0xe0, 0x06, 0x61, 0x54, 0xbb, 0xd1, 0x25, 0xb7, 0x45, 0x56, 0x9b, 0xc8, 0x97, },
{ 0x75, 0xd5, 0xef, 0x26, 0x2b, 0x44, 0xc4, 0x1a, 0x9c, 0xf6, 0x3a, 0xe1, 0x45, 0x68, 0xe1, 0xb9, },
{ 0x6d, 0xa4, 0x53, 0xdb, 0xf8, 0x1e, 0x82, 0x33, 0x4a, 0x3d, 0x88, 0x66, 0xcb, 0x50, 0xa1, 0xe3, },
{ 0x78, 0x28, 0xd0, 0x74, 0x11, 0x9c, 0xab, 0x5c, 0x22, 0xb2, 0x94, 0xd7, 0xa9, 0xbf, 0xa0, 0xbb, },
{ 0xad, 0xb8, 0x9c, 0xea, 0x9a, 0x15, 0xfb, 0xe6, 0x17, 0x29, 0x5b, 0xd0, 0x4b, 0x8c, 0xa0, 0x5c, },
{ 0x62, 0x51, 0xd8, 0x7f, 0xd4, 0xaa, 0xae, 0x9a, 0x7e, 0x4a, 0xd5, 0xc2, 0x17, 0xd3, 0xf3, 0x00, },
{ 0xe7, 0x11, 0x9b, 0xd6, 0xdd, 0x9b, 0x22, 0xaf, 0xe8, 0xf8, 0x95, 0x85, 0x43, 0x28, 0x81, 0xe2, },
{ 0x78, 0x5b, 0x60, 0xfd, 0x7e, 0xc4, 0xe9, 0xfc, 0xb6, 0x54, 0x5f, 0x35, 0x0d, 0x66, 0x0f, 0xab, },
{ 0xaf, 0xec, 0xc0, 0x37, 0xfd, 0xb7, 0xb0, 0x83, 0x8e, 0xb3, 0xd7, 0x0b, 0xcd, 0x26, 0x83, 0x82, },
{ 0xdb, 0xc1, 0xa7, 0xb4, 0x9d, 0x57, 0x35, 0x8c, 0xc9, 0xfa, 0x6d, 0x61, 0xd7, 0x3b, 0x7c, 0xf0, },
{ 0x63, 0x49, 0xd1, 0x26, 0xa3, 0x7a, 0xfc, 0xba, 0x89, 0x79, 0x4f, 0x98, 0x04, 0x91, 0x4f, 0xdc, },
{ 0xbf, 0x42, 0xc3, 0x01, 0x8c, 0x2f, 0x7c, 0x66, 0xbf, 0xde, 0x52, 0x49, 0x75, 0x76, 0x81, 0x15, },
}
},
{
{ 0x19, 0x10, 0x83, 0x32, 0x22, 0x77, 0x2a },
{
{ 0xbc, 0x92, 0x22, 0xdb, 0xd3, 0x27, 0x4d, 0x8f, 0xc6, 0x6d, 0x14, 0xcc, 0xbd, 0xa6, 0x69, 0x0b, },
{ 0x7a, 0xe6, 0x27, 0x41, 0x0c, 0x9a, 0x2b, 0xe6, 0x93, 0xdf, 0x5b, 0xb7, 0x48, 0x5a, 0x63, 0xe3, },
{ 0x3f, 0x09, 0x31, 0xaa, 0x03, 0xde, 0xfb, 0x30, 0x0f, 0x06, 0x01, 0x03, 0x82, 0x6f, 0x2a, 0x64, },
{ 0xbe, 0xaa, 0x9e, 0xc8, 0xd5, 0x9b, 0xb6, 0x81, 0x29, 0xf3, 0x02, 0x7c, 0x96, 0x36, 0x11, 0x81, },
{ 0x74, 0xe0, 0x4d, 0xb4, 0x6d, 0x28, 0x64, 0x8d, 0x7d, 0xee, 0x8a, 0x00, 0x64, 0xb0, 0x6c, 0xfe, },
{ 0x9b, 0x5e, 0x81, 0xc6, 0x2f, 0xe0, 0x23, 0xc5, 0x5b, 0xe4, 0x2f, 0x87, 0xbb, 0xf9, 0x32, 0xb8, },
{ 0xce, 0x17, 0x8f, 0xc1, 0x82, 0x6e, 0xfe, 0xcb, 0xc1, 0x82, 0xf5, 0x79, 0x99, 0xa4, 0x61, 0x40, },
{ 0x8b, 0xdf, 0x55, 0xcd, 0x55, 0x06, 0x1c, 0x06, 0xdb, 0xa6, 0xbe, 0x11, 0xde, 0x4a, 0x57, 0x8a, },
{ 0x62, 0x6f, 0x5f, 0x4d, 0xce, 0x65, 0x25, 0x01, 0xf3, 0x08, 0x7d, 0x39, 0xc9, 0x2c, 0xc3, 0x49, },
{ 0x42, 0xda, 0xac, 0x6a, 0x8f, 0x9a, 0xb9, 0xa7, 0xfd, 0x13, 0x7c, 0x60, 0x37, 0x82, 0x56, 0x82, },
{ 0xcc, 0x03, 0xfd, 0xb7, 0x91, 0x92, 0xa2, 0x07, 0x31, 0x2f, 0x53, 0xf5, 0xd4, 0xdc, 0x33, 0xd9, },
{ 0xf7, 0x0f, 0x14, 0x12, 0x2a, 0x1c, 0x98, 0xa3, 0x15, 0x5d, 0x28, 0xb8, 0xa0, 0xa8, 0xa4, 0x1d, },
{ 0x2a, 0x3a, 0x30, 0x7a, 0xb2, 0x70, 0x8a, 0x9c, 0x00, 0xfe, 0x0b, 0x42, 0xf9, 0xc2, 0xd6, 0xa1, },
{ 0x86, 0x26, 0x17, 0x62, 0x7d, 0x22, 0x61, 0xea, 0xb0, 0xb1, 0x24, 0x65, 0x97, 0xca, 0x0a, 0xe9, },
{ 0x55, 0xf8, 0x77, 0xce, 0x4f, 0x2e, 0x1d, 0xdb, 0xbf, 0x8e, 0x13, 0xe2, 0xcd, 0xe0, 0xfd, 0xc8, },
{ 0x1b, 0x15, 0x56, 0xcb, 0x93, 0x5f, 0x17, 0x33, 0x37, 0x70, 0x5f, 0xbb, 0x5d, 0x50, 0x1f, 0xc1, },
{ 0xec, 0xd0, 0xe9, 0x66, 0x02, 0xbe, 0x7f, 0x8d, 0x50, 0x92, 0x81, 0x6c, 0xcc, 0xf2, 0xc2, 0xe9, },
{ 0x02, 0x78, 0x81, 0xfa, 0xb4, 0x99, 0x3a, 0x1c, 0x26, 0x20, 0x24, 0xa9, 0x4f, 0xff, 0x3f, 0x61, },
}
},
{
{ 0x64, 0x19, 0x10, 0x83, 0x32, 0x22, 0x77, 0x2a },
{
{ 0xbb, 0xf6, 0x09, 0xde, 0x94, 0x13, 0x17, 0x2d, 0x07, 0x66, 0x0c, 0xb6, 0x80, 0x71, 0x69, 0x26, },
{ 0x46, 0x10, 0x1a, 0x6d, 0xab, 0x43, 0x11, 0x5d, 0x6c, 0x52, 0x2b, 0x4f, 0xe9, 0x36, 0x04, 0xa9, },
{ 0xcb, 0xe1, 0xff, 0xf2, 0x1c, 0x96, 0xf3, 0xee, 0xf6, 0x1e, 0x8f, 0xe0, 0x54, 0x2c, 0xbd, 0xf0, },
{ 0x34, 0x79, 0x38, 0xbf, 0xfa, 0x40, 0x09, 0xc5, 0x12, 0xcf, 0xb4, 0x03, 0x4b, 0x0d, 0xd1, 0xa7, },
{ 0x78, 0x67, 0xa7, 0x86, 0xd0, 0x0a, 0x71, 0x47, 0x90, 0x4d, 0x76, 0xdd, 0xf1, 0xe5, 0x20, 0xe3, },
{ 0x8d, 0x3e, 0x9e, 0x1c, 0xae, 0xfc, 0xcc, 0xb3, 0xfb, 0xf8, 0xd1, 0x8f, 0x64, 0x12, 0x0b, 0x32, },
{ 0x94, 0x23, 0x37, 0xf8, 0xfd, 0x76, 0xf0, 0xfa, 0xe8, 0xc5, 0x2d, 0x79, 0x54, 0x81, 0x06, 0x72, },
{ 0xb8, 0x54, 0x8c, 0x10, 0xf5, 0x16, 0x67, 0xf6, 0xe6, 0x0e, 0x18, 0x2f, 0xa1, 0x9b, 0x30, 0xf7, },
{ 0x02, 0x11, 0xc7, 0xc6, 0x19, 0x0c, 0x9e, 0xfd, 0x12, 0x37, 0xc3, 0x4c, 0x8f, 0x2e, 0x06, 0xc4, },
{ 0xbd, 0xa6, 0x4f, 0x65, 0x27, 0x6d, 0x2a, 0xac, 0xb8, 0xf9, 0x02, 0x12, 0x20, 0x3a, 0x80, 0x8e, },
{ 0xbd, 0x38, 0x20, 0xf7, 0x32, 0xff, 0xb5, 0x3e, 0xc1, 0x93, 0xe7, 0x9d, 0x33, 0xe2, 0x7c, 0x73, },
{ 0xd0, 0x16, 0x86, 0x16, 0x86, 0x19, 0x07, 0xd4, 0x82, 0xe3, 0x6c, 0xda, 0xc8, 0xcf, 0x57, 0x49, },
{ 0x97, 0xb0, 0xf0, 0xf2, 0x24, 0xb2, 0xd2, 0x31, 0x71, 0x14, 0x80, 0x8f, 0xb0, 0x3a, 0xf7, 0xa0, },
{ 0xe5, 0x96, 0x16, 0xe4, 0x69, 0x78, 0x79, 0x39, 0xa0, 0x63, 0xce, 0xea, 0x9a, 0xf9, 0x56, 0xd1, },
{ 0xc4, 0x7e, 0x0d, 0xc1, 0x66, 0x09, 0x19, 0xc1, 0x11, 0x01, 0x20, 0x8f, 0x9e, 0x69, 0xaa, 0x1f, },
{ 0x5a, 0xe4, 0xf1, 0x28, 0x96, 0xb8, 0x37, 0x9a, 0x2a, 0xad, 0x89, 0xb5, 0xb5, 0x53, 0xd6, 0xb0, },
{ 0x6b, 0x6b, 0x09, 0x8d, 0x0c, 0x29, 0x3b, 0xc2, 0x99, 0x3d, 0x80, 0xbf, 0x05, 0x18, 0xb6, 0xd9, },
{ 0x81, 0x70, 0xcc, 0x3c, 0xcd, 0x92, 0xa6, 0x98, 0x62, 0x1b, 0x93, 0x9d, 0xd3, 0x8f, 0xe7, 0xb9, },
}
},
{
{ 0x8b, 0x37, 0x64, 0x19, 0x10, 0x83, 0x32, 0x22, 0x77, 0x2a },
{
{ 0xab, 0x65, 0xc2, 0x6e, 0xdd, 0xb2, 0x87, 0x60, 0x0d, 0xb2, 0xfd, 0xa1, 0x0d, 0x1e, 0x60, 0x5c, },
{ 0xbb, 0x75, 0x90, 0x10, 0xc2, 0x96, 0x58, 0xf2, 0xc7, 0x2d, 0x93, 0xa2, 0xd1, 0x6d, 0x29, 0x30, },
{ 0xb9, 0x01, 0xe8, 0x03, 0x6e, 0xd1, 0xc3, 0x83, 0xcd, 0x3c, 0x4c, 0x4d, 0xd0, 0xa6, 0xab, 0x05, },
{ 0x3d, 0x25, 0xce, 0x49, 0x22, 0x92, 0x4c, 0x55, 0xf0, 0x64, 0x94, 0x33, 0x53, 0xd7, 0x8a, 0x6c, },
{ 0x12, 0xc1, 0xaa, 0x44, 0xbb, 0xf8, 0x7e, 0x75, 0xe6, 0x11, 0xf6, 0x9b, 0x2c, 0x38, 0xf4, 0x9b, },
{ 0x28, 0xf2, 0xb3, 0x43, 0x4b, 0x65, 0xc0, 0x98, 0x77, 0x47, 0x00, 0x44, 0xc6, 0xea, 0x17, 0x0d, },
{ 0xbd, 0x9e, 0xf8, 0x22, 0xde, 0x52, 0x88, 0x19, 0x61, 0x34, 0xcf, 0x8a, 0xf7, 0x83, 0x93, 0x04, },
{ 0x67, 0x55, 0x9c, 0x23, 0xf0, 0x52, 0x15, 0x84, 0x70, 0xa2, 0x96, 0xf7, 0x25, 0x73, 0x5a, 0x32, },
{ 0x8b, 0xab, 0x26, 0xfb, 0xc2, 0xc1, 0x2b, 0x0f, 0x13, 0xe2, 0xab, 0x18, 0x5e, 0xab, 0xf2, 0x41, },
{ 0x31, 0x18, 0x5a, 0x6d, 0x69, 0x6f, 0x0c, 0xfa, 0x9b, 0x42, 0x80, 0x8b, 0x38, 0xe1, 0x32, 0xa2, },
{ 0x56, 0x4d, 0x3d, 0xae, 0x18, 0x3c, 0x52, 0x34, 0xc8, 0xaf, 0x1e, 0x51, 0x06, 0x1c, 0x44, 0xb5, },
{ 0x3c, 0x07, 0x78, 0xa7, 0xb5, 0xf7, 0x2d, 0x3c, 0x23, 0xa3, 0x13, 0x5c, 0x7d, 0x67, 0xb9, 0xf4, },
{ 0xf3, 0x43, 0x69, 0x89, 0x0f, 0xcf, 0x16, 0xfb, 0x51, 0x7d, 0xca, 0xae, 0x44, 0x63, 0xb2, 0xdd, },
{ 0x02, 0xf3, 0x1c, 0x81, 0xe8, 0x20, 0x07, 0x31, 0xb8, 0x99, 0xb0, 0x28, 0xe7, 0x91, 0xbf, 0xa7, },
{ 0x72, 0xda, 0x64, 0x62, 0x83, 0x22, 0x8c, 0x14, 0x30, 0x08, 0x53, 0x70, 0x17, 0x95, 0x61, 0x6f, },
{ 0x4e, 0x0a, 0x8c, 0x6f, 0x79, 0x34, 0xa7, 0x88, 0xe2, 0x26, 0x5e, 0x81, 0xd6, 0xd0, 0xc8, 0xf4, },
{ 0x43, 0x8d, 0xd5, 0xea, 0xfe, 0xa0, 0x11, 0x1b, 0x6f, 0x36, 0xb4, 0xb9, 0x38, 0xda, 0x2a, 0x68, },
{ 0x5f, 0x6b, 0xfc, 0x73, 0x81, 0x58, 0x74, 0xd9, 0x71, 0x00, 0xf0, 0x86, 0x97, 0x93, 0x57, 0xd8, },
}
},
{
{ 0xeb, 0xb4, 0x62, 0x27, 0xc6, 0xcc, 0x8b, 0x37, 0x64, 0x19, 0x10, 0x83, 0x32, 0x22, 0x77, 0x2a },
{
{ 0x72, 0x0c, 0x94, 0xb6, 0x3e, 0xdf, 0x44, 0xe1, 0x31, 0xd9, 0x50, 0xca, 0x21, 0x1a, 0x5a, 0x30, },
{ 0xc3, 0x66, 0xfd, 0xea, 0xcf, 0x9c, 0xa8, 0x04, 0x36, 0xbe, 0x7c, 0x35, 0x84, 0x24, 0xd2, 0x0b, },
{ 0xb3, 0x39, 0x4a, 0x40, 0xaa, 0xbf, 0x75, 0xcb, 0xa4, 0x22, 0x82, 0xef, 0x25, 0xa0, 0x05, 0x9f, },
{ 0x48, 0x47, 0xd8, 0x1d, 0xa4, 0x94, 0x2d, 0xbc, 0x24, 0x9d, 0xef, 0xc4, 0x8c, 0x92, 0x2b, 0x9f, },
{ 0x08, 0x12, 0x8c, 0x46, 0x9f, 0x27, 0x53, 0x42, 0xad, 0xda, 0x20, 0x2b, 0x2b, 0x58, 0xda, 0x95, },
{ 0x97, 0x0d, 0xac, 0xef, 0x40, 0xad, 0x98, 0x72, 0x3b, 0xac, 0x5d, 0x69, 0x55, 0xb8, 0x17, 0x61, },
{ 0x3c, 0xb8, 0x99, 0x93, 0xb0, 0x7b, 0x0c, 0xed, 0x93, 0xde, 0x13, 0xd2, 0xa1, 0x10, 0x13, 0xac, },
{ 0xef, 0x2d, 0x67, 0x6f, 0x15, 0x45, 0xc2, 0xc1, 0x3d, 0xc6, 0x80, 0xa0, 0x2f, 0x4a, 0xdb, 0xfe, },
{ 0xb6, 0x05, 0x95, 0x51, 0x4f, 0x24, 0xbc, 0x9f, 0xe5, 0x22, 0xa6, 0xca, 0xd7, 0x39, 0x36, 0x44, },
{ 0xb5, 0x15, 0xa8, 0xc5, 0x01, 0x17, 0x54, 0xf5, 0x90, 0x03, 0x05, 0x8b, 0xdb, 0x81, 0x51, 0x4e, },
{ 0x3c, 0x70, 0x04, 0x7e, 0x8c, 0xbc, 0x03, 0x8e, 0x3b, 0x98, 0x20, 0xdb, 0x60, 0x1d, 0xa4, 0x95, },
{ 0x11, 0x75, 0xda, 0x6e, 0xe7, 0x56, 0xde, 0x46, 0xa5, 0x3e, 0x2b, 0x07, 0x56, 0x60, 0xb7, 0x70, },
{ 0x00, 0xa5, 0x42, 0xbb, 0xa0, 0x21, 0x11, 0xcc, 0x2c, 0x65, 0xb3, 0x8e, 0xbd, 0xba, 0x58, 0x7e, },
{ 0x58, 0x65, 0xfd, 0xbb, 0x5b, 0x48, 0x06, 0x41, 0x04, 0xe8, 0x30, 0xb3, 0x80, 0xf2, 0xae, 0xde, },
{ 0x34, 0xb2, 0x1a, 0xd2, 0xad, 0x44, 0xe9, 0x99, 0xdb, 0x2d, 0x7f, 0x08, 0x63, 0xf0, 0xd9, 0xb6, },
{ 0x84, 0xa9, 0x21, 0x8f, 0xc3, 0x6e, 0x8a, 0x5f, 0x2c, 0xcf, 0xbe, 0xae, 0x53, 0xa2, 0x7d, 0x25, },
{ 0xa2, 0x22, 0x1a, 0x11, 0xb8, 0x33, 0xcc, 0xb4, 0x98, 0xa5, 0x95, 0x40, 0xf0, 0x54, 0x5f, 0x4a, },
{ 0x5b, 0xbe, 0xb4, 0x78, 0x7d, 0x59, 0xe5, 0x37, 0x3f, 0xdb, 0xea, 0x6c, 0x6f, 0x75, 0xc2, 0x9b, },
}
},
{
{ 0xc1, 0x09, 0x16, 0x39, 0x08, 0xeb, 0xe5, 0x1d, 0xeb, 0xb4, 0x62, 0x27, 0xc6, 0xcc, 0x8b, 0x37, 0x64, 0x19, 0x10, 0x83, 0x32, 0x22, 0x77, 0x2a },
{
{ 0x54, 0xb6, 0x4e, 0x6b, 0x5a, 0x20, 0xb5, 0xe2, 0xec, 0x84, 0x59, 0x3d, 0xc7, 0x98, 0x9d, 0xa7, },
{ 0xc1, 0x35, 0xee, 0xe2, 0x37, 0xa8, 0x54, 0x65, 0xff, 0x97, 0xdc, 0x03, 0x92, 0x4f, 0x45, 0xce, },
{ 0xcf, 0xcc, 0x92, 0x2f, 0xb4, 0xa1, 0x4a, 0xb4, 0x5d, 0x61, 0x75, 0xaa, 0xbb, 0xf2, 0xd2, 0x01, },
{ 0x83, 0x7b, 0x87, 0xe2, 0xa4, 0x46, 0xad, 0x0e, 0xf7, 0x98, 0xac, 0xd0, 0x2b, 0x94, 0x12, 0x4f, },
{ 0x17, 0xa6, 0xdb, 0xd6, 0x64, 0x92, 0x6a, 0x06, 0x36, 0xb3, 0xf4, 0xc3, 0x7a, 0x4f, 0x46, 0x94, },
{ 0x4a, 0x5f, 0x9f, 0x26, 0xae, 0xee, 0xd4, 0xd4, 0xa2, 0x5f, 0x63, 0x2d, 0x30, 0x52, 0x33, 0xd9, },
{ 0x80, 0xa3, 0xd0, 0x1e, 0xf0, 0x0c, 0x8e, 0x9a, 0x42, 0x09, 0xc1, 0x7f, 0x4e, 0xeb, 0x35, 0x8c, },
{ 0xd1, 0x5e, 0x7d, 0x5f, 0xfa, 0xaa, 0xbc, 0x02, 0x07, 0xbf, 0x20, 0x0a, 0x11, 0x77, 0x93, 0xa2, },
{ 0x34, 0x96, 0x82, 0xbf, 0x58, 0x8e, 0xaa, 0x52, 0xd0, 0xaa, 0x15, 0x60, 0x34, 0x6a, 0xea, 0xfa, },
{ 0xf5, 0x85, 0x4c, 0xdb, 0x76, 0xc8, 0x89, 0xe3, 0xad, 0x63, 0x35, 0x4e, 0x5f, 0x72, 0x75, 0xe3, },
{ 0x53, 0x2c, 0x7c, 0xec, 0xcb, 0x39, 0xdf, 0x32, 0x36, 0x31, 0x84, 0x05, 0xa4, 0xb1, 0x27, 0x9c, },
{ 0xba, 0xef, 0xe6, 0xd9, 0xce, 0xb6, 0x51, 0x84, 0x22, 0x60, 0xe0, 0xd1, 0xe0, 0x5e, 0x3b, 0x90, },
{ 0xe8, 0x2d, 0x8c, 0x6d, 0xb5, 0x4e, 0x3c, 0x63, 0x3f, 0x58, 0x1c, 0x95, 0x2b, 0xa0, 0x42, 0x07, },
{ 0x4b, 0x16, 0xe5, 0x0a, 0xbd, 0x38, 0x1b, 0xd7, 0x09, 0x00, 0xa9, 0xcd, 0x9a, 0x62, 0xcb, 0x23, },
{ 0x36, 0x82, 0xee, 0x33, 0xbd, 0x14, 0x8b, 0xd9, 0xf5, 0x86, 0x56, 0xcd, 0x8f, 0x30, 0xd9, 0xfb, },
{ 0x1e, 0x5a, 0x0b, 0x84, 0x75, 0x04, 0x5d, 0x9b, 0x20, 0xb2, 0x62, 0x86, 0x24, 0xed, 0xfd, 0x9e, },
{ 0x63, 0xed, 0xd6, 0x84, 0xfb, 0x82, 0x62, 0x82, 0xfe, 0x52, 0x8f, 0x9c, 0x0e, 0x92, 0x37, 0xbc, },
{ 0xe4, 0xdd, 0x2e, 0x98, 0xd6, 0x96, 0x0f, 0xae, 0x0b, 0x43, 0x54, 0x54, 0x56, 0x74, 0x33, 0x91, },
}
},
{
{ 0x1a, 0xda, 0x31, 0xd5, 0xcf, 0x68, 0x82, 0x21, 0xc1, 0x09, 0x16, 0x39, 0x08, 0xeb, 0xe5, 0x1d, 0xeb, 0xb4, 0x62, 0x27, 0xc6, 0xcc, 0x8b, 0x37, 0x64, 0x19, 0x10, 0x83, 0x32, 0x22, 0x77, 0x2a },
{
{ 0xdd, 0x5b, 0xcb, 0x00, 0x18, 0xe9, 0x22, 0xd4, 0x94, 0x75, 0x9d, 0x7c, 0x39, 0x5d, 0x02, 0xd3, },
{ 0xc8, 0x44, 0x6f, 0x8f, 0x77, 0xab, 0xf7, 0x37, 0x68, 0x53, 0x53, 0xeb, 0x89, 0xa1, 0xc9, 0xeb, },
{ 0xaf, 0x3e, 0x30, 0xf9, 0xc0, 0x95, 0x04, 0x59, 0x38, 0x15, 0x15, 0x75, 0xc3, 0xfb, 0x90, 0x98, },
{ 0xf8, 0xcb, 0x62, 0x74, 0xdb, 0x99, 0xb8, 0x0b, 0x1d, 0x20, 0x12, 0xa9, 0x8e, 0xd4, 0x8f, 0x0e, },
{ 0x25, 0xc3, 0x00, 0x5a, 0x1c, 0xb8, 0x5d, 0xe0, 0x76, 0x25, 0x98, 0x39, 0xab, 0x71, 0x98, 0xab, },
{ 0x9d, 0xcb, 0xc1, 0x83, 0xe8, 0xcb, 0x99, 0x4b, 0x72, 0x7b, 0x75, 0xbe, 0x31, 0x80, 0x76, 0x9c, },
{ 0xa1, 0xd3, 0x07, 0x8d, 0xfa, 0x91, 0x69, 0x50, 0x3e, 0xd9, 0xd4, 0x49, 0x1d, 0xee, 0x4e, 0xb2, },
{ 0x85, 0x14, 0xa5, 0x49, 0x58, 0x58, 0x09, 0x6f, 0x59, 0x6e, 0x4b, 0xcd, 0x66, 0xb1, 0x06, 0x65, },
{ 0x5f, 0x40, 0xd5, 0x9e, 0xc1, 0xb0, 0x3b, 0x33, 0x73, 0x8e, 0xfa, 0x60, 0xb2, 0x25, 0x5d, 0x31, },
{ 0x34, 0x77, 0xc7, 0xf7, 0x64, 0xa4, 0x1b, 0xac, 0xef, 0xf9, 0x0b, 0xf1, 0x4f, 0x92, 0xb7, 0xcc, },
{ 0xac, 0x4e, 0x95, 0x36, 0x8d, 0x99, 0xb9, 0xeb, 0x78, 0xb8, 0xda, 0x8f, 0x81, 0xff, 0xa7, 0x95, },
{ 0x8c, 0x3c, 0x13, 0xf8, 0xc2, 0x38, 0x8b, 0xb7, 0x3f, 0x38, 0x57, 0x6e, 0x65, 0xb7, 0xc4, 0x46, },
{ 0x13, 0xc4, 0xb9, 0xc1, 0xdf, 0xb6, 0x65, 0x79, 0xed, 0xdd, 0x8a, 0x28, 0x0b, 0x9f, 0x73, 0x16, },
{ 0xdd, 0xd2, 0x78, 0x20, 0x55, 0x01, 0x26, 0x69, 0x8e, 0xfa, 0xad, 0xc6, 0x4b, 0x64, 0xf6, 0x6e, },
{ 0xf0, 0x8f, 0x2e, 0x66, 0xd2, 0x8e, 0xd1, 0x43, 0xf3, 0xa2, 0x37, 0xcf, 0x9d, 0xe7, 0x35, 0x59, },
{ 0x9e, 0xa3, 0x6c, 0x52, 0x55, 0x31, 0xb8, 0x80, 0xba, 0x12, 0x43, 0x34, 0xf5, 0x7b, 0x0b, 0x70, },
{ 0xd5, 0xa3, 0x9e, 0x3d, 0xfc, 0xc5, 0x02, 0x80, 0xba, 0xc4, 0xa6, 0xb5, 0xaa, 0x0d, 0xca, 0x7d, },
{ 0x37, 0x0b, 0x1c, 0x1f, 0xe6, 0x55, 0x91, 0x6d, 0x97, 0xfd, 0x0d, 0x47, 0xca, 0x1d, 0x72, 0xb8, },
}
},
};
for (size_t i = 0; i < std::size (TESTS); ++i) {
const auto &t = TESTS[i];
RC4 gen (t.key.data (), t.key.size ());
uint8_t data[16];
size_t consumed = 0;
bool success = true;
for (size_t j = 0; j < std::size (OFFSETS); ++j) {
CHECK_GE (OFFSETS[j], consumed);
size_t diff = OFFSETS[j] - consumed;
gen.discard (diff);
consumed += diff;
gen.generate (data, 16);
consumed += 16;
success = success && std::equal (std::begin (data), std::end (data), std::begin (t.data[j]));
};
tap.expect (success, "ARC4 %zu", i);
}
return tap.status ();
}

249
test/stream/salsa.cpp Normal file
View File

@ -0,0 +1,249 @@
#include "stream/salsa.hpp"
#include <cruft/util/tap.hpp>
///////////////////////////////////////////////////////////////////////////////
void
test_quarter (util::TAP::logger &tap)
{
static const struct {
std::array<uint32_t, 4> a, b;
} TESTS[] = {
{ { 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
{ { 0x00000001, 0x00000000, 0x00000000, 0x00000000 },
{ 0x08008145, 0x00000080, 0x00010200, 0x20500000 } },
{ { 0x00000000, 0x00000001, 0x00000000, 0x00000000 },
{ 0x88000100, 0x00000001, 0x00000200, 0x00402000 } },
{ { 0x00000000, 0x00000000, 0x00000001, 0x00000000 },
{ 0x80040000, 0x00000000, 0x00000001, 0x00002000 } },
{ { 0x00000000, 0x00000000, 0x00000000, 0x00000001 },
{ 0x00048044, 0x00000080, 0x00010000, 0x20100001 } },
{ { 0xe7e8c006, 0xc4f9417d, 0x6479b4b2, 0x68c67137 },
{ 0xe876d72b, 0x9361dfd5, 0xf1460244, 0x948541a3 } },
{ { 0xd3917c5b, 0x55f1c407, 0x52a58a7a, 0x8f887a3b },
{ 0x3e2f308c, 0xd90a8f36, 0x6ab2a923, 0x2883524c } },
};
for (size_t i = 0; i < std::size (TESTS); ++i)
tap.expect_eq (
cruft::crypto::stream::salsa::quarter (TESTS[i].a),
TESTS[i].b,
"quarter %zu", i
);
}
///////////////////////////////////////////////////////////////////////////////
void
test_row (util::TAP::logger &tap)
{
static const struct {
std::array<uint32_t, 16> a, b;
} TESTS[] = {
{ { 0x00000001, 0x00000000, 0x00000000, 0x00000000,
0x00000001, 0x00000000, 0x00000000, 0x00000000,
0x00000001, 0x00000000, 0x00000000, 0x00000000,
0x00000001, 0x00000000, 0x00000000, 0x00000000, },
{ 0x08008145, 0x00000080, 0x00010200, 0x20500000,
0x20100001, 0x00048044, 0x00000080, 0x00010000,
0x00000001, 0x00002000, 0x80040000, 0x00000000,
0x00000001, 0x00000200, 0x00402000, 0x88000100, }
},
{ { 0x08521bd6, 0x1fe88837, 0xbb2aa576, 0x3aa26365,
0xc54c6a5b, 0x2fc74c2f, 0x6dd39cc3, 0xda0a64f6,
0x90a2f23d, 0x067f95a6, 0x06b35f61, 0x41e4732e,
0xe859c100, 0xea4d84b7, 0x0f619bff, 0xbc6e965a, },
{ 0xa890d39d, 0x65d71596, 0xe9487daa, 0xc8ca6a86,
0x949d2192, 0x764b7754, 0xe408d9b9, 0x7a41b4d1,
0x3402e183, 0x3c3af432, 0x50669f96, 0xd89ef0a8,
0x0040ede5, 0xb545fbce, 0xd257ed4f, 0x1818882d, },
}
};
for (size_t i = 0; i < std::size (TESTS); ++i)
tap.expect_eq (
cruft::crypto::stream::salsa::row (TESTS[i].a),
TESTS[i].b,
"row %zu",
i);
}
///////////////////////////////////////////////////////////////////////////////
void
test_col (util::TAP::logger &tap)
{
static const struct {
std::array<uint32_t,16> a, b;
} TESTS[] = {
{ { 0x00000001, 0x00000000, 0x00000000, 0x00000000,
0x00000001, 0x00000000, 0x00000000, 0x00000000,
0x00000001, 0x00000000, 0x00000000, 0x00000000,
0x00000001, 0x00000000, 0x00000000, 0x00000000, },
{ 0x10090288, 0x00000000, 0x00000000, 0x00000000,
0x00000101, 0x00000000, 0x00000000, 0x00000000,
0x00020401, 0x00000000, 0x00000000, 0x00000000,
0x40a04001, 0x00000000, 0x00000000, 0x00000000, } },
{ { 0x08521bd6, 0x1fe88837, 0xbb2aa576, 0x3aa26365,
0xc54c6a5b, 0x2fc74c2f, 0x6dd39cc3, 0xda0a64f6,
0x90a2f23d, 0x067f95a6, 0x06b35f61, 0x41e4732e,
0xe859c100, 0xea4d84b7, 0x0f619bff, 0xbc6e965a, },
{ 0x8c9d190a, 0xce8e4c90, 0x1ef8e9d3, 0x1326a71a,
0x90a20123, 0xead3c4f3, 0x63a091a0, 0xf0708d69,
0x789b010c, 0xd195a681, 0xeb7d5504, 0xa774135c,
0x481c2027, 0x53a8e4b5, 0x4c1f89c5, 0x3f78c9c8, } },
};
for (size_t i = 0; i < std::size (TESTS); ++i)
tap.expect_eq (
cruft::crypto::stream::salsa::col (TESTS[i].a),
TESTS[i].b,
"col %zu",
i);
}
///////////////////////////////////////////////////////////////////////////////
void
test_doubleround (util::TAP::logger &tap)
{
static const struct {
std::array<uint32_t,16> a, b;
} TESTS[] = {
{ { 0x00000001, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, },
{ 0x8186a22d, 0x0040a284, 0x82479210, 0x06929051,
0x08000090, 0x02402200, 0x00004000, 0x00800000,
0x00010200, 0x20400000, 0x08008104, 0x00000000,
0x20500000, 0xa0000040, 0x0008180a, 0x612a8020, } },
{ { 0xde501066, 0x6f9eb8f7, 0xe4fbbd9b, 0x454e3f57,
0xb75540d3, 0x43e93a4c, 0x3a6f2aa0, 0x726d6b36,
0x9243f484, 0x9145d1e8, 0x4fa9d247, 0xdc8dee11,
0x054bf545, 0x254dd653, 0xd9421b6d, 0x67b276c1, },
{ 0xccaaf672, 0x23d960f7, 0x9153e63a, 0xcd9a60d0,
0x50440492, 0xf07cad19, 0xae344aa0, 0xdf4cfdfc,
0xca531c29, 0x8e7943db, 0xac1680cd, 0xd503ca00,
0xa74b2ad6, 0xbc331c5c, 0x1dda24c7, 0xee928277, } }
};
for (size_t i = 0; i < std::size (TESTS); ++i)
tap.expect_eq (
cruft::crypto::stream::salsa::doubleround (TESTS[i].a),
TESTS[i].b,
"doubleround %zu",
i);
}
///////////////////////////////////////////////////////////////////////////////
void
test_salsa20 (util::TAP::logger &tap)
{
static const struct {
std::array<uint8_t,64> a, b;
} TESTS[] = {
{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
{ { 0xd3, 0x9f, 0x0d, 0x73, 0x4c, 0x37, 0x52, 0xb7,
0x03, 0x75, 0xde, 0x25, 0xbf, 0xbb, 0xea, 0x88,
0x31, 0xed, 0xb3, 0x30, 0x01, 0x6a, 0xb2, 0xdb,
0xaf, 0xc7, 0xa6, 0x30, 0x56, 0x10, 0xb3, 0xcf,
0x1f, 0xf0, 0x20, 0x3f, 0x0f, 0x53, 0x5d, 0xa1,
0x74, 0x93, 0x30, 0x71, 0xee, 0x37, 0xcc, 0x24,
0x4f, 0xc9, 0xeb, 0x4f, 0x03, 0x51, 0x9c, 0x2f,
0xcb, 0x1a, 0xf4, 0xf3, 0x58, 0x76, 0x68, 0x36 },
{ 0x6d, 0x2a, 0xb2, 0xa8, 0x9c, 0xf0, 0xf8, 0xee,
0xa8, 0xc4, 0xbe, 0xcb, 0x1a, 0x6e, 0xaa, 0x9a,
0x1d, 0x1d, 0x96, 0x1a, 0x96, 0x1e, 0xeb, 0xf9,
0xbe, 0xa3, 0xfb, 0x30, 0x45, 0x90, 0x33, 0x39,
0x76, 0x28, 0x98, 0x9d, 0xb4, 0x39, 0x1b, 0x5e,
0x6b, 0x2a, 0xec, 0x23, 0x1b, 0x6f, 0x72, 0x72,
0xdb, 0xec, 0xe8, 0x87, 0x6f, 0x9b, 0x6e, 0x12,
0x18, 0xe8, 0x5f, 0x9e, 0xb3, 0x13, 0x30, 0xca } },
{ { 0x58, 0x76, 0x68, 0x36, 0x4f, 0xc9, 0xeb, 0x4f,
0x03, 0x51, 0x9c, 0x2f, 0xcb, 0x1a, 0xf4, 0xf3,
0xbf, 0xbb, 0xea, 0x88, 0xd3, 0x9f, 0x0d, 0x73,
0x4c, 0x37, 0x52, 0xb7, 0x03, 0x75, 0xde, 0x25,
0x56, 0x10, 0xb3, 0xcf, 0x31, 0xed, 0xb3, 0x30,
0x01, 0x6a, 0xb2, 0xdb, 0xaf, 0xc7, 0xa6, 0x30,
0xee, 0x37, 0xcc, 0x24, 0x1f, 0xf0, 0x20, 0x3f,
0x0f, 0x53, 0x5d, 0xa1, 0x74, 0x93, 0x30, 0x71 },
{ 0xb3, 0x13, 0x30, 0xca, 0xdb, 0xec, 0xe8, 0x87,
0x6f, 0x9b, 0x6e, 0x12, 0x18, 0xe8, 0x5f, 0x9e,
0x1a, 0x6e, 0xaa, 0x9a, 0x6d, 0x2a, 0xb2, 0xa8,
0x9c, 0xf0, 0xf8, 0xee, 0xa8, 0xc4, 0xbe, 0xcb,
0x45, 0x90, 0x33, 0x39, 0x1d, 0x1d, 0x96, 0x1a,
0x96, 0x1e, 0xeb, 0xf9, 0xbe, 0xa3, 0xfb, 0x30,
0x1b, 0x6f, 0x72, 0x72, 0x76, 0x28, 0x98, 0x9d,
0xb4, 0x39, 0x1b, 0x5e, 0x6b, 0x2a, 0xec, 0x23 } }
};
for (size_t i = 0; i < std::size (TESTS); ++i)
tap.expect_eq (
cruft::crypto::stream::salsa20 (TESTS[i].a),
TESTS[i].b,
"salsa20 %zu",
i);
struct {
std::array<uint8_t,64> a, b;
} million = {
{ 0x06, 0x7c, 0x53, 0x92, 0x26, 0xbf, 0x09, 0x32,
0x04, 0xa1, 0x2f, 0xde, 0x7a, 0xb6, 0xdf, 0xb9,
0x4b, 0x1b, 0x00, 0xd8, 0x10, 0x7a, 0x07, 0x59,
0xa2, 0x68, 0x65, 0x93, 0xd5, 0x15, 0x36, 0x5f,
0xe1, 0xfd, 0x8b, 0xb0, 0x69, 0x84, 0x17, 0x74,
0x4c, 0x29, 0xb0, 0xcf, 0xdd, 0x22, 0x9d, 0x6c,
0x5e, 0x5e, 0x63, 0x34, 0x5a, 0x75, 0x5b, 0xdc,
0x92, 0xbe, 0xef, 0x8f, 0xc4, 0xb0, 0x82, 0xba },
{ 0x08, 0x12, 0x26, 0xc7, 0x77, 0x4c, 0xd7, 0x43,
0xad, 0x7f, 0x90, 0xa2, 0x67, 0xd4, 0xb0, 0xd9,
0xc0, 0x13, 0xe9, 0x21, 0x9f, 0xc5, 0x9a, 0xa0,
0x80, 0xf3, 0xdb, 0x41, 0xab, 0x88, 0x87, 0xe1,
0x7b, 0x0b, 0x44, 0x56, 0xed, 0x52, 0x14, 0x9b,
0x85, 0xbd, 0x09, 0x53, 0xa7, 0x74, 0xc2, 0x4e,
0x7a, 0x7f, 0xc3, 0xb9, 0xb9, 0xcc, 0xbc, 0x5a,
0xf5, 0x09, 0xb7, 0xf8, 0xe2, 0x55, 0xf5, 0x68 }
};
for (int i = 0; i < 1'000'000; ++i)
million.a = cruft::crypto::stream::salsa20 (million.a);
tap.expect_eq (million.a, million.b, "salsa20 million");
}
///////////////////////////////////////////////////////////////////////////////
int
main (void)
{
util::TAP::logger tap;
test_quarter (tap);
test_row (tap);
test_col (tap);
test_doubleround (tap);
test_salsa20 (tap);
return 0;
}

145
tools/hash.cpp Normal file
View File

@ -0,0 +1,145 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright:
* 2014-2016, Danny Robson <danny@nerdcruft.net>
*/
#include "../hash/md2.hpp"
#include "../hash/md4.hpp"
#include "../hash/md5.hpp"
#include "../hash/ripemd.hpp"
#include "../hash/sha1.hpp"
#include "../hash/sha2.hpp"
#include <cruft/util/hash/adler.hpp>
#include <cruft/util/hash/bsdsum.cpp>
#include <cruft/util/hash/crc.hpp>
#include <cruft/util/io.hpp>
#include <cruft/util/stream.hpp>
#include <iostream>
#include <cstdlib>
#include <cstring>
///////////////////////////////////////////////////////////////////////////////
static
const char* NAMES[] = {
"adler32",
"bsdsum",
"crc",
"MD2",
"MD4",
"MD5",
"RIPEMD",
"SHA1",
"SHA256",
};
///////////////////////////////////////////////////////////////////////////////
std::ostream&
print_digest (std::ostream &os, uint32_t t)
{
return os << std::hex << t << std::dec;
}
//-----------------------------------------------------------------------------
template <size_t S>
std::ostream&
print_digest (std::ostream &os, std::array<uint8_t,S> digest)
{
util::stream::scoped::flags f (os);
os << std::hex;
for (auto c: digest)
os << +(c >> 4) << +(c & 0x0F);
return os;
}
///////////////////////////////////////////////////////////////////////////////
static void
compute (const std::string &name, const util::view<const uint8_t*> data)
{
#define stream(TYPE, ...) do { \
if (name != #TYPE) \
break; \
\
print_digest ( \
std::cout, \
util::hash::TYPE{} (data) \
) << '\n'; \
return; \
} while (0);
stream (adler32);
//stream (bsdsum);
//stream (crc32);
//stream (MD2);
//stream (MD4);
//stream (MD5);
//stream (RIPEMD);
//stream (SHA1);
//stream (SHA256);
#undef stream
}
///////////////////////////////////////////////////////////////////////////////
enum {
ARG_CMD,
ARG_HASH,
ARG_INPUT,
NUM_ARGS
};
//-----------------------------------------------------------------------------
void
print_usage (int argc, char **argv)
{
(void)argc;
std::cerr << argv[ARG_CMD] << " [";
for (auto name: NAMES)
std::cerr << name << "|";
std::cerr << "] <input>\n";
}
//-----------------------------------------------------------------------------
int
main (int argc, char **argv)
{
if (argc != NUM_ARGS) {
print_usage (argc, argv);
return EXIT_FAILURE;
}
if (strcmp (argv[ARG_INPUT], "-")) {
const util::mapped_file src (argv[ARG_INPUT]);
compute (argv[ARG_HASH], util::view{src});
return EXIT_SUCCESS;
} else {
//compute (argv[ARG_HASH], std::cin);
return EXIT_SUCCESS;
}
}