Coverage Report

Created: 2023-02-13 06:21

/src/botan/src/lib/hash/skein/skein_512.cpp
Line
Count
Source (jump to first uncovered line)
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
#include <botan/internal/loadstor.h>
10
#include <botan/exceptn.h>
11
#include <algorithm>
12
13
namespace Botan {
14
15
Skein_512::Skein_512(size_t arg_output_bits,
16
                     const std::string& arg_personalization) :
17
   m_personalization(arg_personalization),
18
   m_output_bits(arg_output_bits),
19
   m_threefish(std::make_unique<Threefish_512>()),
20
   m_T(2), m_buffer(64), m_buf_pos(0)
21
0
   {
22
0
   if(m_output_bits == 0 || m_output_bits % 8 != 0 || m_output_bits > 512)
23
0
      throw Invalid_Argument("Bad output bits size for Skein-512");
24
25
0
   initial_block();
26
0
   }
27
28
std::string Skein_512::name() const
29
0
   {
30
0
   if(!m_personalization.empty())
31
0
      return "Skein-512(" + std::to_string(m_output_bits) + "," +
32
0
                            m_personalization + ")";
33
0
   return "Skein-512(" + std::to_string(m_output_bits) + ")";
34
0
   }
35
36
std::unique_ptr<HashFunction> Skein_512::new_object() const
37
0
   {
38
0
   return std::make_unique<Skein_512>(m_output_bits, m_personalization);
39
0
   }
40
41
std::unique_ptr<HashFunction> Skein_512::copy_state() const
42
0
   {
43
0
   auto copy = std::make_unique<Skein_512>(m_output_bits, m_personalization);
44
0
   copy->m_threefish->m_K = this->m_threefish->m_K;
45
0
   copy->m_T = this->m_T;
46
0
   copy->m_buffer = this->m_buffer;
47
0
   copy->m_buf_pos = this->m_buf_pos;
48
0
   return copy;
49
0
   }
50
51
void Skein_512::clear()
52
0
   {
53
0
   zeroise(m_buffer);
54
0
   m_buf_pos = 0;
55
56
0
   initial_block();
57
0
   }
58
59
void Skein_512::reset_tweak(type_code type, bool is_final)
60
0
   {
61
0
   m_T[0] = 0;
62
63
0
   m_T[1] = (static_cast<uint64_t>(type) << 56) |
64
0
          (static_cast<uint64_t>(1) << 62) |
65
0
          (static_cast<uint64_t>(is_final) << 63);
66
0
   }
67
68
void Skein_512::initial_block()
69
0
   {
70
0
   const uint8_t zeros[64] = { 0 };
71
72
0
   m_threefish->set_key(zeros, sizeof(zeros));
73
74
   // ASCII("SHA3") followed by version (0x0001) code
75
0
   uint8_t config_str[32] = { 0x53, 0x48, 0x41, 0x33, 0x01, 0x00, 0 };
76
0
   store_le(uint32_t(m_output_bits), config_str + 8);
77
78
0
   reset_tweak(SKEIN_CONFIG, true);
79
0
   ubi_512(config_str, sizeof(config_str));
80
81
0
   if(!m_personalization.empty())
82
0
      {
83
      /*
84
        This is a limitation of this implementation, and not of the
85
        algorithm specification. Could be fixed relatively easily, but
86
        doesn't seem worth the trouble.
87
      */
88
0
      if(m_personalization.length() > 64)
89
0
         throw Invalid_Argument("Skein personalization must be less than 64 bytes");
90
91
0
      const uint8_t* bits = cast_char_ptr_to_uint8(m_personalization.data());
92
0
      reset_tweak(SKEIN_PERSONALIZATION, true);
93
0
      ubi_512(bits, m_personalization.length());
94
0
      }
95
96
0
   reset_tweak(SKEIN_MSG, false);
97
0
   }
98
99
void Skein_512::ubi_512(const uint8_t msg[], size_t msg_len)
100
0
   {
101
0
   secure_vector<uint64_t> M(8);
102
103
0
   do
104
0
      {
105
0
      const size_t to_proc = std::min<size_t>(msg_len, 64);
106
0
      m_T[0] += to_proc;
107
108
0
      load_le(M.data(), msg, to_proc / 8);
109
110
0
      if(to_proc % 8)
111
0
         {
112
0
         for(size_t j = 0; j != to_proc % 8; ++j)
113
0
           M[to_proc/8] |= static_cast<uint64_t>(msg[8*(to_proc/8)+j]) << (8*j);
114
0
         }
115
116
0
      m_threefish->skein_feedfwd(M, m_T);
117
118
      // clear first flag if set
119
0
      m_T[1] &= ~(static_cast<uint64_t>(1) << 62);
120
121
0
      msg_len -= to_proc;
122
0
      msg += to_proc;
123
0
      } while(msg_len);
124
0
   }
125
126
void Skein_512::add_data(const uint8_t input[], size_t length)
127
0
   {
128
0
   if(length == 0)
129
0
      return;
130
131
0
   if(m_buf_pos)
132
0
      {
133
0
      buffer_insert(m_buffer, m_buf_pos, input, length);
134
0
      if(m_buf_pos + length > 64)
135
0
         {
136
0
         ubi_512(m_buffer.data(), m_buffer.size());
137
138
0
         input += (64 - m_buf_pos);
139
0
         length -= (64 - m_buf_pos);
140
0
         m_buf_pos = 0;
141
0
         }
142
0
      }
143
144
0
   const size_t full_blocks = (length - 1) / 64;
145
146
0
   if(full_blocks)
147
0
      ubi_512(input, 64*full_blocks);
148
149
0
   length -= full_blocks * 64;
150
151
0
   buffer_insert(m_buffer, m_buf_pos, input + full_blocks * 64, length);
152
0
   m_buf_pos += length;
153
0
   }
154
155
void Skein_512::final_result(uint8_t out[])
156
0
   {
157
0
   m_T[1] |= (static_cast<uint64_t>(1) << 63); // final block flag
158
159
0
   for(size_t i = m_buf_pos; i != m_buffer.size(); ++i)
160
0
      m_buffer[i] = 0;
161
162
0
   ubi_512(m_buffer.data(), m_buf_pos);
163
164
0
   const uint8_t counter[8] = { 0 };
165
166
0
   reset_tweak(SKEIN_OUTPUT, true);
167
0
   ubi_512(counter, sizeof(counter));
168
169
0
   copy_out_vec_le(out, m_output_bits / 8, m_threefish->m_K);
170
171
0
   m_buf_pos = 0;
172
0
   initial_block();
173
0
   }
174
175
}