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