Botan  2.6.0
Crypto and TLS for C++11
nist_keywrap.cpp
Go to the documentation of this file.
1 /*
2 * (C) 2011,2017 Jack Lloyd
3 *
4 * Botan is released under the Simplified BSD License (see license.txt)
5 */
6 
7 #include <botan/nist_keywrap.h>
8 #include <botan/block_cipher.h>
9 #include <botan/loadstor.h>
10 #include <botan/exceptn.h>
11 
12 namespace Botan {
13 
14 namespace {
15 
16 std::vector<uint8_t>
17 raw_nist_key_wrap(const uint8_t input[],
18  size_t input_len,
19  const BlockCipher& bc,
20  uint64_t ICV)
21  {
22  const size_t n = (input_len + 7) / 8;
23 
24  secure_vector<uint8_t> R((n + 1) * 8);
25  secure_vector<uint8_t> A(16);
26 
27  store_be(ICV, A.data());
28 
29  copy_mem(&R[8], input, input_len);
30 
31  for(size_t j = 0; j <= 5; ++j)
32  {
33  for(size_t i = 1; i <= n; ++i)
34  {
35  const uint32_t t = static_cast<uint32_t>((n * j) + i);
36 
37  copy_mem(&A[8], &R[8*i], 8);
38 
39  bc.encrypt(A.data());
40  copy_mem(&R[8*i], &A[8], 8);
41 
42  uint8_t t_buf[4] = { 0 };
43  store_be(t, t_buf);
44  xor_buf(&A[4], t_buf, 4);
45  }
46  }
47 
48  copy_mem(R.data(), A.data(), 8);
49 
50  return std::vector<uint8_t>(R.begin(), R.end());
51  }
52 
53 secure_vector<uint8_t>
54 raw_nist_key_unwrap(const uint8_t input[],
55  size_t input_len,
56  const BlockCipher& bc,
57  uint64_t& ICV_out)
58  {
59  if(input_len < 16 || input_len % 8 != 0)
60  throw Invalid_Argument("Bad input size for NIST key unwrap");
61 
62  const size_t n = (input_len - 8) / 8;
63 
64  secure_vector<uint8_t> R(n * 8);
65  secure_vector<uint8_t> A(16);
66 
67  for(size_t i = 0; i != 8; ++i)
68  A[i] = input[i];
69 
70  copy_mem(R.data(), input + 8, input_len - 8);
71 
72  for(size_t j = 0; j <= 5; ++j)
73  {
74  for(size_t i = n; i != 0; --i)
75  {
76  const uint32_t t = static_cast<uint32_t>((5 - j) * n + i);
77 
78  uint8_t t_buf[4] = { 0 };
79  store_be(t, t_buf);
80 
81  xor_buf(&A[4], t_buf, 4);
82 
83  copy_mem(&A[8], &R[8*(i-1)], 8);
84 
85  bc.decrypt(A.data());
86 
87  copy_mem(&R[8*(i-1)], &A[8], 8);
88  }
89  }
90 
91  ICV_out = load_be<uint64_t>(A.data(), 0);
92 
93  return R;
94  }
95 
96 }
97 
98 std::vector<uint8_t>
99 nist_key_wrap(const uint8_t input[],
100  size_t input_len,
101  const BlockCipher& bc)
102  {
103  if(bc.block_size() != 16)
104  throw Invalid_Argument("NIST key wrap algorithm requires a 128-bit cipher");
105 
106  if(input_len % 8 != 0)
107  throw Invalid_Argument("Bad input size for NIST key wrap");
108 
109  return raw_nist_key_wrap(input, input_len, bc, 0xA6A6A6A6A6A6A6A6);
110  }
111 
112 secure_vector<uint8_t>
113 nist_key_unwrap(const uint8_t input[],
114  size_t input_len,
115  const BlockCipher& bc)
116  {
117  if(bc.block_size() != 16)
118  throw Invalid_Argument("NIST key wrap algorithm requires a 128-bit cipher");
119 
120  if(input_len < 16 || input_len % 8 != 0)
121  throw Invalid_Argument("Bad input size for NIST key unwrap");
122 
123  uint64_t ICV_out = 0;
124 
125  secure_vector<uint8_t> R = raw_nist_key_unwrap(input, input_len, bc, ICV_out);
126 
127  if(ICV_out != 0xA6A6A6A6A6A6A6A6)
128  throw Integrity_Failure("NIST key unwrap failed");
129 
130  return R;
131  }
132 
133 std::vector<uint8_t>
134 nist_key_wrap_padded(const uint8_t input[],
135  size_t input_len,
136  const BlockCipher& bc)
137  {
138  if(bc.block_size() != 16)
139  throw Invalid_Argument("NIST key wrap algorithm requires a 128-bit cipher");
140 
141  const uint64_t ICV = 0xA65959A600000000 | static_cast<uint32_t>(input_len);
142 
143  if(input_len <= 8)
144  {
145  /*
146  * Special case for small inputs: if input <= 8 bytes just use ECB
147  */
148  std::vector<uint8_t> block(16);
149  store_be(ICV, block.data());
150  copy_mem(block.data() + 8, input, input_len);
151  bc.encrypt(block);
152  return block;
153  }
154  else
155  {
156  return raw_nist_key_wrap(input, input_len, bc, ICV);
157  }
158  }
159 
160 secure_vector<uint8_t>
161 nist_key_unwrap_padded(const uint8_t input[],
162  size_t input_len,
163  const BlockCipher& bc)
164  {
165  if(bc.block_size() != 16)
166  throw Invalid_Argument("NIST key wrap algorithm requires a 128-bit cipher");
167 
168  if(input_len < 16 || input_len % 8 != 0)
169  throw Invalid_Argument("Bad input size for NIST key unwrap");
170 
171  uint64_t ICV_out = 0;
173 
174  if(input_len == 16)
175  {
176  secure_vector<uint8_t> block(input, input + input_len);
177  bc.decrypt(block);
178 
179  ICV_out = load_be<uint64_t>(block.data(), 0);
180  R.resize(8);
181  copy_mem(R.data(), block.data() + 8, 8);
182  }
183  else
184  {
185  R = raw_nist_key_unwrap(input, input_len, bc, ICV_out);
186  }
187 
188  if((ICV_out >> 32) != 0xA65959A6)
189  throw Integrity_Failure("NIST key unwrap failed");
190 
191  const size_t len = (ICV_out & 0xFFFFFFFF);
192 
193  if(len > R.size() || len < R.size() - 8)
194  throw Integrity_Failure("NIST key unwrap failed");
195 
196  const size_t padding = R.size() - len;
197 
198  for(size_t i = 0; i != padding; ++i)
199  {
200  if(R[R.size() - i - 1] != 0)
201  throw Integrity_Failure("NIST key unwrap failed");
202  }
203 
204  R.resize(R.size() - padding);
205 
206  return R;
207  }
208 
209 }
void store_be(uint16_t in, uint8_t out[2])
Definition: loadstor.h:434
void decrypt(const uint8_t in[], uint8_t out[]) const
Definition: block_cipher.h:91
std::vector< uint8_t > nist_key_wrap(const uint8_t input[], size_t input_len, const BlockCipher &bc)
uint64_t load_be< uint64_t >(const uint8_t in[], size_t off)
Definition: loadstor.h:215
void xor_buf(uint8_t out[], const uint8_t in[], size_t length)
Definition: mem_ops.h:174
secure_vector< uint8_t > nist_key_unwrap_padded(const uint8_t input[], size_t input_len, const BlockCipher &bc)
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:108
Definition: alg_id.cpp:13
secure_vector< uint8_t > nist_key_unwrap(const uint8_t input[], size_t input_len, const BlockCipher &bc)
void encrypt(const uint8_t in[], uint8_t out[]) const
Definition: block_cipher.h:81
std::vector< uint8_t > nist_key_wrap_padded(const uint8_t input[], size_t input_len, const BlockCipher &bc)
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:88
virtual size_t block_size() const =0