Botan 3.4.0
Crypto and TLS for C&
skein_512.cpp
Go to the documentation of this file.
1/*
2* The Skein-512 hash function
3* (C) 2009,2010,2014 Jack Lloyd
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#include <botan/internal/skein_512.h>
9
10#include <botan/exceptn.h>
11#include <botan/internal/fmt.h>
12#include <botan/internal/loadstor.h>
13#include <botan/internal/stl_util.h>
14#include <algorithm>
15
16namespace Botan {
17
18Skein_512::Skein_512(size_t arg_output_bits, std::string_view arg_personalization) :
19 m_personalization(arg_personalization),
20 m_output_bits(arg_output_bits),
21 m_threefish(std::make_unique<Threefish_512>()),
22 m_T(2) {
23 if(m_output_bits == 0 || m_output_bits % 8 != 0 || m_output_bits > 512) {
24 throw Invalid_Argument("Bad output bits size for Skein-512");
25 }
26
27 initial_block();
28}
29
30std::string Skein_512::name() const {
31 if(m_personalization.empty()) {
32 return fmt("Skein-512({})", m_output_bits);
33 } else {
34 return fmt("Skein-512({},{})", m_output_bits, m_personalization);
35 }
36}
37
38std::unique_ptr<HashFunction> Skein_512::new_object() const {
39 return std::make_unique<Skein_512>(m_output_bits, m_personalization);
40}
41
42std::unique_ptr<HashFunction> Skein_512::copy_state() const {
43 auto copy = std::make_unique<Skein_512>(m_output_bits, m_personalization);
44 copy->m_threefish->m_K = this->m_threefish->m_K;
45 copy->m_T = this->m_T;
46 copy->m_buffer = this->m_buffer;
47 return copy;
48}
49
51 m_buffer.clear();
52
53 initial_block();
54}
55
56void Skein_512::reset_tweak(type_code type, bool is_final) {
57 m_T[0] = 0;
58
59 m_T[1] =
60 (static_cast<uint64_t>(type) << 56) | (static_cast<uint64_t>(1) << 62) | (static_cast<uint64_t>(is_final) << 63);
61}
62
63void Skein_512::initial_block() {
64 const uint8_t zeros[64] = {0};
65
66 m_threefish->set_key(zeros, sizeof(zeros));
67
68 // ASCII("SHA3") followed by version (0x0001) code
69 uint8_t config_str[32] = {0x53, 0x48, 0x41, 0x33, 0x01, 0x00, 0};
70 store_le(uint32_t(m_output_bits), config_str + 8);
71
72 reset_tweak(SKEIN_CONFIG, true);
73 ubi_512(config_str, sizeof(config_str));
74
75 if(!m_personalization.empty()) {
76 /*
77 This is a limitation of this implementation, and not of the
78 algorithm specification. Could be fixed relatively easily, but
79 doesn't seem worth the trouble.
80 */
81 if(m_personalization.length() > 64) {
82 throw Invalid_Argument("Skein personalization must be less than 64 bytes");
83 }
84
85 const uint8_t* bits = cast_char_ptr_to_uint8(m_personalization.data());
86 reset_tweak(SKEIN_PERSONALIZATION, true);
87 ubi_512(bits, m_personalization.length());
88 }
89
90 reset_tweak(SKEIN_MSG, false);
91}
92
93void Skein_512::ubi_512(const uint8_t msg[], size_t msg_len) {
94 secure_vector<uint64_t> M(8);
95
96 do {
97 const size_t to_proc = std::min<size_t>(msg_len, 64);
98 m_T[0] += to_proc;
99
100 load_le(M.data(), msg, to_proc / 8);
101
102 if(to_proc % 8) {
103 for(size_t j = 0; j != to_proc % 8; ++j) {
104 M[to_proc / 8] |= static_cast<uint64_t>(msg[8 * (to_proc / 8) + j]) << (8 * j);
105 }
106 }
107
108 m_threefish->skein_feedfwd(M, m_T);
109
110 // clear first flag if set
111 m_T[1] &= ~(static_cast<uint64_t>(1) << 62);
112
113 msg_len -= to_proc;
114 msg += to_proc;
115 } while(msg_len);
116}
117
118void Skein_512::add_data(std::span<const uint8_t> input) {
119 BufferSlicer in(input);
120
121 while(!in.empty()) {
122 if(const auto one_block = m_buffer.handle_unaligned_data(in)) {
123 ubi_512(one_block->data(), one_block->size());
124 }
125
126 if(m_buffer.in_alignment()) {
127 const auto [aligned_data, full_blocks] = m_buffer.aligned_data_to_process(in);
128 if(full_blocks > 0) {
129 ubi_512(aligned_data.data(), aligned_data.size());
130 }
131 }
132 }
133}
134
135void Skein_512::final_result(std::span<uint8_t> out) {
136 m_T[1] |= (static_cast<uint64_t>(1) << 63); // final block flag
137
138 const auto pos = m_buffer.elements_in_buffer();
139 m_buffer.fill_up_with_zeros();
140 ubi_512(m_buffer.consume().data(), pos);
141
142 const uint8_t counter[8] = {0};
143
144 reset_tweak(SKEIN_OUTPUT, true);
145 ubi_512(counter, sizeof(counter));
146
147 copy_out_le(out.first(m_output_bits / 8), m_threefish->m_K);
148
149 initial_block();
150}
151
152} // namespace Botan
size_t elements_in_buffer() const
std::tuple< std::span< const uint8_t >, size_t > aligned_data_to_process(BufferSlicer &slicer) const
std::optional< std::span< const T > > handle_unaligned_data(BufferSlicer &slicer)
std::span< const T > consume()
std::unique_ptr< HashFunction > copy_state() const override
Definition skein_512.cpp:42
std::unique_ptr< HashFunction > new_object() const override
Definition skein_512.cpp:38
std::string name() const override
Definition skein_512.cpp:30
Skein_512(size_t output_bits=512, std::string_view personalization="")
Definition skein_512.cpp:18
void clear() override
Definition skein_512.cpp:50
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53
constexpr auto store_le(ParamTs &&... params)
Definition loadstor.h:702
void copy_out_le(std::span< uint8_t > out, InR &&in)
Definition loadstor.h:755
constexpr auto load_le(ParamTs &&... params)
Definition loadstor.h:462
const uint8_t * cast_char_ptr_to_uint8(const char *s)
Definition mem_ops.h:275