Botan 2.19.4
Crypto and TLS for C&
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
12namespace Botan {
13
14namespace {
15
16std::vector<uint8_t>
17raw_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
53secure_vector<uint8_t>
54raw_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
98std::vector<uint8_t>
99nist_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 const uint64_t ICV = 0xA6A6A6A6A6A6A6A6;
110
111 if(input_len == 8)
112 {
113 /*
114 * Special case for small inputs: if input == 8 bytes just use ECB
115 * (see RFC 3394 Section 2)
116 */
117 std::vector<uint8_t> block(16);
118 store_be(ICV, block.data());
119 copy_mem(block.data() + 8, input, input_len);
120 bc.encrypt(block);
121 return block;
122 }
123 else
124 {
125 return raw_nist_key_wrap(input, input_len, bc, ICV);
126 }
127 }
128
129secure_vector<uint8_t>
130nist_key_unwrap(const uint8_t input[],
131 size_t input_len,
132 const BlockCipher& bc)
133 {
134 if(bc.block_size() != 16)
135 throw Invalid_Argument("NIST key wrap algorithm requires a 128-bit cipher");
136
137 if(input_len < 16 || input_len % 8 != 0)
138 throw Invalid_Argument("Bad input size for NIST key unwrap");
139
140 const uint64_t ICV = 0xA6A6A6A6A6A6A6A6;
141
142 uint64_t ICV_out = 0;
144
145 if(input_len == 16)
146 {
147 secure_vector<uint8_t> block(input, input + input_len);
148 bc.decrypt(block);
149
150 ICV_out = load_be<uint64_t>(block.data(), 0);
151 R.resize(8);
152 copy_mem(R.data(), block.data() + 8, 8);
153 }
154 else
155 {
156 R = raw_nist_key_unwrap(input, input_len, bc, ICV_out);
157 }
158
159 if(ICV_out != ICV)
160 throw Invalid_Authentication_Tag("NIST key unwrap failed");
161
162 return R;
163 }
164
165std::vector<uint8_t>
166nist_key_wrap_padded(const uint8_t input[],
167 size_t input_len,
168 const BlockCipher& bc)
169 {
170 if(bc.block_size() != 16)
171 throw Invalid_Argument("NIST key wrap algorithm requires a 128-bit cipher");
172
173 const uint64_t ICV = 0xA65959A600000000 | static_cast<uint32_t>(input_len);
174
175 if(input_len <= 8)
176 {
177 /*
178 * Special case for small inputs: if input <= 8 bytes just use ECB
179 */
180 std::vector<uint8_t> block(16);
181 store_be(ICV, block.data());
182 copy_mem(block.data() + 8, input, input_len);
183 bc.encrypt(block);
184 return block;
185 }
186 else
187 {
188 return raw_nist_key_wrap(input, input_len, bc, ICV);
189 }
190 }
191
192secure_vector<uint8_t>
193nist_key_unwrap_padded(const uint8_t input[],
194 size_t input_len,
195 const BlockCipher& bc)
196 {
197 if(bc.block_size() != 16)
198 throw Invalid_Argument("NIST key wrap algorithm requires a 128-bit cipher");
199
200 if(input_len < 16 || input_len % 8 != 0)
201 throw Invalid_Argument("Bad input size for NIST key unwrap");
202
203 uint64_t ICV_out = 0;
205
206 if(input_len == 16)
207 {
208 secure_vector<uint8_t> block(input, input + input_len);
209 bc.decrypt(block);
210
211 ICV_out = load_be<uint64_t>(block.data(), 0);
212 R.resize(8);
213 copy_mem(R.data(), block.data() + 8, 8);
214 }
215 else
216 {
217 R = raw_nist_key_unwrap(input, input_len, bc, ICV_out);
218 }
219
220 if((ICV_out >> 32) != 0xA65959A6)
221 throw Invalid_Authentication_Tag("NIST key unwrap failed");
222
223 const size_t len = (ICV_out & 0xFFFFFFFF);
224
225 if(R.size() < 8 || len > R.size() || len <= R.size() - 8)
226 throw Invalid_Authentication_Tag("NIST key unwrap failed");
227
228 const size_t padding = R.size() - len;
229
230 for(size_t i = 0; i != padding; ++i)
231 {
232 if(R[R.size() - i - 1] != 0)
233 throw Invalid_Authentication_Tag("NIST key unwrap failed");
234 }
235
236 R.resize(R.size() - padding);
237
238 return R;
239 }
240
241}
void encrypt(const uint8_t in[], uint8_t out[]) const
Definition: block_cipher.h:82
void decrypt(const uint8_t in[], uint8_t out[]) const
Definition: block_cipher.h:92
virtual size_t block_size() const =0
Definition: alg_id.cpp:13
std::vector< uint8_t > nist_key_wrap(const uint8_t input[], size_t input_len, const BlockCipher &bc)
void store_be(uint16_t in, uint8_t out[2])
Definition: loadstor.h:438
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:133
uint64_t load_be< uint64_t >(const uint8_t in[], size_t off)
Definition: loadstor.h:217
void xor_buf(uint8_t out[], const uint8_t in[], size_t length)
Definition: mem_ops.h:262
std::vector< uint8_t > nist_key_wrap_padded(const uint8_t input[], size_t input_len, const BlockCipher &bc)
secure_vector< uint8_t > nist_key_unwrap_padded(const uint8_t input[], size_t input_len, const BlockCipher &bc)
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:65
secure_vector< uint8_t > nist_key_unwrap(const uint8_t input[], size_t input_len, const BlockCipher &bc)