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