Botan  2.15.0
Crypto and TLS for C++11
shacal2.cpp
Go to the documentation of this file.
1 /*
2 * SHACAL-2
3 * (C) 2017 Jack Lloyd
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7 
8 #include <botan/shacal2.h>
9 #include <botan/loadstor.h>
10 #include <botan/rotate.h>
11 #include <botan/cpuid.h>
12 
13 namespace Botan {
14 
15 namespace {
16 
17 inline void SHACAL2_Fwd(uint32_t A, uint32_t B, uint32_t C, uint32_t& D,
18  uint32_t E, uint32_t F, uint32_t G, uint32_t& H,
19  uint32_t RK)
20  {
21  const uint32_t A_rho = rotr<2>(A) ^ rotr<13>(A) ^ rotr<22>(A);
22  const uint32_t E_rho = rotr<6>(E) ^ rotr<11>(E) ^ rotr<25>(E);
23 
24  H += E_rho + ((E & F) ^ (~E & G)) + RK;
25  D += H;
26  H += A_rho + ((A & B) | ((A | B) & C));
27  }
28 
29 inline void SHACAL2_Rev(uint32_t A, uint32_t B, uint32_t C, uint32_t& D,
30  uint32_t E, uint32_t F, uint32_t G, uint32_t& H,
31  uint32_t RK)
32  {
33  const uint32_t A_rho = rotr<2>(A) ^ rotr<13>(A) ^ rotr<22>(A);
34  const uint32_t E_rho = rotr<6>(E) ^ rotr<11>(E) ^ rotr<25>(E);
35 
36  H -= A_rho + ((A & B) | ((A | B) & C));
37  D -= H;
38  H -= E_rho + ((E & F) ^ (~E & G)) + RK;
39  }
40 
41 }
42 
43 /*
44 * SHACAL2 Encryption
45 */
46 void SHACAL2::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const
47  {
48  verify_key_set(m_RK.empty() == false);
49 
50 #if defined(BOTAN_HAS_SHACAL2_X86)
51  if(CPUID::has_intel_sha())
52  {
53  return x86_encrypt_blocks(in, out, blocks);
54  }
55 #endif
56 
57 #if defined(BOTAN_HAS_SHACAL2_AVX2)
58  if(CPUID::has_avx2())
59  {
60  while(blocks >= 8)
61  {
62  avx2_encrypt_8(in, out);
63  in += 8*BLOCK_SIZE;
64  out += 8*BLOCK_SIZE;
65  blocks -= 8;
66  }
67  }
68 #endif
69 
70 #if defined(BOTAN_HAS_SHACAL2_SIMD)
71  if(CPUID::has_simd_32())
72  {
73  while(blocks >= 4)
74  {
75  simd_encrypt_4(in, out);
76  in += 4*BLOCK_SIZE;
77  out += 4*BLOCK_SIZE;
78  blocks -= 4;
79  }
80  }
81 #endif
82 
83  for(size_t i = 0; i != blocks; ++i)
84  {
85  uint32_t A = load_be<uint32_t>(in, 0);
86  uint32_t B = load_be<uint32_t>(in, 1);
87  uint32_t C = load_be<uint32_t>(in, 2);
88  uint32_t D = load_be<uint32_t>(in, 3);
89  uint32_t E = load_be<uint32_t>(in, 4);
90  uint32_t F = load_be<uint32_t>(in, 5);
91  uint32_t G = load_be<uint32_t>(in, 6);
92  uint32_t H = load_be<uint32_t>(in, 7);
93 
94  for(size_t r = 0; r != 64; r += 8)
95  {
96  SHACAL2_Fwd(A, B, C, D, E, F, G, H, m_RK[r+0]);
97  SHACAL2_Fwd(H, A, B, C, D, E, F, G, m_RK[r+1]);
98  SHACAL2_Fwd(G, H, A, B, C, D, E, F, m_RK[r+2]);
99  SHACAL2_Fwd(F, G, H, A, B, C, D, E, m_RK[r+3]);
100  SHACAL2_Fwd(E, F, G, H, A, B, C, D, m_RK[r+4]);
101  SHACAL2_Fwd(D, E, F, G, H, A, B, C, m_RK[r+5]);
102  SHACAL2_Fwd(C, D, E, F, G, H, A, B, m_RK[r+6]);
103  SHACAL2_Fwd(B, C, D, E, F, G, H, A, m_RK[r+7]);
104  }
105 
106  store_be(out, A, B, C, D, E, F, G, H);
107 
108  in += BLOCK_SIZE;
109  out += BLOCK_SIZE;
110  }
111  }
112 
113 /*
114 * SHACAL2 Encryption
115 */
116 void SHACAL2::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const
117  {
118  verify_key_set(m_RK.empty() == false);
119 
120 #if defined(BOTAN_HAS_SHACAL2_AVX2)
121  if(CPUID::has_avx2())
122  {
123  while(blocks >= 8)
124  {
125  avx2_decrypt_8(in, out);
126  in += 8*BLOCK_SIZE;
127  out += 8*BLOCK_SIZE;
128  blocks -= 8;
129  }
130  }
131 #endif
132 
133 #if defined(BOTAN_HAS_SHACAL2_SIMD)
134  if(CPUID::has_simd_32())
135  {
136  while(blocks >= 4)
137  {
138  simd_decrypt_4(in, out);
139  in += 4*BLOCK_SIZE;
140  out += 4*BLOCK_SIZE;
141  blocks -= 4;
142  }
143  }
144 #endif
145 
146  for(size_t i = 0; i != blocks; ++i)
147  {
148  uint32_t A = load_be<uint32_t>(in, 0);
149  uint32_t B = load_be<uint32_t>(in, 1);
150  uint32_t C = load_be<uint32_t>(in, 2);
151  uint32_t D = load_be<uint32_t>(in, 3);
152  uint32_t E = load_be<uint32_t>(in, 4);
153  uint32_t F = load_be<uint32_t>(in, 5);
154  uint32_t G = load_be<uint32_t>(in, 6);
155  uint32_t H = load_be<uint32_t>(in, 7);
156 
157  for(size_t r = 0; r != 64; r += 8)
158  {
159  SHACAL2_Rev(B, C, D, E, F, G, H, A, m_RK[63-r]);
160  SHACAL2_Rev(C, D, E, F, G, H, A, B, m_RK[62-r]);
161  SHACAL2_Rev(D, E, F, G, H, A, B, C, m_RK[61-r]);
162  SHACAL2_Rev(E, F, G, H, A, B, C, D, m_RK[60-r]);
163  SHACAL2_Rev(F, G, H, A, B, C, D, E, m_RK[59-r]);
164  SHACAL2_Rev(G, H, A, B, C, D, E, F, m_RK[58-r]);
165  SHACAL2_Rev(H, A, B, C, D, E, F, G, m_RK[57-r]);
166  SHACAL2_Rev(A, B, C, D, E, F, G, H, m_RK[56-r]);
167  }
168 
169  store_be(out, A, B, C, D, E, F, G, H);
170 
171  in += BLOCK_SIZE;
172  out += BLOCK_SIZE;
173  }
174  }
175 
176 /*
177 * SHACAL2 Key Schedule
178 */
179 void SHACAL2::key_schedule(const uint8_t key[], size_t len)
180  {
181  const uint32_t RC[64] = {
182  0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
183  0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
184  0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
185  0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
186  0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
187  0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
188  0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
189  0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
190  0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
191  0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
192  0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
193  0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
194  0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
195  0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
196  0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
197  0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2
198  };
199 
200  if(m_RK.empty())
201  m_RK.resize(64);
202  else
203  clear_mem(m_RK.data(), m_RK.size());
204 
205  load_be(m_RK.data(), key, len/4);
206 
207  for(size_t i = 16; i != 64; ++i)
208  {
209  const uint32_t sigma0_15 = rotr< 7>(m_RK[i-15]) ^ rotr<18>(m_RK[i-15]) ^ (m_RK[i-15] >> 3);
210  const uint32_t sigma1_2 = rotr<17>(m_RK[i- 2]) ^ rotr<19>(m_RK[i- 2]) ^ (m_RK[i- 2] >> 10);
211  m_RK[i] = m_RK[i-16] + sigma0_15 + m_RK[i-7] + sigma1_2;
212  }
213 
214  for(size_t i = 0; i != 64; ++i)
215  {
216  m_RK[i] += RC[i];
217  }
218  }
219 
220 size_t SHACAL2::parallelism() const
221  {
222 #if defined(BOTAN_HAS_SHACAL2_X86)
223  if(CPUID::has_intel_sha())
224  {
225  return 4;
226  }
227 #endif
228 
229 #if defined(BOTAN_HAS_SHACAL2_AVX2)
230  if(CPUID::has_avx2())
231  {
232  return 8;
233  }
234 #endif
235 
236 #if defined(BOTAN_HAS_SHACAL2_SIMD)
237  if(CPUID::has_simd_32())
238  {
239  return 4;
240  }
241 #endif
242 
243  return 1;
244  }
245 
246 std::string SHACAL2::provider() const
247  {
248 #if defined(BOTAN_HAS_SHACAL2_X86)
249  if(CPUID::has_intel_sha())
250  {
251  return "intel_sha";
252  }
253 #endif
254 
255 #if defined(BOTAN_HAS_SHACAL2_AVX2)
256  if(CPUID::has_avx2())
257  {
258  return "avx2";
259  }
260 #endif
261 
262 #if defined(BOTAN_HAS_SHACAL2_SIMD)
263  if(CPUID::has_simd_32())
264  {
265  return "simd";
266  }
267 #endif
268 
269  return "base";
270  }
271 
272 /*
273 * Clear memory of sensitive data
274 */
276  {
277  zap(m_RK);
278  }
279 
280 }
void clear() override
Definition: shacal2.cpp:275
void verify_key_set(bool cond) const
Definition: sym_algo.h:89
void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override
Definition: shacal2.cpp:116
void zap(std::vector< T, Alloc > &vec)
Definition: secmem.h:170
void store_be(uint16_t in, uint8_t out[2])
Definition: loadstor.h:438
void clear_mem(T *ptr, size_t n)
Definition: mem_ops.h:115
uint32_t load_be< uint32_t >(const uint8_t in[], size_t off)
Definition: loadstor.h:179
static bool has_simd_32()
Definition: cpuid.cpp:16
T load_be(const uint8_t in[], size_t off)
Definition: loadstor.h:107
Definition: alg_id.cpp:13
size_t parallelism() const override
Definition: shacal2.cpp:220
std::string provider() const override
Definition: shacal2.cpp:246
void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override
Definition: shacal2.cpp:46