/src/botan/build/include/botan/xmss_privatekey.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * XMSS_PrivateKey.h |
3 | | * (C) 2016,2017,2018 Matthias Gierlings |
4 | | * |
5 | | * Botan is released under the Simplified BSD License (see license.txt) |
6 | | **/ |
7 | | |
8 | | #ifndef BOTAN_XMSS_PRIVATEKEY_H_ |
9 | | #define BOTAN_XMSS_PRIVATEKEY_H_ |
10 | | |
11 | | #include <cstddef> |
12 | | #include <iterator> |
13 | | #include <memory> |
14 | | #include <botan/alg_id.h> |
15 | | #include <botan/exceptn.h> |
16 | | #include <botan/pk_keys.h> |
17 | | #include <botan/types.h> |
18 | | #include <botan/xmss_parameters.h> |
19 | | #include <botan/xmss_publickey.h> |
20 | | #include <botan/atomic.h> |
21 | | #include <botan/xmss_wots_privatekey.h> |
22 | | #include <botan/xmss_index_registry.h> |
23 | | |
24 | | namespace Botan { |
25 | | |
26 | | /** |
27 | | * An XMSS: Extended Hash-Based Signature private key. |
28 | | * The XMSS private key does not support the X509 and PKCS7 standard. Instead |
29 | | * the raw format described in [1] is used. |
30 | | * |
31 | | * [1] XMSS: Extended Hash-Based Signatures, |
32 | | * Request for Comments: 8391 |
33 | | * Release: May 2018. |
34 | | * https://datatracker.ietf.org/doc/rfc8391/ |
35 | | **/ |
36 | | class BOTAN_PUBLIC_API(2,0) XMSS_PrivateKey final : public virtual XMSS_PublicKey, |
37 | | public virtual Private_Key |
38 | | { |
39 | | public: |
40 | | /** |
41 | | * Creates a new XMSS private key for the chosen XMSS signature method. |
42 | | * New seeds for public/private key and pseudo random function input are |
43 | | * generated using the provided RNG. The appropriate WOTS signature method |
44 | | * will be automatically set based on the chosen XMSS signature method. |
45 | | * |
46 | | * @param xmss_algo_id Identifier for the selected XMSS signature method. |
47 | | * @param rng A random number generator to use for key generation. |
48 | | **/ |
49 | | XMSS_PrivateKey(XMSS_Parameters::xmss_algorithm_t xmss_algo_id, |
50 | | RandomNumberGenerator& rng); |
51 | | |
52 | | /** |
53 | | * Creates an XMSS_PrivateKey from a byte sequence produced by |
54 | | * raw_private_key(). |
55 | | * |
56 | | * @param raw_key An XMSS private key serialized using raw_private_key(). |
57 | | **/ |
58 | | XMSS_PrivateKey(const secure_vector<uint8_t>& raw_key); |
59 | | |
60 | | /** |
61 | | * Creates a new XMSS private key for the chosen XMSS signature method |
62 | | * using precomputed seeds for public/private keys and pseudo random |
63 | | * function input. The appropriate WOTS signature method will be |
64 | | * automatically set, based on the chosen XMSS signature method. |
65 | | * |
66 | | * @param xmss_algo_id Identifier for the selected XMSS signature method. |
67 | | * @param idx_leaf Index of the next unused leaf. |
68 | | * @param wots_priv_seed A seed to generate a Winternitz-One-Time- |
69 | | * Signature private key from. |
70 | | * @param prf a secret n-byte key sourced from a secure source |
71 | | * of uniformly random data. |
72 | | * @param root Root node of the binary hash tree. |
73 | | * @param public_seed The public seed. |
74 | | **/ |
75 | | XMSS_PrivateKey(XMSS_Parameters::xmss_algorithm_t xmss_algo_id, |
76 | | size_t idx_leaf, |
77 | | const secure_vector<uint8_t>& wots_priv_seed, |
78 | | const secure_vector<uint8_t>& prf, |
79 | | const secure_vector<uint8_t>& root, |
80 | | const secure_vector<uint8_t>& public_seed) |
81 | | : XMSS_PublicKey(xmss_algo_id, root, public_seed), |
82 | | m_wots_priv_key(XMSS_PublicKey::m_xmss_params.ots_oid(), |
83 | | public_seed, |
84 | | wots_priv_seed), |
85 | | m_hash(XMSS_PublicKey::m_xmss_params.hash_function_name()), |
86 | | m_prf(prf), |
87 | | m_index_reg(XMSS_Index_Registry::get_instance()) |
88 | 0 | { |
89 | 0 | set_unused_leaf_index(idx_leaf); |
90 | 0 | } |
91 | | |
92 | 0 | bool stateful_operation() const override { return true; } |
93 | | |
94 | | /** |
95 | | * Retrieves the last unused leaf index of the private key. Reusing a leaf |
96 | | * by utilizing leaf indices lower than the last unused leaf index will |
97 | | * compromise security. |
98 | | * |
99 | | * @return Index of the last unused leaf. |
100 | | **/ |
101 | | size_t unused_leaf_index() const |
102 | 0 | { |
103 | 0 | return *recover_global_leaf_index(); |
104 | 0 | } |
105 | | |
106 | | /** |
107 | | * Sets the last unused leaf index of the private key. The leaf index |
108 | | * will be updated automatically during every signing operation, and |
109 | | * should not be set manually. |
110 | | * |
111 | | * @param idx Index of the last unused leaf. |
112 | | **/ |
113 | | void set_unused_leaf_index(size_t idx) |
114 | 0 | { |
115 | 0 | if(idx >= (1ull << XMSS_PublicKey::m_xmss_params.tree_height())) |
116 | 0 | { |
117 | 0 | throw Decoding_Error("XMSS private key leaf index out of bounds"); |
118 | 0 | } |
119 | 0 | else |
120 | 0 | { |
121 | 0 | std::atomic<size_t>& index = |
122 | 0 | static_cast<std::atomic<size_t>&>(*recover_global_leaf_index()); |
123 | 0 | size_t current = 0; |
124 | 0 |
|
125 | 0 | do |
126 | 0 | { |
127 | 0 | current = index.load(); |
128 | 0 | if(current > idx) |
129 | 0 | { return; } |
130 | 0 | } |
131 | 0 | while(!index.compare_exchange_strong(current, idx)); |
132 | 0 | } |
133 | 0 | } |
134 | | |
135 | | size_t reserve_unused_leaf_index() |
136 | 0 | { |
137 | 0 | size_t idx = (static_cast<std::atomic<size_t>&>( |
138 | 0 | *recover_global_leaf_index())).fetch_add(1); |
139 | 0 | if(idx >= (1ull << XMSS_PublicKey::m_xmss_params.tree_height())) |
140 | 0 | { |
141 | 0 | throw Decoding_Error("XMSS private key, one time signatures exhaused"); |
142 | 0 | } |
143 | 0 | return idx; |
144 | 0 | } |
145 | | |
146 | | /** |
147 | | * Winternitz One Time Signature Scheme key utilized for signing |
148 | | * operations. |
149 | | * |
150 | | * @return WOTS+ private key. |
151 | | **/ |
152 | | const XMSS_WOTS_PrivateKey& wots_private_key() const |
153 | 0 | { |
154 | 0 | return m_wots_priv_key; |
155 | 0 | } |
156 | | |
157 | | /** |
158 | | * Winternitz One Time Signature Scheme key utilized for signing |
159 | | * operations. |
160 | | * |
161 | | * @return WOTS+ private key. |
162 | | **/ |
163 | | XMSS_WOTS_PrivateKey& wots_private_key() |
164 | 0 | { |
165 | 0 | return m_wots_priv_key; |
166 | 0 | } |
167 | | |
168 | | const secure_vector<uint8_t>& prf() const |
169 | 0 | { |
170 | 0 | return m_prf; |
171 | 0 | } |
172 | | |
173 | | secure_vector<uint8_t>& prf() |
174 | 0 | { |
175 | 0 | return m_prf; |
176 | 0 | } |
177 | | |
178 | | void set_public_seed( |
179 | | const secure_vector<uint8_t>& public_seed) override |
180 | 0 | { |
181 | 0 | m_public_seed = public_seed; |
182 | 0 | m_wots_priv_key.set_public_seed(public_seed); |
183 | 0 | } |
184 | | |
185 | | void set_public_seed(secure_vector<uint8_t>&& public_seed) override |
186 | 0 | { |
187 | 0 | m_public_seed = std::move(public_seed); |
188 | 0 | m_wots_priv_key.set_public_seed(m_public_seed); |
189 | 0 | } |
190 | | |
191 | | const secure_vector<uint8_t>& public_seed() const override |
192 | 0 | { |
193 | 0 | return m_public_seed; |
194 | 0 | } |
195 | | |
196 | | std::unique_ptr<PK_Ops::Signature> |
197 | | create_signature_op(RandomNumberGenerator&, |
198 | | const std::string&, |
199 | | const std::string& provider) const override; |
200 | | |
201 | | secure_vector<uint8_t> private_key_bits() const override |
202 | 0 | { |
203 | 0 | return DER_Encoder().encode(raw_private_key(), OCTET_STRING).get_contents(); |
204 | 0 | } |
205 | | |
206 | | size_t size() const override |
207 | 0 | { |
208 | 0 | return XMSS_PublicKey::size() + |
209 | 0 | sizeof(uint32_t) + |
210 | 0 | 2 * XMSS_PublicKey::m_xmss_params.element_size(); |
211 | 0 | } |
212 | | |
213 | | /** |
214 | | * Generates a non standartized byte sequence representing the XMSS |
215 | | * private key. |
216 | | * |
217 | | * @return byte sequence consisting of the following elements in order: |
218 | | * 4-byte OID, n-byte root node, n-byte public seed, |
219 | | * 8-byte unused leaf index, n-byte prf seed, n-byte private seed. |
220 | | **/ |
221 | | secure_vector<uint8_t> raw_private_key() const; |
222 | | /** |
223 | | * Algorithm 9: "treeHash" |
224 | | * Computes the internal n-byte nodes of a Merkle tree. |
225 | | * |
226 | | * @param start_idx The start index. |
227 | | * @param target_node_height Height of the target node. |
228 | | * @param adrs Address of the tree containing the target node. |
229 | | * |
230 | | * @return The root node of a tree of height target_node height with the |
231 | | * leftmost leaf being the hash of the WOTS+ pk with index |
232 | | * start_idx. |
233 | | **/ |
234 | | secure_vector<uint8_t> tree_hash( |
235 | | size_t start_idx, |
236 | | size_t target_node_height, |
237 | | XMSS_Address& adrs); |
238 | | |
239 | | private: |
240 | | /** |
241 | | * Fetches shared unused leaf index from the index registry |
242 | | **/ |
243 | | std::shared_ptr<Atomic<size_t>> recover_global_leaf_index() const; |
244 | | |
245 | | inline void tree_hash_subtree(secure_vector<uint8_t>& result, |
246 | | size_t start_idx, |
247 | | size_t target_node_height, |
248 | | XMSS_Address& adrs) |
249 | 0 | { |
250 | 0 | return tree_hash_subtree(result, start_idx, target_node_height, adrs, m_hash); |
251 | 0 | } |
252 | | |
253 | | |
254 | | /** |
255 | | * Helper for multithreaded tree hashing. |
256 | | */ |
257 | | void tree_hash_subtree(secure_vector<uint8_t>& result, |
258 | | size_t start_idx, |
259 | | size_t target_node_height, |
260 | | XMSS_Address& adrs, |
261 | | XMSS_Hash& hash); |
262 | | |
263 | | XMSS_WOTS_PrivateKey m_wots_priv_key; |
264 | | XMSS_Hash m_hash; |
265 | | secure_vector<uint8_t> m_prf; |
266 | | XMSS_Index_Registry& m_index_reg; |
267 | | }; |
268 | | |
269 | | } |
270 | | |
271 | | #endif |
272 | | |