diff options
author | Matthias Gierlings <[email protected]> | 2016-10-08 20:45:53 +0200 |
---|---|---|
committer | Matthias Gierlings <[email protected]> | 2016-11-11 12:52:26 +0100 |
commit | 8b06b4fe5fbe189c7d5250becb189bf2b87b9013 (patch) | |
tree | c73fbb3bf4eddcddf1d3f37983799d80204e8f2c /src/lib/pubkey/xmss/xmss_verification_operation.cpp | |
parent | 618f890fd7ede74c728612ca8bc590c72ee353f1 (diff) |
Added Extended Hash-Based Signatures (XMSS)
[1] XMSS: Extended Hash-Based Signatures,
draft-itrf-cfrg-xmss-hash-based-signatures-06
Release: July 2016.
https://datatracker.ietf.org/doc/
draft-irtf-cfrg-xmss-hash-based-signatures/?include_text=1
Provides XMSS_PublicKey and XMSS_PrivateKey classes as well as implementations
for the Botan interfaces PK_Ops::Signature and PK_Ops::Verification. XMSS has
been integrated into the Botan test bench, signature generation and verification
can be tested independently by invoking "botan-test xmss_sign" and
"botan-test xmss_verify"
- Some headers that are not required to be exposed to users of the library have
to be declared as public in `info.txt`. Declaring those headers private will
cause the amalgamation build to fail. The following headers have been
declared public inside `info.txt`, even though they are only intended for
internal use:
* atomic.h
* xmss_hash.h
* xmss_index_registry.h
* xmss_address.h
* xmss_common_ops.h
* xmss_tools.h
* xmss_wots_parameters.h
* xmss_wots_privatekey.h
* xmss_wots_publickey.h
- XMSS_Verification_Operation Requires the "randomness" parameter out of the
XMSS signature. "Randomness" is part of the prefix that is hashed *before*
the message. Since the signature is unknown till sign() is called, all
message content has to be buffered. For large messages this can be
inconvenient or impossible.
**Possible solution**: Change PK_Ops::Verification interface to take
the signature as constructor argument, and provide a setter method to be able
to update reuse the instance on multiple signatures. Make sign a parameterless
member call. This solution requires interface changes in botan.
**Suggested workaround** for signing large messages is to not sign the message
itself, but to precompute the message hash manually using Botan::HashFunctio
and sign the message hash instead of the message itself.
- Some of the available test vectors for the XMSS signature verification have
been commented out in order to reduce testbench runtime.
Diffstat (limited to 'src/lib/pubkey/xmss/xmss_verification_operation.cpp')
-rw-r--r-- | src/lib/pubkey/xmss/xmss_verification_operation.cpp | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/src/lib/pubkey/xmss/xmss_verification_operation.cpp b/src/lib/pubkey/xmss/xmss_verification_operation.cpp new file mode 100644 index 000000000..20945e8ca --- /dev/null +++ b/src/lib/pubkey/xmss/xmss_verification_operation.cpp @@ -0,0 +1,128 @@ +/** + * XMSS Verification Operation + * Provides signature verification capabilities for Extended Hash-Based + * Signatures (XMSS). + * + * (C) 2016 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#include <botan/internal/xmss_verification_operation.h> + +namespace Botan { + +XMSS_Verification_Operation::XMSS_Verification_Operation( + const XMSS_PublicKey& public_key) + : XMSS_Common_Ops(public_key.xmss_oid()), + m_pub_key(public_key), + m_msg_buf(0) + { + } + +secure_vector<byte> +XMSS_Verification_Operation::root_from_signature(const XMSS_Signature& sig, + const secure_vector<byte>& msg, + XMSS_Address& adrs, + const secure_vector<byte>& seed) + { + adrs.set_type(XMSS_Address::Type::OTS_Hash_Address); + adrs.set_ots_address(sig.unused_leaf_index()); + + XMSS_WOTS_PublicKey pub_key_ots(m_pub_key.wots_parameters().oid(), + msg, + sig.tree().ots_signature(), + adrs, + seed); + + adrs.set_type(XMSS_Address::Type::LTree_Address); + adrs.set_ltree_address(sig.unused_leaf_index()); + + std::array<secure_vector<byte>, 2> node; + create_l_tree(node[0], pub_key_ots, adrs, seed); + + adrs.set_type(XMSS_Address::Type::Hash_Tree_Address); + adrs.set_tree_index(sig.unused_leaf_index()); + + for(size_t k = 0; k < m_xmss_params.tree_height(); k++) + { + adrs.set_tree_height(k); + if(((sig.unused_leaf_index() / (1 << k)) & 0x01) == 0) + { + adrs.set_tree_index(adrs.get_tree_index() >> 1); + randomize_tree_hash(node[1], + node[0], + sig.tree().authentication_path()[k], + adrs, + seed); + } + else + { + adrs.set_tree_index((adrs.get_tree_index() - 1) >> 1); + randomize_tree_hash(node[1], + sig.tree().authentication_path()[k], + node[0], + adrs, + seed); + } + node[0] = node[1]; + } + return node[0]; + } + +bool +XMSS_Verification_Operation::verify(const XMSS_Signature& sig, + const secure_vector<byte>& msg, + const XMSS_PublicKey& public_key) + { + XMSS_Address adrs; + secure_vector<byte> index_bytes; + XMSS_Tools::get().concat(index_bytes, + sig.unused_leaf_index(), + m_xmss_params.element_size()); + secure_vector<byte> msg_digest = + m_hash.h_msg(sig.randomness(), + public_key.root(), + index_bytes, + msg); + + secure_vector<byte> node = root_from_signature(sig, + msg_digest, + adrs, + public_key.public_seed()); + + return (node == public_key.root()); + } + +// FIXME: XMSS signature verification requires the "randomness" parameter out +// of the XMSS signature, which is part of the prefix that is hashed before +// msg. Since the signature is unknown till sign() is called all message +// content has to be buffered. For large messages this can be inconvenient or +// impossible. +// Possible solution: Change PK_Ops::Verification interface to take the +// signature as constructor argument, make sign a parameterless member call. +void XMSS_Verification_Operation::update(const byte msg[], size_t msg_len) + { + std::copy(msg, msg + msg_len, std::back_inserter(m_msg_buf)); + } + +bool XMSS_Verification_Operation::is_valid_signature(const byte sig[], + size_t sig_len) + { + try + { + XMSS_Signature signature(m_pub_key.xmss_parameters().oid(), + secure_vector<byte>(sig, sig + sig_len)); + bool result = verify(signature, m_msg_buf, m_pub_key); + m_msg_buf.clear(); + return result; + } + catch(Integrity_Failure& e) + { + m_msg_buf.clear(); + return false; + } + } + +} + |