diff options
290 files changed, 5566 insertions, 2633 deletions
diff --git a/.travis.yml b/.travis.yml index ae7330751..80b176fc8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ os: dist: trusty sudo: required -osx_image: xcode7 +osx_image: xcode8.2 compiler: - clang @@ -43,8 +43,6 @@ matrix: # Ignore some problem builds for now allow_failures: - os: linux - env: BUILD_MODE="cross-ppc32" - - os: linux env: BUILD_MODE="cross-win32" exclude: diff --git a/botan_version.py b/botan_version.py index 8591b878c..74ba8b3d5 100644 --- a/botan_version.py +++ b/botan_version.py @@ -1,7 +1,7 @@ release_major = 1 release_minor = 11 -release_patch = 34 +release_patch = 35 release_so_abi_rev = release_patch # These are set by the distribution script diff --git a/configure.py b/configure.py index e98d0e41f..e262c3bce 100755 --- a/configure.py +++ b/configure.py @@ -129,7 +129,7 @@ class BuildConfigurationInformation(object): self.internal_headers = sorted(flatten([m.internal_headers() for m in modules])) self.external_headers = sorted(flatten([m.external_headers() for m in modules])) - if options.via_amalgamation: + if options.amalgamation: self.build_sources = ['botan_all.cpp'] else: self.build_sources = self.sources @@ -272,12 +272,15 @@ def process_command_line(args): build_group = optparse.OptionGroup(parser, 'Build options') build_group.add_option('--with-debug-info', action='store_true', default=False, dest='with_debug_info', - help='enable debug info') + help='include debug symbols') build_group.add_option('--with-sanitizers', action='store_true', default=False, dest='with_sanitizers', - help='enable runtime checks') + help='enable ASan/UBSan checks') build_group.add_option('--with-coverage', action='store_true', default=False, dest='with_coverage', + help='enable coverage checking and disable opts') + + build_group.add_option('--with-coverage-info', action='store_true', default=False, dest='with_coverage_info', help='enable coverage checking') build_group.add_option('--enable-shared-library', dest='build_shared_lib', @@ -320,6 +323,11 @@ def process_command_line(args): build_group.add_option('--with-external-includedir', metavar='DIR', default='', help='use DIR for external includes') + build_group.add_option('--with-openmp', default=False, action='store_true', + help='enable use of OpenMP') + build_group.add_option('--with-cilkplus', default=False, action='store_true', + help='enable use of Cilk Plus') + link_methods = ['symlink', 'hardlink', 'copy'] build_group.add_option('--link-method', default=None, metavar='METHOD', choices=link_methods, @@ -483,6 +491,7 @@ def process_command_line(args): options.with_debug_info = True if options.with_coverage: + options.with_coverage_info = True options.no_optimizations = True def parse_multiple_enable(modules): @@ -598,7 +607,7 @@ class ModuleInfo(object): def __init__(self, infofile): lex_me_harder(infofile, self, - ['source', 'header:internal', 'header:public', + ['header:internal', 'header:public', 'header:external', 'requires', 'os', 'arch', 'cc', 'libs', 'frameworks', 'comment', 'warning'], @@ -623,8 +632,7 @@ class ModuleInfo(object): else: self.need_isa = self.need_isa.split(',') - if self.source == []: - self.source = list(extract_files_matching(self.lives_in, ['.cpp'])) + self.source = list(extract_files_matching(self.lives_in, ['.cpp'])) if self.header_internal == [] and self.header_public == []: self.header_public = list(extract_files_matching(self.lives_in, ['.h'])) @@ -846,6 +854,11 @@ class ArchInfo(object): if options.with_valgrind: macros.append('HAS_VALGRIND') + if options.with_openmp: + macros.append('TARGET_HAS_OPENMP') + if options.with_cilkplus: + macros.append('TARGET_HAS_CILKPLUS') + return macros class CompilerInfo(object): @@ -939,7 +952,7 @@ class CompilerInfo(object): if flag != None and flag != '' and flag not in abi_link: abi_link.append(flag) - if options.with_coverage: + if options.with_coverage_info: if self.coverage_flags == '': raise Exception('No coverage handling for %s' % (self.basename)) abi_link.append(self.coverage_flags) @@ -949,6 +962,16 @@ class CompilerInfo(object): raise Exception('No sanitizer handling for %s' % (self.basename)) abi_link.append(self.sanitizer_flags) + if options.with_openmp: + if 'openmp' not in self.mach_abi_linking: + raise Exception('No support for OpenMP for %s' % (self.basename)) + abi_link.append(self.mach_abi_linking['openmp']) + + if options.with_cilkplus: + if 'cilkplus' not in self.mach_abi_linking: + raise Exception('No support for Cilk Plus for %s' % (self.basename)) + abi_link.append(self.mach_abi_linking['cilkplus']) + abi_flags = ' '.join(sorted(abi_link)) if options.cc_abi_flags != '': @@ -1572,7 +1595,7 @@ def create_template_vars(build_config, options, modules, cc, arch, osinfo): vars["gmake_dso_in"] = process_template(os.path.join(options.makefile_dir, 'gmake_dso.in'), vars) \ if options.build_shared_lib else '' vars["gmake_coverage_in"] = process_template(os.path.join(options.makefile_dir, 'gmake_coverage.in'), vars) \ - if options.with_coverage else '' + if options.with_coverage_info else '' return vars @@ -1815,7 +1838,7 @@ def generate_amalgamation(build_config, options): return contents botan_include_matcher = re.compile('#include <botan/(.*)>$') - std_include_matcher = re.compile('#include <([^/\.]+|stddef.h)>$') + std_include_matcher = re.compile('^#include <([^/\.]+|stddef.h)>$') any_include_matcher = re.compile('#include <(.*)>$') class Amalgamation_Generator: @@ -1879,7 +1902,7 @@ def generate_amalgamation(build_config, options): amalg_header = """/* * Botan %s Amalgamation -* (C) 1999-2013,2014,2015 Jack Lloyd and others +* (C) 1999-2013,2014,2015,2016 Jack Lloyd and others * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -2177,8 +2200,7 @@ def main(argv = None): raise Exception("--gen-amalgamation was removed. Migrate to --amalgamation.") if options.via_amalgamation: - logging.warn("--via-amalgamation is deprecated. Use --amalgamation.") - options.amalgamation = True + raise Exception("--via-amalgamation was removed. Use --amalgamation instead.") if options.build_shared_lib and not osinfo.building_shared_supported: raise Exception('Botan does not support building as shared library on the target os. ' @@ -2193,6 +2215,7 @@ def main(argv = None): using_mods = [modules[m] for m in loaded_mods] build_config = BuildConfigurationInformation(options, using_mods) + build_config.public_headers.append(os.path.join(build_config.build_dir, 'build.h')) template_vars = create_template_vars(build_config, options, using_mods, cc, arch, osinfo) @@ -2303,8 +2326,9 @@ def main(argv = None): return 'undated' return 'dated %d' % (datestamp) - logging.info('Botan %s (%s %s) build setup is complete' % ( + logging.info('Botan %s (VC %s) (%s %s) build setup is complete' % ( build_config.version_string, + build_config.version_vc_rev, build_config.version_release_type, release_date(build_config.version_datestamp))) diff --git a/doc/contributing.rst b/doc/contributing.rst index 4ca17e355..5aaf3d61c 100644 --- a/doc/contributing.rst +++ b/doc/contributing.rst @@ -46,6 +46,83 @@ Library Layout * ``misc`` contains odds and ends: format preserving encryption, SRP, threshold secret sharing, all or nothing transform, and others +Sending patches +======================================== + +All contributions should be submitted as pull requests via GitHub +(https://github.com/randombit/botan). If you are planning a large +change email the mailing list or open a discussion ticket on github +before starting out to make sure you are on the right path. And once +you have something written, free to open a [WIP] PR for early review +and comment. + +If possible please sign your git commits using a PGP key. +See https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work for +instructions on how to set this up. + +Depending on what your change is, your PR should probably also include an update +to ``news.rst`` with a note explaining the change. If your change is a +simple bug fix, a one sentence description is perhaps sufficient. If there is an +existing ticket on GitHub with discussion or other information, reference it in +your change note as 'GH #000'. + +Update ``doc/credits.txt`` with your information so people know what you did! + +If you are interested in contributing but don't know where to start check out +``doc/todo.rst`` for some ideas - these are changes we would almost certainly +accept once they've passed code review. + +Also, try building and testing it on whatever hardware you have handy, +especially non-x86 platforms, or especially C++11 compilers other than the +regularly tested GCC, Clang, and Visual Studio compilers. + +Git Usage +======================================== + +Do *NOT* merge ``master`` into your topic branch, this creates +needless commits and noise in history. Instead, as needed, rebase your +branch against master (``git rebase -i master``) and force push the +branch to update the PR. If the GitHub PR page does not report any +merge conflicts and nobody asks you to rebase, you don't need to +rebase. + +Try to keep your history clean and use rebase to squash your commits +as needed. If your diff is less than roughly 100 lines, it should +probably be a single commit. Only split commits as needed to help with +review/understanding of the change. + +Python +======================================== + +Scripts should be in Python whenever possible. + +For configure.py (and install.py) the target is stock (no modules outside the +standard library) CPython 2.7 plus latest CPython 3.x. Support for CPython 2.6, +PyPy, etc is great when viable (in the sense of not causing problems for 2.7 or +3.x, and not requiring huge blocks of version dependent code). As running this +program succesfully is required for a working build making it as portable as +possible is considered key. + +The python wrapper botan.py targets CPython 2.7, 3.x, and latest PyPy. Note that +a single file is used to avoid dealing with any of Python's various crazy module +distribution issues. + +For random scripts not typically run by an end-user (codegen, visualization, and +so on) there isn't any need to worry about 2.6 and even just running under +Python2 xor Python3 is acceptable if needed. Here it's fine to depend on any +useful modules such as graphviz or matplotlib, regardless if it is available +from a stock CPython install. + +Build Tools and Hints +======================================== + +If you don't already use it for all your C/C++ development, install +``ccache`` now and configure a large cache on a fast disk. It allows for +very quick rebuilds by caching the compiler output. + +Use ``--with-sanitizers`` to enable ASan. UBSan has to be added separately +with ``--cc-abi-flags`` at the moment as GCC 4.8 does not have UBSan. + Copyright Notice ======================================== @@ -108,52 +185,7 @@ use ``std::bind``. Use ``::`` to explicitly refer to the global namespace (eg, when calling an OS or library function like ``::select`` or ``::sqlite3_open``). -Sending patches -======================================== - -All contributions should be submitted as pull requests via GitHub -(https://github.com/randombit/botan). If you are planning a large -change email the mailing list or open a discussion ticket on github -before starting out to make sure you are on the right path. And once -you have something written, free to open a [WIP] PR for early review -and comment. - -If possible please sign your git commits using a PGP key. -See https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work for -instructions on how to set this up. - -Depending on what your change is, your PR should probably also include an update -to ``news.rst`` with a note explaining the change. If your change is a -simple bug fix, a one sentence description is perhaps sufficient. If there is an -existing ticket on GitHub with discussion or other information, reference it in -your change note as 'GH #000'. - -Update ``doc/credits.txt`` with your information so people know what you did! - -If you are interested in contributing but don't know where to start check out -``doc/todo.rst`` for some ideas - these are changes we would almost certainly -accept once they've passed code review. - -Also, try building and testing it on whatever hardware you have handy, -especially non-x86 platforms, or especially C++11 compilers other than the -regularly tested GCC, Clang, and Visual Studio compilers. - -Git Usage -======================================== - -Do *NOT* merge ``master`` into your topic branch, this creates -needless commits and noise in history. Instead, as needed, rebase your -branch against master (``git rebase -i master``) and force push the -branch to update the PR. If the GitHub PR page does not report any -merge conflicts and nobody asks you to rebase, you don't need to -rebase. - -Try to keep your history clean and use rebase to squash your commits -as needed. If your diff is less than roughly 100 lines, it should -probably be a single commit. Only split commits as needed to help with -review/understanding of the change. - -External Dependencies +Use of External Dependencies ======================================== Compiler Dependencies @@ -223,45 +255,3 @@ algorithms), potentially a parallelism framework such as Cilk (as part of a larger design for parallel message processing, say), or hypothentically use of a safe ASN.1 parser (that is, one written in a safe language like Rust or OCaml providing a C API). - -Test Tools -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Integration to better leverage specialized test or verification tools such as -valgrind, ASan/UBSan, AFL, LLVM libFuzzer, KLEE, Coq, etc is fine. Typically -these are not enabled or used during normal builds but are specially set up by -developers or auditors. - -The fuzzer tests currently live at https://github.com/randombit/botan-fuzzers - -Python -======================================== - -Scripts should be in Python whenever possible. - -For configure.py (and install.py) the target is stock (no modules outside the -standard library) CPython 2.7 plus latest CPython 3.x. Support for CPython 2.6, -PyPy, etc is great when viable (in the sense of not causing problems for 2.7 or -3.x, and not requiring huge blocks of version dependent code). As running this -program succesfully is required for a working build making it as portable as -possible is considered key. - -The python wrapper botan.py targets CPython 2.7, 3.x, and latest PyPy. Note that -a single file is used to avoid dealing with any of Python's various crazy module -distribution issues. - -For random scripts not typically run by an end-user (codegen, visualization, and -so on) there isn't any need to worry about 2.6 and even just running under -Python2 xor Python3 is acceptable if needed. Here it's fine to depend on any -useful modules such as graphviz or matplotlib, regardless if it is available -from a stock CPython install. - -Build Tools and Hints -======================================== - -If you don't already use it for all your C/C++ development, install -``ccache`` now and configure a large cache on a fast disk. It allows for -very quick rebuilds by caching the compiler output. - -Use ``--with-sanitizers`` to enable ASan. UBSan has to be added separately -with ``--cc-abi-flags`` at the moment as GCC 4.8 does not have UBSan. diff --git a/doc/credits.rst b/doc/credits.rst index cef62f0d4..e13e38c85 100644 --- a/doc/credits.rst +++ b/doc/credits.rst @@ -29,6 +29,13 @@ snail-mail address (S), and Bitcoin address (B). N: Olivier de Gaalon D: SQLite encryption codec (src/contrib/sqlite) + N: Matthias Gierlings + E: [email protected] + W: https://www.hackmanit.de/ + P: 39E0 D270 19A4 B356 05D0 29AE 1BD3 49CF 744A 02FF + D: GMAC, Extended Hash-Based Signatures (XMSS) + S: Bochum, Germany + N: Matthew Gregan D: Binary file I/O support, allocator fixes @@ -124,7 +131,7 @@ snail-mail address (S), and Bitcoin address (B). W: https://sirrix.com/ D: KDF1-18033, ECIES S: Saarland, Germany - + N: Daniel Neus W: https://sirrix.com/ diff --git a/doc/deprecated.txt b/doc/deprecated.txt index 1a1a95242..cafb34d93 100644 --- a/doc/deprecated.txt +++ b/doc/deprecated.txt @@ -8,8 +8,6 @@ in the source. Currently deprecated: -- ECB Cipher_Mode for block ciphers - - 3DES and SEED ciphersuites in TLS - DSA ciphersuites/certs in TLS diff --git a/doc/manual/building.rst b/doc/manual/building.rst index 807ff5556..a92d1c6a5 100644 --- a/doc/manual/building.rst +++ b/doc/manual/building.rst @@ -254,13 +254,13 @@ is quite convenient if you plan to embed the library into another application. To generate the amalgamation, run ``configure.py`` with whatever options you would ordinarily use, along with the option -``--gen-amalgamation``. This will create two (rather large) files, +``--amalgamation``. This will create two (rather large) files, ``botan_all.h`` and ``botan_all.cpp``, plus (unless the option ``--single-amalgmation-file`` is used) also some number of files like ``botan_all_aesni.cpp`` and ``botan_all_sse2.cpp`` which need to be compiled with the appropriate compiler flags to enable that instruction set. The ISA specific files are only generated if there is -code that requires them, so you can simplify your build The +code that requires them, so you can simplify your build. The ``--minimized-build`` option (described elsewhere in this documentation) is also quite useful with the amalgamation. @@ -272,11 +272,14 @@ to take advantage of prepackaged versions of botan on operating systems that support it), you can instead ignore ``botan_all.h`` and use the headers from ``build/include`` as normal. -You can also build the library as normal but using the amalgamation -instead of the individual source files using ``--via-amalgamation``. +You can also build the library using Botan's build system (as normal) +but utilizing the amalgamation instead of the individual source files +by running something like ``./configure.py --amalgamation && make``. This is essentially a very simple form of link time optimization; because the entire library source is visible to the compiler, it has more opportunities for interprocedural optimizations. +Additionally, amalgamation builds usually have significantly shorter +compile times for full rebuilds. Modules Relying on Third Party Libraries ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/doc/manual/credentials_manager.rst b/doc/manual/credentials_manager.rst index 04e9e3f2e..006d47343 100644 --- a/doc/manual/credentials_manager.rst +++ b/doc/manual/credentials_manager.rst @@ -29,31 +29,6 @@ implementation. The default implementation returns an empty list. - .. cpp::function:: void verify_certificate_chain( \ - const std::string& type, \ - const std::string& hostname, \ - const std::vector<X509_Certificate>& cert_chain) - - Verifies the certificate chain in *cert_chain*, assuming the - leaf certificate is the first element. - - If *hostname* is set, additionally ``verify_certificate_chain`` - will check that the leaf certificate has a DNS entry matching - *hostname*. - - In the default implementation the *type* argument is passed, - along with *hostname*, to ``trusted_certificate_authorities`` to - find out what root(s) should be trusted for verifying this - certificate. - - This function indicates a validation failure by throwing an - exception. - - This function has a default implementation that probably - sufficies for most uses, however can be overrided for - implementing extra validation routines such as public key - pinning. - .. cpp:function:: std::vector<X509_Certificate> cert_chain( \ const std::vector<std::string>& cert_key_types, \ const std::string& type, \ @@ -78,6 +53,15 @@ implementation. the leaf cert of a chain returned previously by ``cert_chain`` or ``cert_chain_single_type``. +In versions before 1.11.34, there was an additional function on `Credentials_Manager` + + .. cpp::function:: void verify_certificate_chain( \ + const std::string& type, \ + const std::string& hostname, \ + const std::vector<X509_Certificate>& cert_chain) + +This function has been replaced by `TLS::Callbacks::tls_verify_cert_chain`. + SRP Authentication ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/doc/manual/index.rst b/doc/manual/index.rst index 1bfc01d30..42f3bceb6 100644 --- a/doc/manual/index.rst +++ b/doc/manual/index.rst @@ -8,3 +8,7 @@ References ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The :ref:`genindex` and :ref:`search` may be useful. + +.. toctree:: + :maxdepth: 1 + :numbered: diff --git a/doc/manual/pkcs11.rst b/doc/manual/pkcs11.rst index 48c063400..38d973798 100644 --- a/doc/manual/pkcs11.rst +++ b/doc/manual/pkcs11.rst @@ -1089,7 +1089,7 @@ implements the :cpp:class:`Hardware_RNG` interface. .. cpp:function:: PKCS11_RNG(Session& session) - A PKCS#11 :cpp:class:`Session` must be passed to instantiate a :cpp:class:`PKCS11_RNG`. + A PKCS#11 :cpp:class:`Session` must be passed to instantiate a ``PKCS11_RNG``. .. cpp:function:: void randomize(Botan::byte output[], std::size_t length) override diff --git a/doc/manual/pubkey.rst b/doc/manual/pubkey.rst index bf47b631d..6cebcd8ba 100644 --- a/doc/manual/pubkey.rst +++ b/doc/manual/pubkey.rst @@ -20,9 +20,9 @@ reference to a ``Public_Key``, it can take any public key or private key, and similiarly for ``Private_Key``. Types of ``Public_Key`` include ``RSA_PublicKey``, ``DSA_PublicKey``, -``ECDSA_PublicKey``, ``ECKCDSA_PublicKey``, ``ECGDSA_PublicKey``, ``DH_PublicKey``, ``ECDH_PublicKey``, ``RW_PublicKey``, -``NR_PublicKey``,, and ``GOST_3410_PublicKey``. There are cooresponding -``Private_Key`` classes for each of these algorithms. +``ECDSA_PublicKey``, ``ECKCDSA_PublicKey``, ``ECGDSA_PublicKey``, ``DH_PublicKey``, ``ECDH_PublicKey``, +``Curve25519_PublicKey``, ``ElGamal_PublicKey``, ``McEliece_PublicKey``, ``XMSS_PublicKey`` +and ``GOST_3410_PublicKey``. There are cooresponding ``Private_Key`` classes for each of these algorithms. .. _creating_new_private_keys: @@ -47,11 +47,10 @@ like key agreement, the two keys *must* use the same group. There are currently two kinds of discrete logarithm groups supported in botan: the integers modulo a prime, represented by :ref:`dl_group`, and elliptic curves in GF(p), represented by :ref:`ec_group`. A rough generalization is that the -larger the group is, the more secure the algorithm is, but coorespondingly the +larger the group is, the more secure the algorithm is, but correspondingly the slower the operations will be. -Given a ``DL_Group``, you can create new DSA, Diffie-Hellman, and -Nyberg-Rueppel key pairs with +Given a ``DL_Group``, you can create new DSA, Diffie-Hellman and ElGamal key pairs with .. cpp:function:: DSA_PrivateKey::DSA_PrivateKey(RandomNumberGenerator& rng, \ const DL_Group& group, const BigInt& x = 0) @@ -59,9 +58,6 @@ Nyberg-Rueppel key pairs with .. cpp:function:: DH_PrivateKey::DH_PrivateKey(RandomNumberGenerator& rng, \ const DL_Group& group, const BigInt& x = 0) -.. cpp:function:: NR_PrivateKey::NR_PrivateKey(RandomNumberGenerator& rng, \ - const DL_Group& group, const BigInt& x = 0) - .. cpp:function:: ElGamal_PrivateKey::ElGamal_PrivateKey(RandomNumberGenerator& rng, \ const DL_Group& group, const BigInt& x = 0) @@ -71,7 +67,7 @@ Nyberg-Rueppel key pairs with :ref:`pbkdf` for how to do that) as a private key value. Normally, you would leave the value as zero, letting the class generate a new random key. -Finally, given an ``EC_Group`` object, you can create a new ECDSA, +Finally, given an ``EC_Group`` object, you can create a new ECDSA, ECKCDSA, ECGDSA, ECDH, or GOST 34.10-2001 private key with .. cpp:function:: ECDSA_PrivateKey::ECDSA_PrivateKey(RandomNumberGenerator& rng, \ @@ -245,17 +241,16 @@ Instantiating a ``DL_Group`` simply requires calling Currently all "modp" groups included in botan are ones defined by the Internet Engineering Task Force, so the provider is "ietf", and the strings - look like "modp/ietf/N" where N can be any of 768, 1024, 1536, 2048, 3072, + look like "modp/ietf/N" where N can be any of 1024, 1536, 2048, 3072, 4096, 6144, or 8192. This group type is used for Diffie-Hellman and ElGamal algorithms. - The other type, "dsa" is used for DSA and Nyberg-Rueppel keys. They can - also be used with Diffie-Hellman and ElGamal, but this is less common. The - currently available groups are "dsa/jce/N" for N in 512, 768, or 1024, and - "dsa/botan/N" with N being 2048 or 3072. The "jce" groups are the standard - DSA groups used in the Java Cryptography Extensions, while the "botan" - groups were randomly generated using the FIPS 186-3 algorithm by the library - maintainers. + The other type, "dsa" is used for DSA keys. They can also be used with + Diffie-Hellman and ElGamal, but this is less common. The currently available + groups are "dsa/jce/1024" and "dsa/botan/N" with N being 2048 or 3072. The + "jce" groups are the standard DSA groups used in the Java Cryptography + Extensions, while the "botan" groups were randomly generated using the + FIPS 186-3 algorithm by the library maintainers. You can generate a new random group using @@ -370,12 +365,14 @@ The primary interface for encryption is than this the operation will fail with an exception. :cpp:class:`PK_Encryptor` is only an interface - to actually encrypt you have -to create an implementation, of which there are currently two available in the -library, :cpp:class:`PK_Encryptor_EME` and :cpp:class:`DLIES_Encryptor`. DLIES -is a standard method (from IEEE 1363) that uses a key agreement technique such -as DH or ECDH to perform message encryption. Normally, public key encryption -is done using algorithms which support it directly, such as RSA or ElGamal; -these use the EME class: +to create an implementation, of which there are currently three available in the +library, :cpp:class:`PK_Encryptor_EME`, :cpp:class:`DLIES_Encryptor` and +:cpp:class:`ECIES_Encryptor`. DLIES is a hybrid encryption scheme (from +IEEE 1363) that uses the DH key agreement technique in combination with a KDF, a +MAC and a symmetric encryption algorithm to perform message encryption. ECIES is +similar to DLIES, but uses ECDH for the key agreement. Normally, public key +encryption is done using algorithms which support it directly, such as RSA or +ElGamal; these use the EME class: .. cpp:class:: PK_Encryptor_EME @@ -392,16 +389,48 @@ these use the EME class: Available in the header ``dlies.h`` - .. cpp:function:: DLIES_Encryptor(const PK_Key_Agreement_Key& key, \ - KDF* kdf, MessageAuthenticationCode* mac, size_t mac_key_len = 20) + .. cpp:function:: DLIES_Encryptor(const DH_PrivateKey& own_priv_key, \ + RandomNumberGenerator& rng, KDF* kdf, MessageAuthenticationCode* mac, \ + size_t mac_key_len = 20) Where *kdf* is a key derivation function (see :ref:`key_derivation_function`) and *mac* is a - MessageAuthenticationCode. + MessageAuthenticationCode. The encryption is performed by XORing the + message with a stream of bytes provided by the KDF. + + .. cpp:function:: DLIES_Encryptor(const DH_PrivateKey& own_priv_key, \ + RandomNumberGenerator& rng, KDF* kdf, Cipher_Mode* cipher, \ + size_t cipher_key_len, MessageAuthenticationCode* mac, \ + size_t mac_key_len = 20) + + Instead of XORing the message a block cipher can be specified. + +.. cpp:class:: ECIES_Encryptor + + Available in the header ``ecies.h``. + + Parameters for encryption and decryption are set by the + :cpp:class:`ECIES_System_Params` class which stores the EC domain parameters, + the KDF (see :ref:`key_derivation_function`), the cipher (see + :ref:`symmetric_crypto`) and the MAC. -The decryption classes are named ``PK_Decryptor``, ``PK_Decryptor_EME``, and -``DLIES_Decryptor``. They are created in the exact same way, except they take -the private key, and the processing function is named ``decrypt``. + .. cpp:function:: ECIES_Encryptor(const PK_Key_Agreement_Key& private_key, \ + const ECIES_System_Params& ecies_params, \ + RandomNumberGenerator& rng) + + Where *private_key* is the key to use for the key agreement. The system + paramters are specified in *ecies_params* and the RNG to use is passed in + *rng*. + + .. cpp:function:: ECIES_Encryptor(RandomNumberGenerator& rng, \ + const ECIES_System_Params& ecies_params) + + Creates an ephemeral private key which is used for the key agreement. + +The decryption classes are named :cpp:class:`PK_Decryptor`, +:cpp:class:`PK_Decryptor_EME`, :cpp:class:`DLIES_Decryptor` and +:cpp:class:`ECIES_Decryptor`. They are created in the exact same way, except +they take the private key, and the processing function is named ``decrypt``. Botan implements the following encryption algorithms and padding schemes: @@ -463,9 +492,16 @@ Signature generation is performed using Constructs a new signer object for the private key *key* using the signature format *emsa*. The key must support signature operations. In - the current version of the library, this includes RSA, DSA, ECDSA, ECKCDSA, ECGDSA, GOST - 34.10-2001, Nyberg-Rueppel, and Rabin-Williams. Other signature schemes - may be supported in the future. + the current version of the library, this includes RSA, DSA, ECDSA, ECKCDSA, + ECGDSA, GOST 34.10-2001. Other signature schemes may be supported in the future. + + .. note:: + + Botan both supports non-deterministic and deterministic (as per RFC + 6979) DSA and ECDSA signatures. Deterministic signatures are compatible + in the way that they can be verified with a non-deterministic implementation. + If the ``rfc6979`` module is enabled, deterministic DSA and ECDSA signatures + will be generated. Currently available values for *emsa* include EMSA1, EMSA2, EMSA3, EMSA4, and Raw. All of them, except Raw, take a parameter naming a message @@ -476,11 +512,11 @@ Signature generation is performed using For RSA, use EMSA4 (also called PSS) unless you need compatibility with software that uses the older PKCS #1 v1.5 standard, in which case use - EMSA3 (also called "EMSA-PKCS1-v1_5"). For DSA, ECDSA, ECKCDSA, ECGDSA GOST 34.10-2001, - and Nyberg-Rueppel, you should use EMSA1. + EMSA3 (also called "EMSA-PKCS1-v1_5"). For DSA, ECDSA, ECKCDSA, ECGDSA and + GOST 34.10-2001 you should use EMSA1. The *format* defaults to ``IEEE_1363`` which is the only available - format for RSA. For DSA and ECDSA, you can also use + format for RSA. For DSA, ECDSA, ECGDSA and ECKCDSA you can also use ``DER_SEQUENCE``, which will format the signature as an ASN.1 SEQUENCE value. @@ -572,17 +608,17 @@ and a ECDSA signature using EMSA1 with SHA-256. Subsequently the computed signat int main() { Botan::AutoSeeded_RNG rng; - //Generate ECDSA keypair + // Generate ECDSA keypair Botan::ECDSA_PrivateKey key(rng, Botan::EC_Group("secp521r1")); std::string text("This is a tasty burger!"); std::vector<uint8_t> data(text.data(),text.data()+text.length()); - //sign data + // sign data Botan::PK_Signer signer(key, rng, "EMSA1(SHA-256)"); signer.update(data); std::vector<uint8_t> signature = signer.signature(rng); std::cout << "Signature:" << std::endl << Botan::hex_encode(signature); - //verify signature + // verify signature Botan::PK_Verifier verifier(key, "EMSA1(SHA-256)"); verifier.update(data); std::cout << std::endl << "is " << (verifier.check_signature(signature)? "valid" : "invalid"); @@ -659,16 +695,16 @@ applies the key derivation function KDF2(SHA-256) with 256 bit output length to int main() { Botan::AutoSeeded_RNG rng - //ec domain and + // ec domain and Botan::EC_Group domain("secp521r1"); std::string kdf = "KDF2(SHA-256)"; - //generate ECDH keys + // generate ECDH keys Botan::ECDH_PrivateKey keyA(rng, domain); Botan::ECDH_PrivateKey keyB(rng, domain); - //Construct key agreements + // Construct key agreements Botan::PK_Key_Agreement ecdhA(keyA,rng,kdf); Botan::PK_Key_Agreement ecdhB(keyB,rng,kdf); - //Agree on shared secret and derive symmetric key of 256 bit length + // Agree on shared secret and derive symmetric key of 256 bit length Botan::secure_vector<uint8_t> sA = ecdhA.derive_key(32,keyB.public_value()).bits_of(); Botan::secure_vector<uint8_t> sB = ecdhB.derive_key(32,keyA.public_value()).bits_of(); diff --git a/doc/manual/symmetric_crypto.rst b/doc/manual/symmetric_crypto.rst index 6afb05322..fb29c9c9f 100644 --- a/doc/manual/symmetric_crypto.rst +++ b/doc/manual/symmetric_crypto.rst @@ -1,3 +1,5 @@ +.. _symmetric_crypto: + Symmetric Key Cryptography =========================================== Block ciphers, stream ciphers and MACs are all keyed operations. diff --git a/doc/manual/tls.rst b/doc/manual/tls.rst index 8508b0a70..16d8e4f08 100644 --- a/doc/manual/tls.rst +++ b/doc/manual/tls.rst @@ -66,12 +66,12 @@ information about the connection. For DTLS, it is possible to receive records with the `rec_no` field out of order, or with gaps, cooresponding to reordered or lost datagrams. - .. cpp:function:: void tls_alert(Alert alert) + .. cpp:function:: void tls_alert(Alert alert) Mandatory. Called when an alert is received from the peer. Note that alerts received before the handshake is complete are not authenticated and could have been inserted by a MITM attacker. - + .. cpp:function:: bool tls_session_established(const TLS::Session& session) Mandatory. Called whenever a negotiation completes. This can happen more @@ -85,6 +85,46 @@ information about the connection. exception which will send a close message to the counterparty and reset the connection state. + .. cpp::function:: void tls_verify_cert_chain(const std::vector<X509_Certificate>& cert_chain, \ + const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_responses, \ + const std::vector<Certificate_Store*>& trusted_roots, \ + Usage_Type usage, \ + const std::string& hostname, \ + const Policy& policy) + + Optional - default implementation should work for many users. + It can be overrided for implementing extra validation routines + such as public key pinning. + + Verifies the certificate chain in *cert_chain*, assuming the leaf + certificate is the first element. Throws an exception if any + error makes this certificate chain unacceptable. + + If usage is `Usage_Type::TLS_SERVER_AUTH`, then *hostname* should + match the information in the server certificate. If usage is + `TLS_CLIENT_AUTH`, then *hostname* specifies the host the client + is authenticating against (from SNI); the callback can use this for + any special site specific auth logic. + + The `ocsp_responses` is a possibly empty list of OCSP responses provided by + the server. In the current implementation of TLS OCSP stapling, only a + single OCSP response can be returned. A existing TLS extension allows the + server to send multiple OCSP responses, this extension may be supported in + the future in which case more than one OCSP response may be given during + this callback. + + The `trusted_roots` parameter was returned by a call from the associated + `Credentials_Manager`. + + The `policy` provided is the policy for the TLS session which is + being authenticated using this certificate chain. It can be consulted + for values such as allowable signature methods and key sizes. + + .. cpp::function:: std::chrono::milliseconds tls_verify_cert_chain_ocsp_timeout() const + + Called by default `tls_verify_cert_chain` to set timeout for online OCSP requests + on the certificate chain. Return 0 to disable OCSP. Current default is 0. + .. cpp:function:: std::string tls_server_choose_app_protocol(const std::vector<std::string>& client_protos) Optional. Called by the server when a client includes a list of protocols in the ALPN extension. @@ -679,6 +719,26 @@ policy settings from a file. Default: false + .. cpp:function:: size_t minimum_signature_strength() const + + Return the minimum strength (as ``n``, representing ``2**n`` work) + we will accept for a signature algorithm on any certificate. + + Use 80 to enable RSA-1024 (*not recommended*), or 128 to require + either ECC or large (~3000 bit) RSA keys. + + Default: 110 (allowing 2048 bit RSA) + + .. cpp:function:: bool require_cert_revocation_info() const + + If this function returns true, and a ciphersuite using certificates was + negotiated, then we must have access to a valid CRL or OCSP response in + order to trust the certificate. + + .. warning:: Returning false here could expose you to attacks + + Default: true + .. cpp:function:: std::string dh_group() const For ephemeral Diffie-Hellman key exchange, the server sends a diff --git a/doc/manual/x509.rst b/doc/manual/x509.rst index 901eee09c..1aec0f043 100644 --- a/doc/manual/x509.rst +++ b/doc/manual/x509.rst @@ -293,7 +293,7 @@ The result of the validation is returned as a class: implicitly trusted for this validation to be correct. -A :cpp:class:`Path_Validation_Restrictions` is passed to the path +A ``Path_Validation_Restrictions`` is passed to the path validator and specifies restrictions and options for the validation step. The two constructors are: diff --git a/doc/roadmap.rst b/doc/roadmap.rst index ccac29a28..668e5553a 100644 --- a/doc/roadmap.rst +++ b/doc/roadmap.rst @@ -63,3 +63,69 @@ Ongoing Issues Documentation could always use help. Many things are completely undocumented, few things are documented well. + +Plans for 2017 +---------------------------------------- + +It's an open question how many of these will end up being backported to 2.0.x, +versus being features only in 2.1.x development snapshots. + +TLS 1.3 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The RFC process seems to be approaching consensus so hopefully there will be a +final spec soon. + +The handshake differences are quite substantial, it's an open question how to +implement that without overly complicating the existing TLS v1.0-v1.2 handshake +code. There will also be some API changes to support 0-RTT data. + +This is a major project and probably will not start until later in the year. + +TLS Hardening/Testing +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Improve testing of TLS: leverage TLS-Attacker better, for example using custom +workflows. Add tests using BoringSSL's hacked Go TLS stack. + +X509_Certificate Refactor +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The certificate classes use a type called Data_Store which ends up shoving +everything (DN values, extension info, etc) into a single std::multimap<string,string>. +This was a bad design. Instead the certificate type should contain X509_DN +objects for the subject and issuer, an int value for the format version, and so on. +The Data_Store type should be removed entirely. + +ASN.1 Redesign +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The current ASN.1 library (DER_Encoder/BER_Decoder) does make it +roughly possible to write C++ code matching the ASN.1 structures. But +it is not flexible enough for all cases and makes many unnecessary +copies (and thus memory allocations) of the data as it works. + +It would be better to have a system that used (a simple subset of) ASN.1 to +define the types as well as encoding/decoding logic. Then new types could be +easily defined. This could also obviate the current code for handling OIDs, and +allow representing the OIDs using the natural OID tree syntax of ASN.1. + +Another important feature will be supporting copy-free streaming decoding. That +is, given a (ptr,len) range the decoding operation either returns an error +(throws exception) or else the decoded object plus the number of bytes after ptr +that contain the object, and it does so without making any allocations or +copies. + +It will probably be easier to be consistently allocation free in machine +generated code, so the two goals of the redesign seem to reinforce each other. + +Interface to PSK and SRP databases +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Adding support for databases storing encrypted PSKs and SRP credentials. + +Ed25519 signatures +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Used by many protocols these days including SSH and Tor. +Probably will be done by importing from SUPERCOP or similar. diff --git a/doc/security.rst b/doc/security.rst index faefca7d5..e7e665a62 100644 --- a/doc/security.rst +++ b/doc/security.rst @@ -21,7 +21,18 @@ Advisories 2016 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -* 2016-10-8871 (CVE-2016-8871) OAEP side channel +* 2016-11-27 (CVE-2016-9132) Integer overflow in BER decoder + + While decoding BER length fields, an integer overflow could occur. This could + occur while parsing untrusted inputs such as X.509 certificates. The overflow + does not seem to lead to any obviously exploitable condition, but exploitation + cannot be positively ruled out. Only 32-bit platforms are likely affected; to + cause an overflow on 64-bit the parsed data would have to be many gigabytes. + Bug found by Falko Strenzke, cryptosource GmbH. + + Fixed in 1.10.14 and 1.11.34, all prior versions affected. + +* 2016-10-26 (CVE-2016-8871) OAEP side channel A side channel in OAEP decoding could be used to distinguish RSA ciphertexts that did or did not have a leading 0 byte. For an attacker capable of diff --git a/doc/todo.rst b/doc/todo.rst index 940ad57d5..d1ca9c299 100644 --- a/doc/todo.rst +++ b/doc/todo.rst @@ -30,7 +30,7 @@ Public Key Crypto, Math ---------------------------------------- * SPHINCS-256 -* EdDSA (GH #283) +* Ed25519 / EdDSA (GH #283) * Ed448-Goldilocks * FHMQV * Support mixed hashes and non-empty param strings in OAEP @@ -47,6 +47,7 @@ External Providers, Hardware Support * Access to system certificate stores (Windows, OS X) * Extend OpenSSL provider (DH, HMAC, CMAC, GCM) +* Support using BoringSSL or LibreSSL instead of OpenSSL * /dev/crypto provider (ciphers, hashes) * Windows CryptoAPI provider (ciphers, hashes, RSA) * Apple CommonCrypto @@ -154,7 +155,6 @@ Documentation ---------------------------------------- * TPM (no docs) -* PKCS #11 (no docs) * X.509 certs, path validation * Specific docs covering one major topic (RSA, ECDSA, AES/GCM, ...) * Some howto style docs (setting up CA, ...) @@ -1,22 +1,48 @@ Release Notes ======================================== -Version 1.11.34, Not Yet Released +Version 1.11.35, Not Yet Released ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +* Fix deref of invalid memory location in TLS client when the server chooses a + ciphersuite value larger than the largest TLS ciphersuite ID compiled into the + table. This might conceivably cause a crash in rare circumstances, but does + not seem to be further exploitable. (GH #758) + +* Rename Public_Key::x509_subject_public_key, which does not return a + X.509 SubjectPublicKey, to public_key_bits. Add a new non-virtual function + Public_Key::subject_public_key which does exactly that. (GH #685 #757) + +* Rename Private_Key::pkcs8_private_key, which does not return a + PKCS#8 private key, to private_key_bits. Add a new non-virtual function + Private_Key::private_key_info which does exactly that. (GH #685 #757) + +* The deprecated ECB Cipher_Mode class has been removed (GH #756) + +* Fix tests errors when write only access to /dev/urandom is prohibited (GH #748) + +Version 1.11.34, 2016-11-28 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix integer overflow during BER decoding, found by Falko Strenzke. + This bug is not thought to be directly exploitable but upgrading ASAP + is advised. (CVE-2016-9132) + * Add post-quantum signature scheme XMSS. Provides either 128 or 256 bit (post-quantum) security, with small public and private keys, fast verification, and reasonably small signatures (2500 bytes for 128-bit security). Signature generation is very slow, on the order of seconds. And very importantly the signature scheme is stateful: each leaf index must only be used once, or all security is lost. In the appropriate system where - signatures are rarely generated (such as code signing) XMSS makes an - excellent choice. (GH #717) + signatures are rarely generated (such as code signing) XMSS makes an excellent + choice. (GH #717 #736) * Add support for CECPQ1 TLS ciphersuites. These use a combination of x25519 ECDH and NewHope to provide post-quantum security. The ciphersuites are not IETF standard, but is compatible with BoringSSL. (GH #729) +* Add support for client-side OCSP stapling to TLS. (GH #738) + * Previously both public and private keys performed automatic self testing after generation or loading. However this often caused unexpected application performance problems, and so has been removed. Instead applications must call @@ -33,6 +59,13 @@ Version 1.11.34, Not Yet Released * Add GMAC, a MAC based on GCM (GH #488 / #691) +* Add ESP block cipher padding from RFC 4304. GH #724 + +* Incompatible change to HKDF: previously the HKDF type in Botan was only the + Expand half of HKDF. Now HKDF is the full Extract-then-Expand KDF, and + HKDF_Extract and HKDF_Expand are available. If you previously used HKDF, you + must switch to using HKDF_Expand. (GH #723) + * Add Cipher_Mode::reset which resets message-specific state, allowing discarding state but allowing continued processing under the same key. (GH #552) @@ -53,7 +86,7 @@ Version 1.11.34, Not Yet Released * Add a BSD sockets version of the HTTP client code used for OCSP. GH #699 -* Add MessageAuthenticationCode::start_msg interface for providing nonce (GH #691) +* Export the public key workfactor functions (GH #734) and add tests for them. * HMAC_DRBG allows configuring maximum number of bytes before reseed check (GH #690) @@ -91,12 +124,14 @@ Version 1.11.34, Not Yet Released * Allow a custom ECC curve to be specified at build time, for application or system specific curves. (GH #636 #710) +* Use NOMINMAX on Windows to avoid problems in amalgamation build. (GH #740) + * Add support to output bakefiles with new `configure.py` option `--with-bakefile`. (GH #360 #720) * The function `zero_mem` has been renamed `secure_scrub_memory` -* More tests for pipe/filter (GH #689 #693) and AEADs (GH #552) +* More tests for pipe/filter (GH #689 #693), AEADs (GH #552), KDF::name (GH #727), * Add a test suite for timing analysis for TLS CBC decryption, OAEP decryption, and PKCS #1 v1.5 decryption. These operations all have the feature that if an @@ -108,6 +143,8 @@ Version 1.11.34, Not Yet Released * Add a fuzzing framework. Supports fuzzing some APIs using AFL and libFuzzer. +* Added documentation for PKCS #11 (GH #725) + * The LibraryInitializer type is no longer needed and is now deprecated. * The license and news files were moved from doc to the top level directory. @@ -119,6 +156,22 @@ Version 1.11.34, Not Yet Released * Add (back) the Perl XS wrapper and sqlite encryption code. +Version 1.10.14, 2016-11-28 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* NOTE WELL: Botan 1.10.x is supported for security patches only until + 2017-12-31 + +* Fix integer overflow during BER decoding, found by Falko Strenzke. + This bug is not thought to be directly exploitable but upgrading ASAP + is advised. (CVE-2016-9132) + +* Fix two cases where (in error situations) an exception would be + thrown from a destructor, causing a call to std::terminate. + +* When RC4 is disabled in the build, also prevent it from being + included in the OpenSSL provider. (GH #638) + Version 1.11.33, 2016-10-26 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/readme.rst b/readme.rst index f7b79228b..1920d6154 100644 --- a/readme.rst +++ b/readme.rst @@ -103,9 +103,9 @@ Versions 1.11 and later require a working C++11 compiler; GCC 4.8 and later, Clang 3.5 and later, and MSVC 2015 are regularly tested. The latest 1.11 release is -`1.11.33 <http://botan.randombit.net/releases/Botan-1.11.33.tgz>`_ -`(sig) <http://botan.randombit.net/releases/Botan-1.11.33.tgz.asc>`_ -released on 2016-10-26 +`1.11.34 <http://botan.randombit.net/releases/Botan-1.11.34.tgz>`_ +`(sig) <http://botan.randombit.net/releases/Botan-1.11.34.tgz.asc>`_ +released on 2016-11-28 Old Stable Series (1.10) ---------------------------------------- @@ -116,9 +116,9 @@ critical security updates (with all support ending on 2018-1-1), and the developers do not recommend its use anymore. The latest 1.10 release is -`1.10.13 <http://botan.randombit.net/releases/Botan-1.10.13.tgz>`_ -`(sig) <http://botan.randombit.net/releases/Botan-1.10.13.tgz.asc>`_ -released on 2016-04-23 +`1.10.14 <http://botan.randombit.net/releases/Botan-1.10.14.tgz>`_ +`(sig) <http://botan.randombit.net/releases/Botan-1.10.14.tgz.asc>`_ +released on 2016-11-28 Books and other resources ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -195,7 +195,7 @@ Hash functions and MACs * SHA-3 (and Keccak-1600) * Skein-512, BLAKE2b * RIPEMD-160, Tiger, Whirlpool, GOST 34.11 -* Authentication codes HMAC, CMAC, Poly1305, SipHash +* Authentication codes CMAC, GMAC, HMAC, Poly1305, SipHash * Hash function combiners (Parallel and Comb4P) * Non-cryptographic checksums Adler32, CRC24, CRC32 * Obsolete algorithms MD5, MD4, CBC-MAC, X9.19 DES-MAC diff --git a/src/build-data/buildh.in b/src/build-data/buildh.in index 56b70e060..ba6eee97d 100644 --- a/src/build-data/buildh.in +++ b/src/build-data/buildh.in @@ -21,8 +21,10 @@ #define BOTAN_VERSION_VC_REVISION "%{version_vc_rev}" #define BOTAN_DISTRIBUTION_INFO "%{distribution_info}" -%{unsafe_fuzzer_mode_define} +/* How many bits per limb in a BigInt */ +#define BOTAN_MP_WORD_BITS %{mp_bits} +%{unsafe_fuzzer_mode_define} #define BOTAN_INSTALL_PREFIX R"(%{prefix})" #define BOTAN_INSTALL_HEADER_DIR "%{includedir}/botan-%{version_major}.%{version_minor}" @@ -33,6 +35,28 @@ #define BOTAN_DLL %{visibility_attribute} #endif +/* Target identification and feature test macros */ +%{target_os_defines} + +%{target_cpu_defines} + +%{target_compiler_defines} + +/* +* Module availability definitions +*/ +%{module_defines} + +/* +* Local/misc configuration options (if any) follow +*/ +%{local_config} +%{misc_config} + +/* +* Things you can edit (but probably shouldn't) +*/ + /* How much to allocate for a buffer of no particular size */ #define BOTAN_DEFAULT_BUFFER_SIZE 1024 @@ -49,12 +73,6 @@ */ #define BOTAN_MLOCK_ALLOCATOR_MAX_LOCKED_KB 512 -/* Multiplier on a block cipher's native parallelism */ -#define BOTAN_BLOCK_CIPHER_PAR_MULT 4 - -/* How many bits per limb in a BigInt */ -#define BOTAN_MP_WORD_BITS %{mp_bits} - /* * If enabled uses memset via volatile function pointer to zero memory, * otherwise does a byte at a time write via a volatile pointer. @@ -114,6 +132,10 @@ { "timestamp", "rdseed", "rdrand", "proc_info", \ "darwin_secrandom", "dev_random", "win32_cryptoapi", "proc_walk", "system_stats" } + +/* Multiplier on a block cipher's native parallelism */ +#define BOTAN_BLOCK_CIPHER_PAR_MULT 4 + /* * These control the RNG used by the system RNG interface */ @@ -156,32 +178,6 @@ Each read generates 32 bits of output #define BOTAN_ENTROPY_RDSEED_RETRIES 20 /* -* Compiler and target specific flags -*/ - -/* Should we use GCC-style inline assembler? */ -#if !defined(BOTAN_USE_GCC_INLINE_ASM) && defined(__GNUG__) - #define BOTAN_USE_GCC_INLINE_ASM 1 -#endif - -#ifdef __GNUC__ - #define BOTAN_GCC_VERSION \ - (__GNUC__ * 100 + __GNUC_MINOR__ * 10 + __GNUC_PATCHLEVEL__) -#else - #define BOTAN_GCC_VERSION 0 -#endif - -/* Target identification and feature test macros */ -%{target_os_defines} - -%{target_cpu_defines} - -#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN) || \ - defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN) - #define BOTAN_TARGET_CPU_HAS_KNOWN_ENDIANNESS -#endif - -/* * If no way of dynamically determining the cache line size for the * system exists, this value is used as the default. Used by the side * channel countermeasures rather than for alignment purposes, so it is @@ -192,93 +188,6 @@ Each read generates 32 bits of output #define BOTAN_TARGET_CPU_DEFAULT_CACHE_LINE_SIZE 32 #endif -%{target_compiler_defines} - - -#if defined(__GNUG__) || defined(__clang__) - #define BOTAN_FUNC_ISA(isa) __attribute__ ((target(isa))) -#else - #define BOTAN_FUNC_ISA(isa) -#endif - -#if defined(__GNUG__) || defined(__clang__) - #define BOTAN_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result)) -#else - #define BOTAN_WARN_UNUSED_RESULT -#endif - -/* -* Compile-time deprecation warnings -*/ -#if !defined(BOTAN_NO_DEPRECATED_WARNINGS) - - #if defined(__clang__) - #define BOTAN_DEPRECATED(msg) __attribute__ ((deprecated)) - - #elif defined(_MSC_VER) - #define BOTAN_DEPRECATED(msg) __declspec(deprecated(msg)) - - #elif defined(__GNUG__) - - #if BOTAN_GCC_VERSION >= 450 - #define BOTAN_DEPRECATED(msg) __attribute__ ((deprecated(msg))) - #else - #define BOTAN_DEPRECATED(msg) __attribute__ ((deprecated)) - #endif - - #endif - -#endif - -#if !defined(BOTAN_NORETURN) - - #if defined (__clang__) || defined (__GNUG__) - #define BOTAN_NORETURN __attribute__ ((__noreturn__)) - - #elif defined (_MSC_VER) - #define BOTAN_NORETURN __declspec(noreturn) - - #else - #define BOTAN_NORETURN - - #endif - -#endif - - -#if defined(_MSC_VER) - #define BOTAN_CURRENT_FUNCTION __FUNCTION__ -#else - #define BOTAN_CURRENT_FUNCTION __func__ -#endif - -#if !defined(BOTAN_DEPRECATED) - #define BOTAN_DEPRECATED(msg) -#endif - -#if defined(_MSC_VER) && (_MSC_VER < 1900) - // noexcept is not supported in VS 2013 - #include <yvals.h> - #define BOTAN_NOEXCEPT _NOEXCEPT -#else - #define BOTAN_NOEXCEPT noexcept -#endif - -/* -* Module availability definitions -*/ -%{module_defines} - -/* -* Local configuration options (if any) follow -*/ -%{local_config} - -/* -* Miscellaneous configuration options (if any) follow -*/ -%{misc_config} - /** * Controls how AutoSeeded_RNG is instantiated */ @@ -301,20 +210,21 @@ Each read generates 32 bits of output // The struct is only declared to force the semicolon, it is never defined. #define BOTAN_FORCE_SEMICOLON struct BOTAN_DUMMY_STRUCT -#if defined(BOTAN_TARGET_ARCH_IS_X86_64) && (\ - (defined(_MSC_VER) && !defined(_WIN64)) || \ - (defined(__clang__) && !defined(__x86_64__)) || \ - (defined(__GNUG__) && !defined(__x86_64__)) \ -) +// Check for a common build problem: + +#if defined(BOTAN_TARGET_ARCH_IS_X86_64) && ((defined(_MSC_VER) && !defined(_WIN64)) || \ + (defined(__clang__) && !defined(__x86_64__)) || \ + (defined(__GNUG__) && !defined(__x86_64__))) #error "Trying to compile Botan configured as x86_64 with non-x86_64 compiler." #endif -#if defined(BOTAN_TARGET_ARCH_IS_X86_32) && (\ - (defined(_MSC_VER) && defined(_WIN64)) || \ - (defined(__clang__) && !defined(__i386__)) || \ - (defined(__GNUG__) && !defined(__i386__)) \ -) +#if defined(BOTAN_TARGET_ARCH_IS_X86_32) && ((defined(_MSC_VER) && defined(_WIN64)) || \ + (defined(__clang__) && !defined(__i386__)) || \ + (defined(__GNUG__) && !defined(__i386__))) + #error "Trying to compile Botan configured as x86_32 with non-x86_32 compiler." #endif +#include <botan/compiler.h> + #endif diff --git a/src/build-data/cc/clang.txt b/src/build-data/cc/clang.txt index c4a85658f..055315c3b 100644 --- a/src/build-data/cc/clang.txt +++ b/src/build-data/cc/clang.txt @@ -73,6 +73,8 @@ ivybridge -> "-march=core-avx-i" <mach_abi_linking> all -> "-pthread" +openmp -> "-fopenmp" + x86_32 -> "-m32" x86_64 -> "-m64" ppc64 -> "-m64" diff --git a/src/build-data/cc/gcc.txt b/src/build-data/cc/gcc.txt index b88454ce6..0a53e15c1 100644 --- a/src/build-data/cc/gcc.txt +++ b/src/build-data/cc/gcc.txt @@ -120,6 +120,9 @@ all_x86_64 -> "-momit-leaf-frame-pointer" <mach_abi_linking> all -> "-pthread -fstack-protector" +cilkplus -> "-fcilkplus" +openmp -> "-fopenmp" + mips64 -> "-mabi=64" s390 -> "-m31" s390x -> "-m64" diff --git a/src/build-data/policy/bsi.txt b/src/build-data/policy/bsi.txt index f1c40c9fa..949626e0a 100644 --- a/src/build-data/policy/bsi.txt +++ b/src/build-data/policy/bsi.txt @@ -103,7 +103,6 @@ eax ocb siv cfb -ecb # stream chacha @@ -140,6 +139,7 @@ md4 rmd160 #sha1 // needed for tls #sha1_sse2 // needed for tls +shake skein tiger whirlpool diff --git a/src/build-data/policy/modern.txt b/src/build-data/policy/modern.txt index e6b58dcf7..def5da2b8 100644 --- a/src/build-data/policy/modern.txt +++ b/src/build-data/policy/modern.txt @@ -101,7 +101,6 @@ md4 gost_3411 cfb -ecb ofb elgamal diff --git a/sonar-project.properties b/src/build-data/sonar-project.properties index 408210b81..408210b81 100644 --- a/sonar-project.properties +++ b/src/build-data/sonar-project.properties diff --git a/src/build-data/sphinx/conf.py b/src/build-data/sphinx/conf.py index e144944f3..d08bb1d57 100644 --- a/src/build-data/sphinx/conf.py +++ b/src/build-data/sphinx/conf.py @@ -59,7 +59,7 @@ source_encoding = 'utf-8-sig' master_doc = 'contents' project = u'botan' -copyright = u'2000-2014, Jack Lloyd' +copyright = u'2000-2016, Jack Lloyd' version = '%d.%d' % (botan_version.release_major, botan_version.release_minor) @@ -198,8 +198,8 @@ htmlhelp_basename = 'botandoc' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('contents', 'botan.tex', u'botan Reference Manual', - u'Jack Lloyd', 'manual'), + ('contents', 'botan.tex', u'Botan Reference Manual', + u'Jack Lloyd \\and Daniel Neus \\and René Korthaus \\and Juraj Somorovsky \\and Tobias Niemann', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of diff --git a/src/cli/credentials.h b/src/cli/credentials.h index 95bbd5aa4..71acdc83d 100644 --- a/src/cli/credentials.h +++ b/src/cli/credentials.h @@ -92,24 +92,6 @@ class Basic_Credentials_Manager : public Botan::Credentials_Manager return v; } - void verify_certificate_chain( - const std::string& type, - const std::string& purported_hostname, - const std::vector<Botan::X509_Certificate>& cert_chain) override - { - try - { - Credentials_Manager::verify_certificate_chain(type, - purported_hostname, - cert_chain); - } - catch(std::exception& e) - { - std::cout << e.what() << std::endl; - //throw; - } - } - std::vector<Botan::X509_Certificate> cert_chain( const std::vector<std::string>& algos, const std::string& type, diff --git a/src/cli/speed.cpp b/src/cli/speed.cpp index 6fac9411c..cd01f9180 100644 --- a/src/cli/speed.cpp +++ b/src/cli/speed.cpp @@ -1188,8 +1188,9 @@ class Speed final : public Command std::chrono::milliseconds msec) { std::vector<std::string> xmss_params{ - "XMSS_SHA2-256_W16_H10", "XMSS_SHA2-512_W16_H10", + "XMSS_SHA2-512_W16_H16", + "XMSS_SHA2-512_W16_H20", }; for(std::string params : xmss_params) diff --git a/src/cli/tls_client.cpp b/src/cli/tls_client.cpp index 0d96f3348..30871791c 100644 --- a/src/cli/tls_client.cpp +++ b/src/cli/tls_client.cpp @@ -10,6 +10,8 @@ #if defined(BOTAN_HAS_TLS) && defined(BOTAN_TARGET_OS_HAS_SOCKETS) #include <botan/tls_client.h> +#include <botan/x509path.h> +#include <botan/ocsp.h> #include <botan/hex.h> #if defined(BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER) @@ -250,6 +252,42 @@ class TLS_Client final : public Command, public Botan::TLS::Callbacks return fd; } + void tls_verify_cert_chain( + const std::vector<Botan::X509_Certificate>& cert_chain, + const std::vector<std::shared_ptr<const Botan::OCSP::Response>>& ocsp, + const std::vector<Botan::Certificate_Store*>& trusted_roots, + Botan::Usage_Type usage, + const std::string& hostname, + const Botan::TLS::Policy& policy) override + { + if(cert_chain.empty()) + throw std::invalid_argument("Certificate chain was empty"); + + Botan::Path_Validation_Restrictions restrictions(policy.require_cert_revocation_info(), + policy.minimum_signature_strength()); + + auto ocsp_timeout = std::chrono::milliseconds(1000); + + Botan::Path_Validation_Result result = + Botan::x509_path_validate(cert_chain, + restrictions, + trusted_roots, + hostname, + usage, + std::chrono::system_clock::now(), + ocsp_timeout, + ocsp); + + std::cout << "Certificate validation status: " << result.result_string() << "\n"; + if(result.successful_validation()) + { + auto status = result.all_statuses(); + + if(status.size() > 0 && status[0].count(Botan::Certificate_Status_Code::OCSP_RESPONSE_GOOD)) + std::cout << "Valid OCSP response for this server\n"; + } + } + bool tls_session_established(const Botan::TLS::Session& session) override { output() << "Handshake complete, " << session.version().to_string() diff --git a/src/cli/x509.cpp b/src/cli/x509.cpp index 25261a2d1..7ae980d76 100644 --- a/src/cli/x509.cpp +++ b/src/cli/x509.cpp @@ -104,7 +104,8 @@ class Cert_Info final : public Command BOTAN_REGISTER_COMMAND("cert_info", Cert_Info); -#if defined(BOTAN_HAS_OCSP) +#if defined(BOTAN_HAS_OCSP) && defined(BOTAN_HAS_HTTP_UTIL) + class OCSP_Check final : public Command { public: @@ -119,7 +120,7 @@ class OCSP_Check final : public Command cas.add_certificate(issuer); Botan::OCSP::Response resp = Botan::OCSP::online_check(issuer, subject, &cas); - auto status = resp.status_for(issuer, subject); + auto status = resp.status_for(issuer, subject, std::chrono::system_clock::now()); if(status == Botan::Certificate_Status_Code::VERIFIED) { @@ -135,7 +136,7 @@ class OCSP_Check final : public Command BOTAN_REGISTER_COMMAND("ocsp_check", OCSP_Check); -#endif // OCSP +#endif // OCSP && HTTP class Cert_Verify final : public Command { diff --git a/src/extra_tests/fuzzers/GNUmakefile b/src/extra_tests/fuzzers/GNUmakefile index a086f8f1a..aa45eb040 100644 --- a/src/extra_tests/fuzzers/GNUmakefile +++ b/src/extra_tests/fuzzers/GNUmakefile @@ -12,17 +12,19 @@ LIBFUZZER_LIBS=llvm-build/libbotan-1.11.a libFuzzer.a AFL_LIBS=afl-build/libbotan-1.11.a #AFL_CXX=AFL_USE_ASAN=1 afl-g++ -m32 -AFL_CXX=afl-clang-fast++ +AFL_CXX=afl-g++ +AFL_CXX_TYPE=gcc CLANG_CXX=clang++ LIBFUZZER_PROGS=$(patsubst %,bin/llvm_fuzz_%,$(FUZZERS)) AFL_PROGS=$(patsubst %,bin/afl_fuzz_%,$(FUZZERS)) -all: afl_progs libfuzzer_progs +all: + @echo "make afl for AFL, llvm for libFuzzer" -afl_progs: $(AFL_PROGS) +afl: dirs afl-build $(AFL_PROGS) -libfuzzer_progs: $(LIBFUZZER_PROGS) +llvm: dirs llvm-build $(LIBFUZZER_PROGS) bin/llvm_fuzz_%: jigs/%.cpp $(LIBFUZZER_LIBS) $(CLANG_CXX) $(LIBFUZZER_FLAGS) -DUSE_LLVM_FUZZER $< $(LIBFUZZER_LIBS) -o $@ @@ -30,8 +32,21 @@ bin/llvm_fuzz_%: jigs/%.cpp $(LIBFUZZER_LIBS) bin/afl_fuzz_%: jigs/%.cpp $(AFL_LIBS) $(AFL_CXX) $(AFL_FLAGS) $< $(AFL_LIBS) -o $@ -# libFuzzer default is max_len 64 this sets 140 but allows override via args= +dirs: + mkdir -p bin + mkdir -p output + mkdir -p corpus + +afl-build: + ../../../configure.py $(CFG_FLAGS) --with-build-dir=afl-build --cc=$(AFL_CXX_TYPE) --cc-bin=$(AFL_CXX) + make -j$(nproc) -f afl-build/Makefile afl-build/libbotan-1.11.a + +llvm-build: + ../../../configure.py $(CFG_FLAGS) --with-build-dir=llvm-build --cc=clang --cc-bin=$(CLANG_CXX) --cc-abi-flags="$(CLANG_SAN_FLAGS)" + make -j$(nproc) -f llvm-build/Makefile llvm-build/libbotan-1.11.a + +# libFuzzer default is max_len 64 this sets 140 but allows override via args= run_llvm_%: bin/llvm_fuzz_% $(eval FUZZER = $(subst bin/llvm_fuzz_,,$<)) mkdir -p output/$(FUZZER)/llvm/queue @@ -55,6 +70,12 @@ cmin_%: bin/afl_fuzz_% clean: rm -f $(LIBFUZZER_PROGS) $(AFL_PROGS) +clean_builds: + rm -rf afl-build llvm-build + +libFuzzer: + svn co http://llvm.org/svn/llvm-project/llvm/trunk/lib/Fuzzer libFuzzer + libFuzzer.a: libFuzzer cd libFuzzer && clang -c -g -O2 -std=c++11 *.cpp ar cr libFuzzer.a libFuzzer/*.o diff --git a/src/extra_tests/fuzzers/jigs/ber_decode.cpp b/src/extra_tests/fuzzers/jigs/ber_decode.cpp new file mode 100644 index 000000000..0f5cc9f20 --- /dev/null +++ b/src/extra_tests/fuzzers/jigs/ber_decode.cpp @@ -0,0 +1,24 @@ +/* +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ +#include "driver.h" + +#include <botan/ber_dec.h> + +void fuzz(const uint8_t in[], size_t len) + { + try + { + DataSource_Memory input(in, len); + BER_Decoder dec(input); + + while(dec.more_items()) + { + BER_Object obj; + dec.get_next(obj); + } + } + catch(Botan::Exception& e) { } + } diff --git a/src/extra_tests/fuzzers/jigs/pkcs1.cpp b/src/extra_tests/fuzzers/jigs/pkcs1.cpp index 889308f0e..8a16d17e5 100644 --- a/src/extra_tests/fuzzers/jigs/pkcs1.cpp +++ b/src/extra_tests/fuzzers/jigs/pkcs1.cpp @@ -13,14 +13,14 @@ secure_vector<byte> simple_pkcs1_unpad(const byte in[], size_t len) if(len < 10) throw Botan::Decoding_Error("bad len"); - if(in[0] != 2) - throw Botan::Decoding_Error("bad field"); + if(in[0] != 0 || in[1] != 2) + throw Botan::Decoding_Error("bad header field"); - for(size_t i = 1; i < len; ++i) + for(size_t i = 2; i < len; ++i) { if(in[i] == 0) { - if(i < 9) + if(i < 10) // at least 8 padding bytes required throw Botan::Decoding_Error("insufficient padding bytes"); return secure_vector<byte>(in + i + 1, in + len); } @@ -42,9 +42,9 @@ void fuzz(const uint8_t in[], size_t len) secure_vector<byte> decoded = ((EME*)&pkcs1)->unpad(valid_mask, in, len); if(valid_mask == 0) - lib_rejected = false; - else if(valid_mask == 0xFF) lib_rejected = true; + else if(valid_mask == 0xFF) + lib_rejected = false; else abort(); } @@ -54,15 +54,24 @@ void fuzz(const uint8_t in[], size_t len) { ref_result = simple_pkcs1_unpad(in, len); } - catch(Botan::Decoding_Error&) { ref_rejected = true; } + catch(Botan::Decoding_Error& e) { ref_rejected = true; /*printf("%s\n", e.what());*/ } - FUZZER_ASSERT_EQUAL(lib_rejected, ref_rejected); + if(lib_rejected == ref_rejected) + { + return; // ok, they agree + } - if(lib_result != ref_result) + // otherwise: incorrect result, log info and crash + if(lib_rejected == true && ref_rejected == false) + { + std::cerr << "Library rejected input accepted by ref\n"; + std::cerr << "Ref decoded " << hex_encode(ref_result) << "\n"; + } + else if(ref_rejected == true && lib_rejected == false) { - std::cerr << hex_encode(lib_result) << " != ref \n" - << hex_encode(ref_result) << std::endl; - abort(); + std::cerr << "Library accepted input reject by ref\n"; + std::cerr << "Lib decoded " << hex_encode(lib_result) << "\n"; } + abort(); } diff --git a/src/extra_tests/fuzzers/jigs/tls_client.cpp b/src/extra_tests/fuzzers/jigs/tls_client.cpp index e0fd039c9..c176667d4 100644 --- a/src/extra_tests/fuzzers/jigs/tls_client.cpp +++ b/src/extra_tests/fuzzers/jigs/tls_client.cpp @@ -11,19 +11,6 @@ class Fuzzer_TLS_Client_Creds : public Credentials_Manager { public: - void verify_certificate_chain(const std::string& type, - const std::string& purported_hostname, - const std::vector<X509_Certificate>& cert_chain) override - { - try - { - Credentials_Manager::verify_certificate_chain(type, - purported_hostname, - cert_chain); - } - catch(std::exception& e) {} - } - std::string psk_identity_hint(const std::string&, const std::string&) override { return "psk_hint"; } std::string psk_identity(const std::string&, const std::string&, const std::string&) override { return "psk_id"; } SymmetricKey psk(const std::string&, const std::string&, const std::string&) override diff --git a/src/extra_tests/fuzzers/jigs/tls_client_hello.cpp b/src/extra_tests/fuzzers/jigs/tls_client_hello.cpp index 5705dca91..33b6f941a 100644 --- a/src/extra_tests/fuzzers/jigs/tls_client_hello.cpp +++ b/src/extra_tests/fuzzers/jigs/tls_client_hello.cpp @@ -12,10 +12,6 @@ void fuzz(const uint8_t in[], size_t len) { std::vector<uint8_t> v(in, in + len); Botan::TLS::Client_Hello ch(v); - - printf("%s\n", ch.version().to_string().c_str()); - if(ch.version() == Botan::TLS::Protocol_Version::TLS_V12) - abort(); } - catch(Botan::Exception& e) {printf("%s\n", e.what()); } + catch(Botan::Exception& e) {} } diff --git a/src/extra_tests/fuzzers/jigs/tls_server.cpp b/src/extra_tests/fuzzers/jigs/tls_server.cpp index 510f7f7b7..dea885de3 100644 --- a/src/extra_tests/fuzzers/jigs/tls_server.cpp +++ b/src/extra_tests/fuzzers/jigs/tls_server.cpp @@ -72,19 +72,6 @@ class Fuzzer_TLS_Server_Creds : public Credentials_Manager //m_rsa_key.reset(Botan::PKCS8::load_key(key_in, Botan::system_rng())); } - void verify_certificate_chain(const std::string& type, - const std::string& purported_hostname, - const std::vector<X509_Certificate>& cert_chain) override - { - try - { - Credentials_Manager::verify_certificate_chain(type, - purported_hostname, - cert_chain); - } - catch(std::exception& e) {} - } - std::vector<Botan::X509_Certificate> cert_chain( const std::vector<std::string>& algos, const std::string& type, diff --git a/src/extra_tests/fuzzers/readme.txt b/src/extra_tests/fuzzers/readme.txt index f10982508..e195b4e70 100644 --- a/src/extra_tests/fuzzers/readme.txt +++ b/src/extra_tests/fuzzers/readme.txt @@ -3,7 +3,13 @@ The code in this directory is for testing various message decoders and math functions using the fuzzers AFL (http://lcamtuf.coredump.cx/afl/) and libFuzzer (http://llvm.org/docs/LibFuzzer.html). -Run setup.sh to set up builds for both fuzzers +To build for AFL, run + + make afl + +For libFuzzer + + make llvm To add a new fuzzer, create a new file in jigs/, include "driver.h", and implement the function with the signature diff --git a/src/extra_tests/fuzzers/setup.sh b/src/extra_tests/fuzzers/setup.sh deleted file mode 100755 index a810d947b..000000000 --- a/src/extra_tests/fuzzers/setup.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh - -mkdir bin -mkdir output -mkdir corpus - -CFG_FLAGS="--with-debug-info --unsafe-fuzzer-mode --minimized-build --enable-modules=tls,chacha20poly1305,ocb,ccm,system_rng,auto_rng" - -if [ ! -d libFuzzer ]; then - svn co http://llvm.org/svn/llvm-project/llvm/trunk/lib/Fuzzer libFuzzer -fi - -exit - -# Just need the static lib, not CLI or tests - -../../../configure.py $CFG_FLAGS --with-build-dir=afl-build --cc=clang --cc-bin='afl-clang-fast++' -make -f afl-build/Makefile afl-build/libbotan-1.11.a -j8 - -CLANG_COV_FLAGS="-fsanitize=address,undefined -fsanitize-coverage=edge,indirect-calls,8bit-counters -fno-sanitize-recover=undefined" -../../../configure.py $CFG_FLAGS --with-build-dir=llvm-build --cc=clang "--cc-abi-flags=$CLANG_COV_FLAGS" -make -f llvm-build/Makefile llvm-build/libbotan-1.11.a -j8 diff --git a/src/extra_tests/tls_scanner/policy.txt b/src/extra_tests/tls_scanner/policy.txt new file mode 100644 index 000000000..a9854ee54 --- /dev/null +++ b/src/extra_tests/tls_scanner/policy.txt @@ -0,0 +1,19 @@ +allow_tls10=true +allow_tls11=true +allow_tls12=true +allow_dtls10=false +allow_dtls12=false + +# Camellia first just to see if there is anyone out there who will negotiate it with us +ciphers=Camellia-128 Camellia-256 Camellia-128/GCM Camellia-256/GCM ChaCha20Poly1305 AES-256/GCM AES-128/GCM AES-256 AES-128 +signature_hashes=SHA-384 SHA-256 SHA-1 +macs=AEAD SHA-384 SHA-256 SHA-1 +key_exchange_methods=CECPQ1 ECDH DH RSA +signature_methods=ECDSA RSA DSA +ecc_curves=x25519 secp256r1 secp384r1 +minimum_dh_group_size=1024 +minimum_ecdh_group_size=255 +minimum_rsa_bits=2048 + +allow_insecure_renegotiation=false +allow_server_initiated_renegotiation=false diff --git a/src/extra_tests/tls_scanner/tls_scanner.py b/src/extra_tests/tls_scanner/tls_scanner.py index f36ee6bfa..8fdf046ca 100755 --- a/src/extra_tests/tls_scanner/tls_scanner.py +++ b/src/extra_tests/tls_scanner/tls_scanner.py @@ -1,6 +1,7 @@ #!/usr/bin/python2 import sys +import time import subprocess import re @@ -27,16 +28,24 @@ def scanner(args = None): scanners = {} for url in [s.strip() for s in open(args[1]).readlines()]: - scanners[url] = subprocess.Popen(['../../../botan', 'tls_client', url], stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE) + scanners[url] = subprocess.Popen(['../../../botan', 'tls_client', '--policy=policy.txt', url], + stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE) for url in scanners.keys(): scanners[url].stdin.close() report = {} + timeout = 10 for url in scanners.keys(): print "waiting for", url - scanners[url].wait() + + for i in range(timeout): + scanners[url].poll() + if scanners[url].returncode != None: + break + #print "Waiting %d more seconds for %s" % (timeout-i, url) + time.sleep(1) if scanners[url].returncode != None: output = scanners[url].stdout.read() + scanners[url].stderr.read() diff --git a/src/extra_tests/tls_scanner/urls.txt b/src/extra_tests/tls_scanner/urls.txt index 33c7e0870..a5bcf349e 100644 --- a/src/extra_tests/tls_scanner/urls.txt +++ b/src/extra_tests/tls_scanner/urls.txt @@ -22,7 +22,6 @@ hp.com huawei.com ibm.com ietf.org -intel.com intuit.com linkedin.com medium.com @@ -32,6 +31,12 @@ nec.com netflix.com openssl.org oracle.com +sgi.com +chase.com +bankofamerica.com +citibank.com +wellsfargo.com +ebay.com paypal.com pwc.com randombit.net @@ -42,7 +47,6 @@ sas.com siemens.com sony.com stripe.com -swift.com symantec.com tls.mbed.org twitter.com diff --git a/src/lib/asn1/ber_dec.cpp b/src/lib/asn1/ber_dec.cpp index ac676cd08..81c04aa6a 100644 --- a/src/lib/asn1/ber_dec.cpp +++ b/src/lib/asn1/ber_dec.cpp @@ -9,6 +9,7 @@ #include <botan/ber_dec.h> #include <botan/bigint.h> #include <botan/loadstor.h> +#include <botan/internal/safeint.h> namespace Botan { @@ -126,7 +127,9 @@ size_t find_eoc(DataSource* ber) size_t item_size = decode_length(&source, length_size); source.discard_next(item_size); - length += item_size + length_size + tag_size; + length = BOTAN_CHECKED_ADD(length, item_size); + length = BOTAN_CHECKED_ADD(length, tag_size); + length = BOTAN_CHECKED_ADD(length, length_size); if(type_tag == EOC && class_tag == UNIVERSAL) break; diff --git a/src/lib/asn1/oids.cpp b/src/lib/asn1/oids.cpp index 2f7597981..eb5101e85 100644 --- a/src/lib/asn1/oids.cpp +++ b/src/lib/asn1/oids.cpp @@ -1,7 +1,10 @@ /* * OID maps * -* This file was automatically generated by ./src/scripts/oids.py on 2016-11-18 +* This file was automatically generated by ./src/scripts/oids.py on 2016-11-21 +* +* All manual edits to this file will be lost. Edit the script +* then regenerate this source file. * * Botan is released under the Simplified BSD License (see license.txt) */ diff --git a/src/lib/base/buf_comp.h b/src/lib/base/buf_comp.h index d0793b84b..264b16bd0 100644 --- a/src/lib/base/buf_comp.h +++ b/src/lib/base/buf_comp.h @@ -101,6 +101,13 @@ class BOTAN_DLL Buffered_Computation return output; } + std::vector<byte> final_stdvec() + { + std::vector<byte> output(output_length()); + final_result(output.data()); + return output; + } + template<typename Alloc> void final(std::vector<byte, Alloc>& out) { diff --git a/src/lib/block/aes/aes.cpp b/src/lib/block/aes/aes.cpp index 39f5bd0db..8c7000135 100644 --- a/src/lib/block/aes/aes.cpp +++ b/src/lib/block/aes/aes.cpp @@ -168,12 +168,15 @@ void aes_encrypt_n(const byte in[], byte out[], } Z &= TE[82]; // this is zero, which hopefully the compiler cannot deduce - for(size_t i = 0; i != blocks; ++i) + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks; ++i) { - u32bit T0 = load_be<u32bit>(in, 0) ^ EK[0]; - u32bit T1 = load_be<u32bit>(in, 1) ^ EK[1]; - u32bit T2 = load_be<u32bit>(in, 2) ^ EK[2]; - u32bit T3 = load_be<u32bit>(in, 3) ^ EK[3]; + u32bit T0, T1, T2, T3; + load_be(in + 16*i, T0, T1, T2, T3); + + T0 ^= EK[0]; + T1 ^= EK[1]; + T2 ^= EK[2]; + T3 ^= EK[3]; T0 ^= Z; @@ -226,25 +229,22 @@ void aes_encrypt_n(const byte in[], byte out[], TE[get_byte(2, T1) + 512] ^ TE[get_byte(3, T2) + 768]; } - out[ 0] = SE[get_byte(0, B0)] ^ ME[0]; - out[ 1] = SE[get_byte(1, B1)] ^ ME[1]; - out[ 2] = SE[get_byte(2, B2)] ^ ME[2]; - out[ 3] = SE[get_byte(3, B3)] ^ ME[3]; - out[ 4] = SE[get_byte(0, B1)] ^ ME[4]; - out[ 5] = SE[get_byte(1, B2)] ^ ME[5]; - out[ 6] = SE[get_byte(2, B3)] ^ ME[6]; - out[ 7] = SE[get_byte(3, B0)] ^ ME[7]; - out[ 8] = SE[get_byte(0, B2)] ^ ME[8]; - out[ 9] = SE[get_byte(1, B3)] ^ ME[9]; - out[10] = SE[get_byte(2, B0)] ^ ME[10]; - out[11] = SE[get_byte(3, B1)] ^ ME[11]; - out[12] = SE[get_byte(0, B3)] ^ ME[12]; - out[13] = SE[get_byte(1, B0)] ^ ME[13]; - out[14] = SE[get_byte(2, B1)] ^ ME[14]; - out[15] = SE[get_byte(3, B2)] ^ ME[15]; - - in += 16; - out += 16; + out[16*i+ 0] = SE[get_byte(0, B0)] ^ ME[0]; + out[16*i+ 1] = SE[get_byte(1, B1)] ^ ME[1]; + out[16*i+ 2] = SE[get_byte(2, B2)] ^ ME[2]; + out[16*i+ 3] = SE[get_byte(3, B3)] ^ ME[3]; + out[16*i+ 4] = SE[get_byte(0, B1)] ^ ME[4]; + out[16*i+ 5] = SE[get_byte(1, B2)] ^ ME[5]; + out[16*i+ 6] = SE[get_byte(2, B3)] ^ ME[6]; + out[16*i+ 7] = SE[get_byte(3, B0)] ^ ME[7]; + out[16*i+ 8] = SE[get_byte(0, B2)] ^ ME[8]; + out[16*i+ 9] = SE[get_byte(1, B3)] ^ ME[9]; + out[16*i+10] = SE[get_byte(2, B0)] ^ ME[10]; + out[16*i+11] = SE[get_byte(3, B1)] ^ ME[11]; + out[16*i+12] = SE[get_byte(0, B3)] ^ ME[12]; + out[16*i+13] = SE[get_byte(1, B0)] ^ ME[13]; + out[16*i+14] = SE[get_byte(2, B1)] ^ ME[14]; + out[16*i+15] = SE[get_byte(3, B2)] ^ ME[15]; } } diff --git a/src/lib/block/aes/aes_ssse3/aes_ssse3.cpp b/src/lib/block/aes/aes_ssse3/aes_ssse3.cpp index ef24795bb..d8c7e7314 100644 --- a/src/lib/block/aes/aes_ssse3/aes_ssse3.cpp +++ b/src/lib/block/aes/aes_ssse3/aes_ssse3.cpp @@ -355,7 +355,7 @@ void AES_128::ssse3_encrypt_n(const byte in[], byte out[], size_t blocks) const CT::poison(in, blocks * block_size()); - for(size_t i = 0; i != blocks; ++i) + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks; ++i) { __m128i B = _mm_loadu_si128(in_mm + i); _mm_storeu_si128(out_mm + i, aes_ssse3_encrypt(B, keys, 10)); @@ -378,7 +378,7 @@ void AES_128::ssse3_decrypt_n(const byte in[], byte out[], size_t blocks) const CT::poison(in, blocks * block_size()); - for(size_t i = 0; i != blocks; ++i) + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks; ++i) { __m128i B = _mm_loadu_si128(in_mm + i); _mm_storeu_si128(out_mm + i, aes_ssse3_decrypt(B, keys, 10)); diff --git a/src/lib/block/blowfish/blowfish.cpp b/src/lib/block/blowfish/blowfish.cpp index 7a06cf797..69d345baa 100644 --- a/src/lib/block/blowfish/blowfish.cpp +++ b/src/lib/block/blowfish/blowfish.cpp @@ -202,10 +202,10 @@ void Blowfish::encrypt_n(const byte in[], byte out[], size_t blocks) const const u32bit* S3 = &m_S[512]; const u32bit* S4 = &m_S[768]; - for(size_t i = 0; i != blocks; ++i) + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks; ++i) { - u32bit L = load_be<u32bit>(in, 0); - u32bit R = load_be<u32bit>(in, 1); + u32bit L, R; + load_be(in + BLOCK_SIZE*i, L, R); for(size_t j = 0; j != 16; j += 2) { @@ -220,10 +220,7 @@ void Blowfish::encrypt_n(const byte in[], byte out[], size_t blocks) const L ^= m_P[16]; R ^= m_P[17]; - store_be(out, R, L); - - in += BLOCK_SIZE; - out += BLOCK_SIZE; + store_be(out + BLOCK_SIZE*i, R, L); } } @@ -237,10 +234,10 @@ void Blowfish::decrypt_n(const byte in[], byte out[], size_t blocks) const const u32bit* S3 = &m_S[512]; const u32bit* S4 = &m_S[768]; - for(size_t i = 0; i != blocks; ++i) + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks; ++i) { - u32bit L = load_be<u32bit>(in, 0); - u32bit R = load_be<u32bit>(in, 1); + u32bit L, R; + load_be(in + BLOCK_SIZE*i, L, R); for(size_t j = 17; j != 1; j -= 2) { @@ -255,10 +252,7 @@ void Blowfish::decrypt_n(const byte in[], byte out[], size_t blocks) const L ^= m_P[1]; R ^= m_P[0]; - store_be(out, R, L); - - in += BLOCK_SIZE; - out += BLOCK_SIZE; + store_be(out + BLOCK_SIZE*i, R, L); } } diff --git a/src/lib/block/camellia/camellia.cpp b/src/lib/block/camellia/camellia.cpp index ac5d57d4e..5ac13b9ab 100644 --- a/src/lib/block/camellia/camellia.cpp +++ b/src/lib/block/camellia/camellia.cpp @@ -645,10 +645,10 @@ inline u64bit FLINV(u64bit v, u64bit K) void encrypt(const byte in[], byte out[], size_t blocks, const secure_vector<u64bit>& SK, const size_t rounds) { - for(size_t i = 0; i != blocks; ++i) + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks; ++i) { - u64bit D1 = load_be<u64bit>(in, 0); - u64bit D2 = load_be<u64bit>(in, 1); + u64bit D1, D2; + load_be(in + 16*i, D1, D2); const u64bit* K = SK.data(); @@ -676,10 +676,7 @@ void encrypt(const byte in[], byte out[], size_t blocks, D2 ^= *K++; D1 ^= *K++; - store_be(out, D2, D1); - - in += 16; - out += 16; + store_be(out + 16*i, D2, D1); } } @@ -689,10 +686,10 @@ void encrypt(const byte in[], byte out[], size_t blocks, void decrypt(const byte in[], byte out[], size_t blocks, const secure_vector<u64bit>& SK, const size_t rounds) { - for(size_t i = 0; i != blocks; ++i) + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks; ++i) { - u64bit D1 = load_be<u64bit>(in, 0); - u64bit D2 = load_be<u64bit>(in, 1); + u64bit D1, D2; + load_be(in + 16*i, D1, D2); const u64bit* K = &SK[SK.size()-1]; @@ -720,10 +717,7 @@ void decrypt(const byte in[], byte out[], size_t blocks, D1 ^= *K--; D2 ^= *K; - store_be(out, D2, D1); - - in += 16; - out += 16; + store_be(out + 16*i, D2, D1); } } diff --git a/src/lib/block/cascade/info.txt b/src/lib/block/cascade/info.txt index 445e49086..14f618fd0 100644 --- a/src/lib/block/cascade/info.txt +++ b/src/lib/block/cascade/info.txt @@ -3,7 +3,3 @@ define CASCADE 20131128 <header:public> cascade.h </header:public> - -<source> -cascade.cpp -</source> diff --git a/src/lib/block/cast/cast128.cpp b/src/lib/block/cast/cast128.cpp index 53f7d4611..96c4f45a7 100644 --- a/src/lib/block/cast/cast128.cpp +++ b/src/lib/block/cast/cast128.cpp @@ -50,10 +50,10 @@ inline void R3(u32bit& L, u32bit R, u32bit MK, byte RK) */ void CAST_128::encrypt_n(const byte in[], byte out[], size_t blocks) const { - for(size_t i = 0; i != blocks; ++i) + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks; ++i) { - u32bit L = load_be<u32bit>(in, 0); - u32bit R = load_be<u32bit>(in, 1); + u32bit L, R; + load_be(in + BLOCK_SIZE*i, L, R); R1(L, R, m_MK[ 0], m_RK[ 0]); R2(R, L, m_MK[ 1], m_RK[ 1]); @@ -72,10 +72,7 @@ void CAST_128::encrypt_n(const byte in[], byte out[], size_t blocks) const R3(L, R, m_MK[14], m_RK[14]); R1(R, L, m_MK[15], m_RK[15]); - store_be(out, R, L); - - in += BLOCK_SIZE; - out += BLOCK_SIZE; + store_be(out + BLOCK_SIZE*i, R, L); } } @@ -84,10 +81,10 @@ void CAST_128::encrypt_n(const byte in[], byte out[], size_t blocks) const */ void CAST_128::decrypt_n(const byte in[], byte out[], size_t blocks) const { - for(size_t i = 0; i != blocks; ++i) + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks; ++i) { - u32bit L = load_be<u32bit>(in, 0); - u32bit R = load_be<u32bit>(in, 1); + u32bit L, R; + load_be(in + BLOCK_SIZE*i, L, R); R1(L, R, m_MK[15], m_RK[15]); R3(R, L, m_MK[14], m_RK[14]); @@ -106,10 +103,7 @@ void CAST_128::decrypt_n(const byte in[], byte out[], size_t blocks) const R2(L, R, m_MK[ 1], m_RK[ 1]); R1(R, L, m_MK[ 0], m_RK[ 0]); - store_be(out, R, L); - - in += BLOCK_SIZE; - out += BLOCK_SIZE; + store_be(out + BLOCK_SIZE*i, R, L); } } diff --git a/src/lib/block/des/des.cpp b/src/lib/block/des/des.cpp index 88671df8d..a55c43ec7 100644 --- a/src/lib/block/des/des.cpp +++ b/src/lib/block/des/des.cpp @@ -144,12 +144,12 @@ void des_decrypt(u32bit& L, u32bit& R, */ void DES::encrypt_n(const byte in[], byte out[], size_t blocks) const { - for(size_t i = 0; i != blocks; ++i) + for(size_t i = 0; i < blocks; ++i) { - u64bit T = (DES_IPTAB1[in[0]] ) | (DES_IPTAB1[in[1]] << 1) | - (DES_IPTAB1[in[2]] << 2) | (DES_IPTAB1[in[3]] << 3) | - (DES_IPTAB1[in[4]] << 4) | (DES_IPTAB1[in[5]] << 5) | - (DES_IPTAB1[in[6]] << 6) | (DES_IPTAB2[in[7]] ); + u64bit T = (DES_IPTAB1[in[8*i+0]] ) | (DES_IPTAB1[in[8*i+1]] << 1) | + (DES_IPTAB1[in[8*i+2]] << 2) | (DES_IPTAB1[in[8*i+3]] << 3) | + (DES_IPTAB1[in[8*i+4]] << 4) | (DES_IPTAB1[in[8*i+5]] << 5) | + (DES_IPTAB1[in[8*i+6]] << 6) | (DES_IPTAB2[in[8*i+7]] ); u32bit L = static_cast<u32bit>(T >> 32); u32bit R = static_cast<u32bit>(T); @@ -162,10 +162,7 @@ void DES::encrypt_n(const byte in[], byte out[], size_t blocks) const (DES_FPTAB1[get_byte(2, R)] ) | (DES_FPTAB2[get_byte(3, R)] ); T = rotate_left(T, 32); - store_be(T, out); - - in += BLOCK_SIZE; - out += BLOCK_SIZE; + store_be(T, out + 8*i); } } @@ -174,12 +171,12 @@ void DES::encrypt_n(const byte in[], byte out[], size_t blocks) const */ void DES::decrypt_n(const byte in[], byte out[], size_t blocks) const { - for(size_t i = 0; i != blocks; ++i) + for(size_t i = 0; i < blocks; ++i) { - u64bit T = (DES_IPTAB1[in[0]] ) | (DES_IPTAB1[in[1]] << 1) | - (DES_IPTAB1[in[2]] << 2) | (DES_IPTAB1[in[3]] << 3) | - (DES_IPTAB1[in[4]] << 4) | (DES_IPTAB1[in[5]] << 5) | - (DES_IPTAB1[in[6]] << 6) | (DES_IPTAB2[in[7]] ); + u64bit T = (DES_IPTAB1[in[BLOCK_SIZE*i+0]] ) | (DES_IPTAB1[in[BLOCK_SIZE*i+1]] << 1) | + (DES_IPTAB1[in[BLOCK_SIZE*i+2]] << 2) | (DES_IPTAB1[in[BLOCK_SIZE*i+3]] << 3) | + (DES_IPTAB1[in[BLOCK_SIZE*i+4]] << 4) | (DES_IPTAB1[in[BLOCK_SIZE*i+5]] << 5) | + (DES_IPTAB1[in[BLOCK_SIZE*i+6]] << 6) | (DES_IPTAB2[in[BLOCK_SIZE*i+7]] ); u32bit L = static_cast<u32bit>(T >> 32); u32bit R = static_cast<u32bit>(T); @@ -193,10 +190,7 @@ void DES::decrypt_n(const byte in[], byte out[], size_t blocks) const T = rotate_left(T, 32); - store_be(T, out); - - in += BLOCK_SIZE; - out += BLOCK_SIZE; + store_be(T, out + BLOCK_SIZE*i); } } diff --git a/src/lib/block/idea/idea.cpp b/src/lib/block/idea/idea.cpp index 85cc5e757..1fe25d599 100644 --- a/src/lib/block/idea/idea.cpp +++ b/src/lib/block/idea/idea.cpp @@ -67,12 +67,10 @@ void idea_op(const byte in[], byte out[], size_t blocks, const u16bit K[52]) CT::poison(out, blocks * 8); CT::poison(K, 52); - for(size_t i = 0; i != blocks; ++i) + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks; ++i) { - u16bit X1 = load_be<u16bit>(in + BLOCK_SIZE*i, 0); - u16bit X2 = load_be<u16bit>(in + BLOCK_SIZE*i, 1); - u16bit X3 = load_be<u16bit>(in + BLOCK_SIZE*i, 2); - u16bit X4 = load_be<u16bit>(in + BLOCK_SIZE*i, 3); + u16bit X1, X2, X3, X4; + load_be(in + BLOCK_SIZE*i, X1, X2, X3, X4); for(size_t j = 0; j != 8; ++j) { diff --git a/src/lib/block/serpent/info.txt b/src/lib/block/serpent/info.txt index aa29c567f..6337ef6c0 100644 --- a/src/lib/block/serpent/info.txt +++ b/src/lib/block/serpent/info.txt @@ -7,7 +7,3 @@ serpent.h <header:internal> serpent_sbox.h </header:internal> - -<source> -serpent.cpp -</source> diff --git a/src/lib/block/serpent/serpent.cpp b/src/lib/block/serpent/serpent.cpp index 07088211d..a1326b888 100644 --- a/src/lib/block/serpent/serpent.cpp +++ b/src/lib/block/serpent/serpent.cpp @@ -70,12 +70,10 @@ void Serpent::encrypt_n(const byte in[], byte out[], size_t blocks) const } #endif - for(size_t i = 0; i != blocks; ++i) + BOTAN_PARALLEL_SIMD_FOR(size_t i = 0; i < blocks; ++i) { - u32bit B0 = load_le<u32bit>(in, 0); - u32bit B1 = load_le<u32bit>(in, 1); - u32bit B2 = load_le<u32bit>(in, 2); - u32bit B3 = load_le<u32bit>(in, 3); + u32bit B0, B1, B2, B3; + load_le(in + 16*i, B0, B1, B2, B3); key_xor( 0,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor( 1,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); @@ -110,10 +108,7 @@ void Serpent::encrypt_n(const byte in[], byte out[], size_t blocks) const key_xor(30,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(31,B0,B1,B2,B3); SBoxE8(B0,B1,B2,B3); key_xor(32,B0,B1,B2,B3); - store_le(out, B0, B1, B2, B3); - - in += BLOCK_SIZE; - out += BLOCK_SIZE; + store_le(out + 16*i, B0, B1, B2, B3); } } @@ -135,12 +130,10 @@ void Serpent::decrypt_n(const byte in[], byte out[], size_t blocks) const } #endif - for(size_t i = 0; i != blocks; ++i) + BOTAN_PARALLEL_SIMD_FOR(size_t i = 0; i < blocks; ++i) { - u32bit B0 = load_le<u32bit>(in, 0); - u32bit B1 = load_le<u32bit>(in, 1); - u32bit B2 = load_le<u32bit>(in, 2); - u32bit B3 = load_le<u32bit>(in, 3); + u32bit B0, B1, B2, B3; + load_le(in + 16*i, B0, B1, B2, B3); key_xor(32,B0,B1,B2,B3); SBoxD8(B0,B1,B2,B3); key_xor(31,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(30,B0,B1,B2,B3); @@ -175,10 +168,7 @@ void Serpent::decrypt_n(const byte in[], byte out[], size_t blocks) const i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor( 1,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor( 0,B0,B1,B2,B3); - store_le(out, B0, B1, B2, B3); - - in += BLOCK_SIZE; - out += BLOCK_SIZE; + store_le(out + 16*i, B0, B1, B2, B3); } } @@ -205,24 +195,47 @@ void Serpent::key_schedule(const byte key[], size_t length) W[i] = rotate_left(wi, 11); } - SBoxE4(W[ 8],W[ 9],W[ 10],W[ 11]); SBoxE3(W[ 12],W[ 13],W[ 14],W[ 15]); - SBoxE2(W[ 16],W[ 17],W[ 18],W[ 19]); SBoxE1(W[ 20],W[ 21],W[ 22],W[ 23]); - SBoxE8(W[ 24],W[ 25],W[ 26],W[ 27]); SBoxE7(W[ 28],W[ 29],W[ 30],W[ 31]); - SBoxE6(W[ 32],W[ 33],W[ 34],W[ 35]); SBoxE5(W[ 36],W[ 37],W[ 38],W[ 39]); - SBoxE4(W[ 40],W[ 41],W[ 42],W[ 43]); SBoxE3(W[ 44],W[ 45],W[ 46],W[ 47]); - SBoxE2(W[ 48],W[ 49],W[ 50],W[ 51]); SBoxE1(W[ 52],W[ 53],W[ 54],W[ 55]); - SBoxE8(W[ 56],W[ 57],W[ 58],W[ 59]); SBoxE7(W[ 60],W[ 61],W[ 62],W[ 63]); - SBoxE6(W[ 64],W[ 65],W[ 66],W[ 67]); SBoxE5(W[ 68],W[ 69],W[ 70],W[ 71]); - SBoxE4(W[ 72],W[ 73],W[ 74],W[ 75]); SBoxE3(W[ 76],W[ 77],W[ 78],W[ 79]); - SBoxE2(W[ 80],W[ 81],W[ 82],W[ 83]); SBoxE1(W[ 84],W[ 85],W[ 86],W[ 87]); - SBoxE8(W[ 88],W[ 89],W[ 90],W[ 91]); SBoxE7(W[ 92],W[ 93],W[ 94],W[ 95]); - SBoxE6(W[ 96],W[ 97],W[ 98],W[ 99]); SBoxE5(W[100],W[101],W[102],W[103]); - SBoxE4(W[104],W[105],W[106],W[107]); SBoxE3(W[108],W[109],W[110],W[111]); - SBoxE2(W[112],W[113],W[114],W[115]); SBoxE1(W[116],W[117],W[118],W[119]); - SBoxE8(W[120],W[121],W[122],W[123]); SBoxE7(W[124],W[125],W[126],W[127]); - SBoxE6(W[128],W[129],W[130],W[131]); SBoxE5(W[132],W[133],W[134],W[135]); + SBoxE1(W[ 20],W[ 21],W[ 22],W[ 23]); + SBoxE1(W[ 52],W[ 53],W[ 54],W[ 55]); + SBoxE1(W[ 84],W[ 85],W[ 86],W[ 87]); + SBoxE1(W[116],W[117],W[118],W[119]); + + SBoxE2(W[ 16],W[ 17],W[ 18],W[ 19]); + SBoxE2(W[ 48],W[ 49],W[ 50],W[ 51]); + SBoxE2(W[ 80],W[ 81],W[ 82],W[ 83]); + SBoxE2(W[112],W[113],W[114],W[115]); + + SBoxE3(W[ 12],W[ 13],W[ 14],W[ 15]); + SBoxE3(W[ 44],W[ 45],W[ 46],W[ 47]); + SBoxE3(W[ 76],W[ 77],W[ 78],W[ 79]); + SBoxE3(W[108],W[109],W[110],W[111]); + + SBoxE4(W[ 8],W[ 9],W[ 10],W[ 11]); + SBoxE4(W[ 40],W[ 41],W[ 42],W[ 43]); + SBoxE4(W[ 72],W[ 73],W[ 74],W[ 75]); + SBoxE4(W[104],W[105],W[106],W[107]); SBoxE4(W[136],W[137],W[138],W[139]); + SBoxE5(W[ 36],W[ 37],W[ 38],W[ 39]); + SBoxE5(W[ 68],W[ 69],W[ 70],W[ 71]); + SBoxE5(W[100],W[101],W[102],W[103]); + SBoxE5(W[132],W[133],W[134],W[135]); + + SBoxE6(W[ 32],W[ 33],W[ 34],W[ 35]); + SBoxE6(W[ 64],W[ 65],W[ 66],W[ 67]); + SBoxE6(W[ 96],W[ 97],W[ 98],W[ 99]); + SBoxE6(W[128],W[129],W[130],W[131]); + + SBoxE7(W[ 28],W[ 29],W[ 30],W[ 31]); + SBoxE7(W[ 60],W[ 61],W[ 62],W[ 63]); + SBoxE7(W[ 92],W[ 93],W[ 94],W[ 95]); + SBoxE7(W[124],W[125],W[126],W[127]); + + SBoxE8(W[ 24],W[ 25],W[ 26],W[ 27]); + SBoxE8(W[ 56],W[ 57],W[ 58],W[ 59]); + SBoxE8(W[ 88],W[ 89],W[ 90],W[ 91]); + SBoxE8(W[120],W[121],W[122],W[123]); + m_round_key.assign(W.begin() + 8, W.end()); } diff --git a/src/lib/block/serpent/serpent_simd/serp_simd.cpp b/src/lib/block/serpent/serpent_simd/serpent_simd.cpp index 7571e5511..7571e5511 100644 --- a/src/lib/block/serpent/serpent_simd/serp_simd.cpp +++ b/src/lib/block/serpent/serpent_simd/serpent_simd.cpp diff --git a/src/lib/block/threefish/threefish.cpp b/src/lib/block/threefish/threefish.cpp index f592021fb..2acdef020 100644 --- a/src/lib/block/threefish/threefish.cpp +++ b/src/lib/block/threefish/threefish.cpp @@ -122,16 +122,10 @@ void Threefish_512::encrypt_n(const byte in[], byte out[], size_t blocks) const } #endif - for(size_t i = 0; i != blocks; ++i) + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks; ++i) { - u64bit X0 = load_le<u64bit>(in, 0); - u64bit X1 = load_le<u64bit>(in, 1); - u64bit X2 = load_le<u64bit>(in, 2); - u64bit X3 = load_le<u64bit>(in, 3); - u64bit X4 = load_le<u64bit>(in, 4); - u64bit X5 = load_le<u64bit>(in, 5); - u64bit X6 = load_le<u64bit>(in, 6); - u64bit X7 = load_le<u64bit>(in, 7); + u64bit X0, X1, X2, X3, X4, X5, X6, X7; + load_le(in + BLOCK_SIZE*i, X0, X1, X2, X3, X4, X5, X6, X7); THREEFISH_INJECT_KEY(0); @@ -145,10 +139,7 @@ void Threefish_512::encrypt_n(const byte in[], byte out[], size_t blocks) const THREEFISH_ENC_8_ROUNDS(15,16); THREEFISH_ENC_8_ROUNDS(17,18); - store_le(out, X0, X1, X2, X3, X4, X5, X6, X7); - - in += 64; - out += 64; + store_le(out + BLOCK_SIZE*i, X0, X1, X2, X3, X4, X5, X6, X7); } } @@ -211,16 +202,10 @@ void Threefish_512::decrypt_n(const byte in[], byte out[], size_t blocks) const THREEFISH_INJECT_KEY(R2); \ } while(0) - for(size_t i = 0; i != blocks; ++i) + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks; ++i) { - u64bit X0 = load_le<u64bit>(in, 0); - u64bit X1 = load_le<u64bit>(in, 1); - u64bit X2 = load_le<u64bit>(in, 2); - u64bit X3 = load_le<u64bit>(in, 3); - u64bit X4 = load_le<u64bit>(in, 4); - u64bit X5 = load_le<u64bit>(in, 5); - u64bit X6 = load_le<u64bit>(in, 6); - u64bit X7 = load_le<u64bit>(in, 7); + u64bit X0, X1, X2, X3, X4, X5, X6, X7; + load_le(in + BLOCK_SIZE*i, X0, X1, X2, X3, X4, X5, X6, X7); THREEFISH_INJECT_KEY(18); @@ -234,10 +219,7 @@ void Threefish_512::decrypt_n(const byte in[], byte out[], size_t blocks) const THREEFISH_DEC_8_ROUNDS(3,2); THREEFISH_DEC_8_ROUNDS(1,0); - store_le(out, X0, X1, X2, X3, X4, X5, X6, X7); - - in += 64; - out += 64; + store_le(out + BLOCK_SIZE*i, X0, X1, X2, X3, X4, X5, X6, X7); } #undef THREEFISH_DEC_8_ROUNDS diff --git a/src/lib/block/twofish/twofish.cpp b/src/lib/block/twofish/twofish.cpp index 336d73a03..0b30d4080 100644 --- a/src/lib/block/twofish/twofish.cpp +++ b/src/lib/block/twofish/twofish.cpp @@ -19,12 +19,15 @@ namespace Botan { */ void Twofish::encrypt_n(const byte in[], byte out[], size_t blocks) const { - for(size_t i = 0; i != blocks; ++i) + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks; ++i) { - u32bit A = load_le<u32bit>(in, 0) ^ m_RK[0]; - u32bit B = load_le<u32bit>(in, 1) ^ m_RK[1]; - u32bit C = load_le<u32bit>(in, 2) ^ m_RK[2]; - u32bit D = load_le<u32bit>(in, 3) ^ m_RK[3]; + u32bit A, B, C, D; + load_le(in + BLOCK_SIZE*i, A, B, C, D); + + A ^= m_RK[0]; + B ^= m_RK[1]; + C ^= m_RK[2]; + D ^= m_RK[3]; for(size_t j = 0; j != 16; j += 2) { @@ -58,10 +61,7 @@ void Twofish::encrypt_n(const byte in[], byte out[], size_t blocks) const A ^= m_RK[6]; B ^= m_RK[7]; - store_le(out, C, D, A, B); - - in += BLOCK_SIZE; - out += BLOCK_SIZE; + store_le(out + BLOCK_SIZE*i, C, D, A, B); } } @@ -70,12 +70,15 @@ void Twofish::encrypt_n(const byte in[], byte out[], size_t blocks) const */ void Twofish::decrypt_n(const byte in[], byte out[], size_t blocks) const { - for(size_t i = 0; i != blocks; ++i) + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks; ++i) { - u32bit A = load_le<u32bit>(in, 0) ^ m_RK[4]; - u32bit B = load_le<u32bit>(in, 1) ^ m_RK[5]; - u32bit C = load_le<u32bit>(in, 2) ^ m_RK[6]; - u32bit D = load_le<u32bit>(in, 3) ^ m_RK[7]; + u32bit A, B, C, D; + load_le(in + BLOCK_SIZE*i, A, B, C, D); + + A ^= m_RK[4]; + B ^= m_RK[5]; + C ^= m_RK[6]; + D ^= m_RK[7]; for(size_t j = 0; j != 16; j += 2) { @@ -109,10 +112,7 @@ void Twofish::decrypt_n(const byte in[], byte out[], size_t blocks) const A ^= m_RK[2]; B ^= m_RK[3]; - store_le(out, C, D, A, B); - - in += BLOCK_SIZE; - out += BLOCK_SIZE; + store_le(out + BLOCK_SIZE*i, C, D, A, B); } } @@ -127,7 +127,25 @@ void Twofish::key_schedule(const byte key[], size_t length) secure_vector<byte> S(16); for(size_t i = 0; i != length; ++i) - rs_mul(&S[4*(i/8)], key[i], i); + { + /* + * Do one column of the RS matrix multiplcation + */ + if(key[i]) + { + byte X = POLY_TO_EXP[key[i] - 1]; + + byte RS1 = RS[(4*i ) % 32]; + byte RS2 = RS[(4*i+1) % 32]; + byte RS3 = RS[(4*i+2) % 32]; + byte RS4 = RS[(4*i+3) % 32]; + + S[4*(i/8) ] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS1 - 1]) % 255]; + S[4*(i/8)+1] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS2 - 1]) % 255]; + S[4*(i/8)+2] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS3 - 1]) % 255]; + S[4*(i/8)+3] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS4 - 1]) % 255]; + } + } if(length == 16) { @@ -139,7 +157,7 @@ void Twofish::key_schedule(const byte key[], size_t length) m_SB[768+i] = MDS3[Q1[Q1[i]^S[ 3]]^S[ 7]]; } - for(size_t i = 0; i != 40; i += 2) + BOTAN_PARALLEL_FOR(size_t i = 0; i < 40; i += 2) { u32bit X = MDS0[Q0[Q0[i ]^key[ 8]]^key[ 0]] ^ MDS1[Q0[Q1[i ]^key[ 9]]^key[ 1]] ^ @@ -166,7 +184,7 @@ void Twofish::key_schedule(const byte key[], size_t length) m_SB[768+i] = MDS3[Q1[Q1[Q0[i]^S[ 3]]^S[ 7]]^S[11]]; } - for(size_t i = 0; i != 40; i += 2) + BOTAN_PARALLEL_FOR(size_t i = 0; i < 40; i += 2) { u32bit X = MDS0[Q0[Q0[Q1[i ]^key[16]]^key[ 8]]^key[ 0]] ^ MDS1[Q0[Q1[Q1[i ]^key[17]]^key[ 9]]^key[ 1]] ^ @@ -193,7 +211,7 @@ void Twofish::key_schedule(const byte key[], size_t length) m_SB[768+i] = MDS3[Q1[Q1[Q0[Q1[i]^S[ 3]]^S[ 7]]^S[11]]^S[15]]; } - for(size_t i = 0; i != 40; i += 2) + BOTAN_PARALLEL_FOR(size_t i = 0; i < 40; i += 2) { u32bit X = MDS0[Q0[Q0[Q1[Q1[i ]^key[24]]^key[16]]^key[ 8]]^key[ 0]] ^ MDS1[Q0[Q1[Q1[Q0[i ]^key[25]]^key[17]]^key[ 9]]^key[ 1]] ^ @@ -213,27 +231,6 @@ void Twofish::key_schedule(const byte key[], size_t length) } /* -* Do one column of the RS matrix multiplcation -*/ -void Twofish::rs_mul(byte S[4], byte key, size_t offset) - { - if(key) - { - byte X = POLY_TO_EXP[key - 1]; - - byte RS1 = RS[(4*offset ) % 32]; - byte RS2 = RS[(4*offset+1) % 32]; - byte RS3 = RS[(4*offset+2) % 32]; - byte RS4 = RS[(4*offset+3) % 32]; - - S[0] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS1 - 1]) % 255]; - S[1] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS2 - 1]) % 255]; - S[2] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS3 - 1]) % 255]; - S[3] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS4 - 1]) % 255]; - } - } - -/* * Clear memory of sensitive data */ void Twofish::clear() diff --git a/src/lib/block/twofish/twofish.h b/src/lib/block/twofish/twofish.h index 42991e354..b8021263e 100644 --- a/src/lib/block/twofish/twofish.h +++ b/src/lib/block/twofish/twofish.h @@ -27,8 +27,6 @@ class BOTAN_DLL Twofish final : public Block_Cipher_Fixed_Params<16, 16, 32, 8> private: void key_schedule(const byte[], size_t) override; - static void rs_mul(byte[4], byte, size_t); - static const u32bit MDS0[256]; static const u32bit MDS1[256]; static const u32bit MDS2[256]; diff --git a/src/lib/block/twofish/two_tab.cpp b/src/lib/block/twofish/twofish_tab.cpp index 6eb6b62f0..6eb6b62f0 100644 --- a/src/lib/block/twofish/two_tab.cpp +++ b/src/lib/block/twofish/twofish_tab.cpp diff --git a/src/lib/block/xtea/xtea.cpp b/src/lib/block/xtea/xtea.cpp index 333406d9b..4e5ca7e7c 100644 --- a/src/lib/block/xtea/xtea.cpp +++ b/src/lib/block/xtea/xtea.cpp @@ -1,6 +1,6 @@ /* * XTEA -* (C) 1999-2009 Jack Lloyd +* (C) 1999-2009,2016 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -10,80 +10,49 @@ namespace Botan { -namespace { - -void xtea_encrypt_4(const byte in[32], byte out[32], const u32bit EK[64]) - { - u32bit L0, R0, L1, R1, L2, R2, L3, R3; - load_be(in, L0, R0, L1, R1, L2, R2, L3, R3); - - for(size_t i = 0; i != 32; ++i) - { - L0 += (((R0 << 4) ^ (R0 >> 5)) + R0) ^ EK[2*i]; - L1 += (((R1 << 4) ^ (R1 >> 5)) + R1) ^ EK[2*i]; - L2 += (((R2 << 4) ^ (R2 >> 5)) + R2) ^ EK[2*i]; - L3 += (((R3 << 4) ^ (R3 >> 5)) + R3) ^ EK[2*i]; - - R0 += (((L0 << 4) ^ (L0 >> 5)) + L0) ^ EK[2*i+1]; - R1 += (((L1 << 4) ^ (L1 >> 5)) + L1) ^ EK[2*i+1]; - R2 += (((L2 << 4) ^ (L2 >> 5)) + L2) ^ EK[2*i+1]; - R3 += (((L3 << 4) ^ (L3 >> 5)) + L3) ^ EK[2*i+1]; - } - - store_be(out, L0, R0, L1, R1, L2, R2, L3, R3); - } - -void xtea_decrypt_4(const byte in[32], byte out[32], const u32bit EK[64]) - { - u32bit L0, R0, L1, R1, L2, R2, L3, R3; - load_be(in, L0, R0, L1, R1, L2, R2, L3, R3); - - for(size_t i = 0; i != 32; ++i) - { - R0 -= (((L0 << 4) ^ (L0 >> 5)) + L0) ^ EK[63 - 2*i]; - R1 -= (((L1 << 4) ^ (L1 >> 5)) + L1) ^ EK[63 - 2*i]; - R2 -= (((L2 << 4) ^ (L2 >> 5)) + L2) ^ EK[63 - 2*i]; - R3 -= (((L3 << 4) ^ (L3 >> 5)) + L3) ^ EK[63 - 2*i]; - - L0 -= (((R0 << 4) ^ (R0 >> 5)) + R0) ^ EK[62 - 2*i]; - L1 -= (((R1 << 4) ^ (R1 >> 5)) + R1) ^ EK[62 - 2*i]; - L2 -= (((R2 << 4) ^ (R2 >> 5)) + R2) ^ EK[62 - 2*i]; - L3 -= (((R3 << 4) ^ (R3 >> 5)) + R3) ^ EK[62 - 2*i]; - } - - store_be(out, L0, R0, L1, R1, L2, R2, L3, R3); - } - -} - /* * XTEA Encryption */ void XTEA::encrypt_n(const byte in[], byte out[], size_t blocks) const { - while(blocks >= 4) - { - xtea_encrypt_4(in, out, &(this->m_EK[0])); - in += 4 * BLOCK_SIZE; - out += 4 * BLOCK_SIZE; - blocks -= 4; - } + const u32bit* EK = &m_EK[0]; - for(size_t i = 0; i != blocks; ++i) + const size_t blocks4 = blocks / 4; + const size_t blocks_left = blocks % 4; + + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks4; i++) { - u32bit L = load_be<u32bit>(in, 0); - u32bit R = load_be<u32bit>(in, 1); + u32bit L0, R0, L1, R1, L2, R2, L3, R3; + load_be(in + 4*BLOCK_SIZE*i, L0, R0, L1, R1, L2, R2, L3, R3); - for(size_t j = 0; j != 32; ++j) + for(size_t r = 0; r != 32; ++r) { - L += (((R << 4) ^ (R >> 5)) + R) ^ m_EK[2*j]; - R += (((L << 4) ^ (L >> 5)) + L) ^ m_EK[2*j+1]; + L0 += (((R0 << 4) ^ (R0 >> 5)) + R0) ^ EK[2*r]; + L1 += (((R1 << 4) ^ (R1 >> 5)) + R1) ^ EK[2*r]; + L2 += (((R2 << 4) ^ (R2 >> 5)) + R2) ^ EK[2*r]; + L3 += (((R3 << 4) ^ (R3 >> 5)) + R3) ^ EK[2*r]; + + R0 += (((L0 << 4) ^ (L0 >> 5)) + L0) ^ EK[2*r+1]; + R1 += (((L1 << 4) ^ (L1 >> 5)) + L1) ^ EK[2*r+1]; + R2 += (((L2 << 4) ^ (L2 >> 5)) + L2) ^ EK[2*r+1]; + R3 += (((L3 << 4) ^ (L3 >> 5)) + L3) ^ EK[2*r+1]; } - store_be(out, L, R); + store_be(out + 4*BLOCK_SIZE*i, L0, R0, L1, R1, L2, R2, L3, R3); + } + + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks_left; ++i) + { + u32bit L, R; + load_be(in + BLOCK_SIZE*(4*blocks4+i), L, R); + + for(size_t r = 0; r != 32; ++r) + { + L += (((R << 4) ^ (R >> 5)) + R) ^ EK[2*r]; + R += (((L << 4) ^ (L >> 5)) + L) ^ EK[2*r+1]; + } - in += BLOCK_SIZE; - out += BLOCK_SIZE; + store_be(out + BLOCK_SIZE*(4*blocks4+i), L, R); } } @@ -92,29 +61,44 @@ void XTEA::encrypt_n(const byte in[], byte out[], size_t blocks) const */ void XTEA::decrypt_n(const byte in[], byte out[], size_t blocks) const { - while(blocks >= 4) - { - xtea_decrypt_4(in, out, &(this->m_EK[0])); - in += 4 * BLOCK_SIZE; - out += 4 * BLOCK_SIZE; - blocks -= 4; - } + const u32bit* EK = &m_EK[0]; - for(size_t i = 0; i != blocks; ++i) + const size_t blocks4 = blocks / 4; + const size_t blocks_left = blocks % 4; + + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks4; i++) { - u32bit L = load_be<u32bit>(in, 0); - u32bit R = load_be<u32bit>(in, 1); + u32bit L0, R0, L1, R1, L2, R2, L3, R3; + load_be(in + 4*BLOCK_SIZE*i, L0, R0, L1, R1, L2, R2, L3, R3); - for(size_t j = 0; j != 32; ++j) + for(size_t r = 0; r != 32; ++r) { - R -= (((L << 4) ^ (L >> 5)) + L) ^ m_EK[63 - 2*j]; - L -= (((R << 4) ^ (R >> 5)) + R) ^ m_EK[62 - 2*j]; + R0 -= (((L0 << 4) ^ (L0 >> 5)) + L0) ^ EK[63 - 2*r]; + R1 -= (((L1 << 4) ^ (L1 >> 5)) + L1) ^ EK[63 - 2*r]; + R2 -= (((L2 << 4) ^ (L2 >> 5)) + L2) ^ EK[63 - 2*r]; + R3 -= (((L3 << 4) ^ (L3 >> 5)) + L3) ^ EK[63 - 2*r]; + + L0 -= (((R0 << 4) ^ (R0 >> 5)) + R0) ^ EK[62 - 2*r]; + L1 -= (((R1 << 4) ^ (R1 >> 5)) + R1) ^ EK[62 - 2*r]; + L2 -= (((R2 << 4) ^ (R2 >> 5)) + R2) ^ EK[62 - 2*r]; + L3 -= (((R3 << 4) ^ (R3 >> 5)) + R3) ^ EK[62 - 2*r]; } - store_be(out, L, R); + store_be(out + 4*BLOCK_SIZE*i, L0, R0, L1, R1, L2, R2, L3, R3); + } + + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks_left; ++i) + { + u32bit L, R; + load_be(in + BLOCK_SIZE*(4*blocks4+i), L, R); + + for(size_t r = 0; r != 32; ++r) + { + R -= (((L << 4) ^ (L >> 5)) + L) ^ m_EK[63 - 2*r]; + L -= (((R << 4) ^ (R >> 5)) + R) ^ m_EK[62 - 2*r]; + } - in += BLOCK_SIZE; - out += BLOCK_SIZE; + store_be(out + BLOCK_SIZE*(4*blocks4+i), L, R); } } diff --git a/src/lib/entropy/cryptoapi_rng/es_capi.cpp b/src/lib/entropy/cryptoapi_rng/es_capi.cpp index a1d809d0d..1624f8946 100644 --- a/src/lib/entropy/cryptoapi_rng/es_capi.cpp +++ b/src/lib/entropy/cryptoapi_rng/es_capi.cpp @@ -7,10 +7,9 @@ #include <botan/internal/es_capi.h> #include <botan/parsing.h> +#define NOMINMAX 1 #include <windows.h> #include <wincrypt.h> -#undef min -#undef max namespace Botan { diff --git a/src/lib/entropy/cryptoapi_rng/info.txt b/src/lib/entropy/cryptoapi_rng/info.txt index 8aa166692..846a11371 100644 --- a/src/lib/entropy/cryptoapi_rng/info.txt +++ b/src/lib/entropy/cryptoapi_rng/info.txt @@ -1,9 +1,5 @@ define ENTROPY_SRC_CAPI 20131128 -<source> -es_capi.cpp -</source> - <header:internal> es_capi.h </header:internal> diff --git a/src/lib/entropy/darwin_secrandom/info.txt b/src/lib/entropy/darwin_secrandom/info.txt index e12c341fd..2460d8f86 100644 --- a/src/lib/entropy/darwin_secrandom/info.txt +++ b/src/lib/entropy/darwin_secrandom/info.txt @@ -1,9 +1,5 @@ define ENTROPY_SRC_DARWIN_SECRANDOM 20150925 -<source> -darwin_secrandom.cpp -</source> - <header:internal> darwin_secrandom.h </header:internal> @@ -14,4 +10,4 @@ darwin <frameworks> darwin -> Security -</frameworks>
\ No newline at end of file +</frameworks> diff --git a/src/lib/entropy/dev_random/info.txt b/src/lib/entropy/dev_random/info.txt index d8b7df134..56162f84e 100644 --- a/src/lib/entropy/dev_random/info.txt +++ b/src/lib/entropy/dev_random/info.txt @@ -1,9 +1,5 @@ define ENTROPY_SRC_DEV_RANDOM 20131128 -<source> -dev_random.cpp -</source> - <header:internal> dev_random.h </header:internal> diff --git a/src/lib/entropy/proc_walk/info.txt b/src/lib/entropy/proc_walk/info.txt index 8c3947dc6..46912eb5a 100644 --- a/src/lib/entropy/proc_walk/info.txt +++ b/src/lib/entropy/proc_walk/info.txt @@ -1,9 +1,5 @@ define ENTROPY_SRC_PROC_WALKER 20131128 -<source> -proc_walk.cpp -</source> - <header:internal> proc_walk.h </header:internal> diff --git a/src/lib/entropy/rdrand/info.txt b/src/lib/entropy/rdrand/info.txt index ebc7fb747..01ef2bc05 100644 --- a/src/lib/entropy/rdrand/info.txt +++ b/src/lib/entropy/rdrand/info.txt @@ -4,10 +4,6 @@ define ENTROPY_SRC_RDRAND 20131128 rdrand_rng </requires> -<source> -rdrand.cpp -</source> - <header:internal> rdrand.h </header:internal> diff --git a/src/lib/entropy/rdseed/info.txt b/src/lib/entropy/rdseed/info.txt index 53aa496b0..10e797322 100644 --- a/src/lib/entropy/rdseed/info.txt +++ b/src/lib/entropy/rdseed/info.txt @@ -2,10 +2,6 @@ define ENTROPY_SRC_RDSEED 20151218 need_isa rdseed -<source> -rdseed.cpp -</source> - <header:internal> rdseed.h </header:internal> diff --git a/src/lib/entropy/win32_stats/es_win32.cpp b/src/lib/entropy/win32_stats/es_win32.cpp index bbc64eaab..520848615 100644 --- a/src/lib/entropy/win32_stats/es_win32.cpp +++ b/src/lib/entropy/win32_stats/es_win32.cpp @@ -6,6 +6,7 @@ */ #include <botan/internal/es_win32.h> +#define NOMINMAX 1 #include <windows.h> #include <tlhelp32.h> diff --git a/src/lib/entropy/win32_stats/info.txt b/src/lib/entropy/win32_stats/info.txt index 48eb91faa..1787c9138 100644 --- a/src/lib/entropy/win32_stats/info.txt +++ b/src/lib/entropy/win32_stats/info.txt @@ -1,9 +1,5 @@ define ENTROPY_SRC_WIN32 20131128 -<source> -es_win32.cpp -</source> - <header:internal> es_win32.h </header:internal> diff --git a/src/lib/ffi/ffi.cpp b/src/lib/ffi/ffi.cpp index 3a943378d..4727c0763 100644 --- a/src/lib/ffi/ffi.cpp +++ b/src/lib/ffi/ffi.cpp @@ -998,7 +998,7 @@ int botan_pubkey_fingerprint(botan_pubkey_t key, const char* hash_fn, { return BOTAN_FFI_DO(Botan::Public_Key, key, k, { std::unique_ptr<Botan::HashFunction> h(Botan::HashFunction::create(hash_fn)); - return write_vec_output(out, out_len, h->process(k.x509_subject_public_key())); + return write_vec_output(out, out_len, h->process(k.public_key_bits())); }); } diff --git a/src/lib/filters/basefilt.h b/src/lib/filters/basefilt.h index d803542a1..629f04f29 100644 --- a/src/lib/filters/basefilt.h +++ b/src/lib/filters/basefilt.h @@ -12,7 +12,7 @@ #include <botan/filter.h> #if defined(BOTAN_TARGET_OS_HAS_THREADS) -#include <thread> + #include <thread> #endif namespace Botan { diff --git a/src/lib/filters/info.txt b/src/lib/filters/info.txt index 620c1e6cc..0e51d0f8a 100644 --- a/src/lib/filters/info.txt +++ b/src/lib/filters/info.txt @@ -1,22 +1,5 @@ define FILTERS 20160415 -<source> -algo_filt.cpp -basefilt.cpp -buf_filt.cpp -comp_filter.cpp -data_snk.cpp -filter.cpp -key_filt.cpp -out_buf.cpp -pipe.cpp -pipe_io.cpp -pipe_rw.cpp -secqueue.cpp -threaded_fork.cpp -cipher_filter.cpp -</source> - <header:public> basefilt.h buf_filt.h diff --git a/src/lib/kdf/hkdf/hkdf.h b/src/lib/kdf/hkdf/hkdf.h index 5ab253420..5ad389aeb 100644 --- a/src/lib/kdf/hkdf/hkdf.h +++ b/src/lib/kdf/hkdf/hkdf.h @@ -36,7 +36,7 @@ class BOTAN_DLL HKDF final : public KDF const byte label[], size_t label_len) const override; private: - MessageAuthenticationCode* m_prf; + std::unique_ptr<MessageAuthenticationCode> m_prf; }; /** diff --git a/src/lib/kdf/kdf.cpp b/src/lib/kdf/kdf.cpp index e48a3463c..2fba1868e 100644 --- a/src/lib/kdf/kdf.cpp +++ b/src/lib/kdf/kdf.cpp @@ -6,6 +6,7 @@ */ #include <botan/kdf.h> +#include <botan/mac.h> #include <botan/scan_name.h> #include <botan/exceptn.h> diff --git a/src/lib/math/bigint/info.txt b/src/lib/math/bigint/info.txt index 53edcb1f1..c91c85e9f 100644 --- a/src/lib/math/bigint/info.txt +++ b/src/lib/math/bigint/info.txt @@ -7,16 +7,6 @@ bigint.h divide.h </header:public> -<source> -big_code.cpp -big_io.cpp -big_ops2.cpp -big_ops3.cpp -big_rand.cpp -bigint.cpp -divide.cpp -</source> - <requires> mp hex diff --git a/src/lib/math/mp/info.txt b/src/lib/math/mp/info.txt index b5db12648..0b8b9c33b 100644 --- a/src/lib/math/mp/info.txt +++ b/src/lib/math/mp/info.txt @@ -1,12 +1,5 @@ define BIGINT_MP 20151225 -<source> -mp_core.cpp -mp_comba.cpp -mp_karat.cpp -mp_monty.cpp -</source> - <header:public> mp_types.h </header:public> diff --git a/src/lib/modes/aead/ccm/ccm.h b/src/lib/modes/aead/ccm/ccm.h index 2a17595e7..9795354fc 100644 --- a/src/lib/modes/aead/ccm/ccm.h +++ b/src/lib/modes/aead/ccm/ccm.h @@ -116,7 +116,7 @@ class BOTAN_DLL CCM_Decryption final : public CCM_Mode size_t output_length(size_t input_length) const override { - BOTAN_ASSERT(input_length > tag_size(), "Sufficient input"); + BOTAN_ASSERT(input_length >= tag_size(), "Sufficient input"); return input_length - tag_size(); } diff --git a/src/lib/modes/aead/chacha20poly1305/chacha20poly1305.h b/src/lib/modes/aead/chacha20poly1305/chacha20poly1305.h index f58bd48ac..58328ac5b 100644 --- a/src/lib/modes/aead/chacha20poly1305/chacha20poly1305.h +++ b/src/lib/modes/aead/chacha20poly1305/chacha20poly1305.h @@ -83,7 +83,7 @@ class BOTAN_DLL ChaCha20Poly1305_Decryption final : public ChaCha20Poly1305_Mode public: size_t output_length(size_t input_length) const override { - BOTAN_ASSERT(input_length > tag_size(), "Sufficient input"); + BOTAN_ASSERT(input_length >= tag_size(), "Sufficient input"); return input_length - tag_size(); } diff --git a/src/lib/modes/aead/gcm/gcm.h b/src/lib/modes/aead/gcm/gcm.h index 463e69a3b..65b6b0474 100644 --- a/src/lib/modes/aead/gcm/gcm.h +++ b/src/lib/modes/aead/gcm/gcm.h @@ -95,7 +95,7 @@ class BOTAN_DLL GCM_Decryption final : public GCM_Mode size_t output_length(size_t input_length) const override { - BOTAN_ASSERT(input_length > tag_size(), "Sufficient input"); + BOTAN_ASSERT(input_length >= tag_size(), "Sufficient input"); return input_length - tag_size(); } diff --git a/src/lib/modes/aead/ocb/ocb.h b/src/lib/modes/aead/ocb/ocb.h index ce9d29f1b..dfdb8c18c 100644 --- a/src/lib/modes/aead/ocb/ocb.h +++ b/src/lib/modes/aead/ocb/ocb.h @@ -107,7 +107,7 @@ class BOTAN_DLL OCB_Decryption final : public OCB_Mode size_t output_length(size_t input_length) const override { - BOTAN_ASSERT(input_length > tag_size(), "Sufficient input"); + BOTAN_ASSERT(input_length >= tag_size(), "Sufficient input"); return input_length - tag_size(); } diff --git a/src/lib/modes/aead/siv/siv.h b/src/lib/modes/aead/siv/siv.h index 71990ef96..711d9e30c 100644 --- a/src/lib/modes/aead/siv/siv.h +++ b/src/lib/modes/aead/siv/siv.h @@ -107,7 +107,7 @@ class BOTAN_DLL SIV_Decryption final : public SIV_Mode size_t output_length(size_t input_length) const override { - BOTAN_ASSERT(input_length > tag_size(), "Sufficient input"); + BOTAN_ASSERT(input_length >= tag_size(), "Sufficient input"); return input_length - tag_size(); } diff --git a/src/lib/modes/cipher_mode.cpp b/src/lib/modes/cipher_mode.cpp index d622e7754..843e49581 100644 --- a/src/lib/modes/cipher_mode.cpp +++ b/src/lib/modes/cipher_mode.cpp @@ -18,10 +18,6 @@ #include <botan/aead.h> #endif -#if defined(BOTAN_HAS_MODE_ECB) - #include <botan/ecb.h> -#endif - #if defined(BOTAN_HAS_MODE_CBC) #include <botan/cbc.h> #endif @@ -140,20 +136,6 @@ Cipher_Mode* get_cipher_mode(const std::string& algo, Cipher_Dir direction) } #endif -#if defined(BOTAN_HAS_MODE_ECB) - if(spec.algo_name() == "ECB") - { - std::unique_ptr<BlockCipherModePaddingMethod> pad(get_bc_pad(spec.arg(1, "NoPadding"))); - if(pad) - { - if(direction == ENCRYPTION) - return new ECB_Encryption(bc.release(), pad.release()); - else - return new ECB_Decryption(bc.release(), pad.release()); - } - } -#endif - #endif return nullptr; diff --git a/src/lib/modes/ecb/ecb.cpp b/src/lib/modes/ecb/ecb.cpp deleted file mode 100644 index 78dff5ffa..000000000 --- a/src/lib/modes/ecb/ecb.cpp +++ /dev/null @@ -1,145 +0,0 @@ -/* -* ECB Mode -* (C) 1999-2009,2013 Jack Lloyd -* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#include <botan/ecb.h> -#include <botan/internal/rounding.h> - -namespace Botan { - -ECB_Mode::ECB_Mode(BlockCipher* cipher, BlockCipherModePaddingMethod* padding) : - m_cipher(cipher), - m_padding(padding) - { - if(!m_padding->valid_blocksize(cipher->block_size())) - throw Invalid_Argument("Padding " + m_padding->name() + - " cannot be used with " + - cipher->name() + "/ECB"); - } - -void ECB_Mode::clear() - { - m_cipher->clear(); - } - -void ECB_Mode::reset() - { - // no msg state here - return; - } - -std::string ECB_Mode::name() const - { - return cipher().name() + "/ECB/" + padding().name(); - } - -size_t ECB_Mode::update_granularity() const - { - return cipher().parallel_bytes(); - } - -Key_Length_Specification ECB_Mode::key_spec() const - { - return cipher().key_spec(); - } - -size_t ECB_Mode::default_nonce_length() const - { - return 0; - } - -bool ECB_Mode::valid_nonce_length(size_t n) const - { - return (n == 0); - } - -void ECB_Mode::key_schedule(const byte key[], size_t length) - { - m_cipher->set_key(key, length); - } - -void ECB_Mode::start_msg(const byte[], size_t nonce_len) - { - if(nonce_len != 0) - throw Invalid_IV_Length(name(), nonce_len); - } - -size_t ECB_Encryption::minimum_final_size() const - { - return 0; - } - -size_t ECB_Encryption::output_length(size_t input_length) const - { - if(input_length == 0) - return cipher().block_size(); - else - return round_up(input_length, cipher().block_size()); - } - -size_t ECB_Encryption::process(uint8_t buf[], size_t sz) - { - const size_t BS = cipher().block_size(); - BOTAN_ASSERT(sz % BS == 0, "ECB input is full blocks"); - const size_t blocks = sz / BS; - cipher().encrypt_n(buf, buf, blocks); - return sz; - } - -void ECB_Encryption::finish(secure_vector<byte>& buffer, size_t offset) - { - BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); - const size_t sz = buffer.size() - offset; - - const size_t BS = cipher().block_size(); - - const size_t bytes_in_final_block = sz % BS; - - padding().add_padding(buffer, bytes_in_final_block, BS); - - if(buffer.size() % BS) - throw Exception("Did not pad to full block size in " + name()); - - update(buffer, offset); - } - -size_t ECB_Decryption::output_length(size_t input_length) const - { - return input_length; - } - -size_t ECB_Decryption::minimum_final_size() const - { - return cipher().block_size(); - } - -size_t ECB_Decryption::process(uint8_t buf[], size_t sz) - { - const size_t BS = cipher().block_size(); - BOTAN_ASSERT(sz % BS == 0, "Input is full blocks"); - size_t blocks = sz / BS; - cipher().decrypt_n(buf, buf, blocks); - return sz; - } - -void ECB_Decryption::finish(secure_vector<byte>& buffer, size_t offset) - { - BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); - const size_t sz = buffer.size() - offset; - - const size_t BS = cipher().block_size(); - - if(sz == 0 || sz % BS) - throw Decoding_Error(name() + ": Ciphertext not a multiple of block size"); - - update(buffer, offset); - - const size_t pad_bytes = BS - padding().unpad(&buffer[buffer.size()-BS], BS); - buffer.resize(buffer.size() - pad_bytes); // remove padding - } - -} diff --git a/src/lib/modes/ecb/ecb.h b/src/lib/modes/ecb/ecb.h deleted file mode 100644 index 9fc17a80d..000000000 --- a/src/lib/modes/ecb/ecb.h +++ /dev/null @@ -1,99 +0,0 @@ -/* -* ECB Mode -* (C) 1999-2009,2013 Jack Lloyd -* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#ifndef BOTAN_MODE_ECB_H__ -#define BOTAN_MODE_ECB_H__ - -#include <botan/cipher_mode.h> -#include <botan/block_cipher.h> -#include <botan/mode_pad.h> - -namespace Botan { - -/** -* ECB mode -*/ -class BOTAN_DLL ECB_Mode : public Cipher_Mode - { - public: - std::string name() const override; - - size_t update_granularity() const override; - - Key_Length_Specification key_spec() const override; - - size_t default_nonce_length() const override; - - bool valid_nonce_length(size_t n) const override; - - void clear() override; - - void reset() override; - - protected: - ECB_Mode(BlockCipher* cipher, BlockCipherModePaddingMethod* padding); - - const BlockCipher& cipher() const { return *m_cipher; } - - const BlockCipherModePaddingMethod& padding() const { return *m_padding; } - - private: - void start_msg(const byte nonce[], size_t nonce_len) override; - void key_schedule(const byte key[], size_t length) override; - - std::unique_ptr<BlockCipher> m_cipher; - std::unique_ptr<BlockCipherModePaddingMethod> m_padding; - }; - -/** -* ECB Encryption -*/ -class BOTAN_DLL ECB_Encryption final : public ECB_Mode - { - public: - /** - * @param cipher block cipher to use - * @param padding padding method to use - */ - ECB_Encryption(BlockCipher* cipher, BlockCipherModePaddingMethod* padding) : - ECB_Mode(cipher, padding) {} - - size_t process(uint8_t buf[], size_t size) override; - - void finish(secure_vector<byte>& final_block, size_t offset = 0) override; - - size_t output_length(size_t input_length) const override; - - size_t minimum_final_size() const override; - }; - -/** -* ECB Decryption -*/ -class BOTAN_DLL ECB_Decryption final : public ECB_Mode - { - public: - /** - * @param cipher block cipher to use - * @param padding padding method to use - */ - ECB_Decryption(BlockCipher* cipher, BlockCipherModePaddingMethod* padding) : - ECB_Mode(cipher, padding) {} - - size_t process(uint8_t buf[], size_t size) override; - - void finish(secure_vector<byte>& final_block, size_t offset = 0) override; - - size_t output_length(size_t input_length) const override; - - size_t minimum_final_size() const override; - }; - -} - -#endif diff --git a/src/lib/modes/ecb/info.txt b/src/lib/modes/ecb/info.txt deleted file mode 100644 index 5e7737717..000000000 --- a/src/lib/modes/ecb/info.txt +++ /dev/null @@ -1,5 +0,0 @@ -define MODE_ECB 20131128 - -<requires> -mode_pad -</requires> diff --git a/src/lib/modes/mode_pad/mode_pad.h b/src/lib/modes/mode_pad/mode_pad.h index 7c67ceaad..4f07bc6ae 100644 --- a/src/lib/modes/mode_pad/mode_pad.h +++ b/src/lib/modes/mode_pad/mode_pad.h @@ -1,5 +1,5 @@ /* -* ECB/CBC Padding Methods +* CBC Padding Methods * (C) 1999-2008,2013 Jack Lloyd * (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity * diff --git a/src/lib/pk_pad/eme_pkcs1/eme_pkcs.cpp b/src/lib/pk_pad/eme_pkcs1/eme_pkcs.cpp index 9bab8eb95..2b5ee4ba0 100644 --- a/src/lib/pk_pad/eme_pkcs1/eme_pkcs.cpp +++ b/src/lib/pk_pad/eme_pkcs1/eme_pkcs.cpp @@ -48,6 +48,12 @@ secure_vector<byte> EME_PKCS1v15::pad(const byte in[], size_t inlen, secure_vector<byte> EME_PKCS1v15::unpad(byte& valid_mask, const byte in[], size_t inlen) const { + if(inlen < 2) + { + valid_mask = false; + return secure_vector<byte>(); + } + CT::poison(in, inlen); byte bad_input_m = 0; @@ -63,7 +69,7 @@ secure_vector<byte> EME_PKCS1v15::unpad(byte& valid_mask, delim_idx += CT::select<byte>(~seen_zero_m, 1, 0); - bad_input_m |= is_zero_m & CT::expand_mask<byte>(i < 9); + bad_input_m |= is_zero_m & CT::expand_mask<byte>(i < 10); seen_zero_m |= is_zero_m; } diff --git a/src/lib/prov/openssl/openssl_rc4.cpp b/src/lib/prov/openssl/openssl_rc4.cpp index b43d801ed..c8ba32235 100644 --- a/src/lib/prov/openssl/openssl_rc4.cpp +++ b/src/lib/prov/openssl/openssl_rc4.cpp @@ -38,7 +38,7 @@ class OpenSSL_RC4 : public StreamCipher } } - StreamCipher* clone() const override { return new OpenSSL_RC4; } + StreamCipher* clone() const override { return new OpenSSL_RC4(m_skip); } Key_Length_Specification key_spec() const override { diff --git a/src/lib/prov/openssl/openssl_rsa.cpp b/src/lib/prov/openssl/openssl_rsa.cpp index 77f74fab6..aef9c95d8 100644 --- a/src/lib/prov/openssl/openssl_rsa.cpp +++ b/src/lib/prov/openssl/openssl_rsa.cpp @@ -44,7 +44,7 @@ class OpenSSL_RSA_Encryption_Operation : public PK_Ops::Encryption OpenSSL_RSA_Encryption_Operation(const RSA_PublicKey& rsa, int pad, size_t pad_overhead) : m_openssl_rsa(nullptr, ::RSA_free), m_padding(pad) { - const std::vector<byte> der = rsa.x509_subject_public_key(); + const std::vector<byte> der = rsa.public_key_bits(); const byte* der_ptr = der.data(); m_openssl_rsa.reset(::d2i_RSAPublicKey(nullptr, &der_ptr, der.size())); if(!m_openssl_rsa) @@ -99,7 +99,7 @@ class OpenSSL_RSA_Decryption_Operation : public PK_Ops::Decryption OpenSSL_RSA_Decryption_Operation(const RSA_PrivateKey& rsa, int pad) : m_openssl_rsa(nullptr, ::RSA_free), m_padding(pad) { - const secure_vector<byte> der = rsa.pkcs8_private_key(); + const secure_vector<byte> der = rsa.private_key_bits(); const byte* der_ptr = der.data(); m_openssl_rsa.reset(d2i_RSAPrivateKey(nullptr, &der_ptr, der.size())); if(!m_openssl_rsa) @@ -143,7 +143,7 @@ class OpenSSL_RSA_Verification_Operation : public PK_Ops::Verification_with_EMSA PK_Ops::Verification_with_EMSA(emsa), m_openssl_rsa(nullptr, ::RSA_free) { - const std::vector<byte> der = rsa.x509_subject_public_key(); + const std::vector<byte> der = rsa.public_key_bits(); const byte* der_ptr = der.data(); m_openssl_rsa.reset(::d2i_RSAPublicKey(nullptr, &der_ptr, der.size())); } @@ -183,7 +183,7 @@ class OpenSSL_RSA_Signing_Operation : public PK_Ops::Signature_with_EMSA PK_Ops::Signature_with_EMSA(emsa), m_openssl_rsa(nullptr, ::RSA_free) { - const secure_vector<byte> der = rsa.pkcs8_private_key(); + const secure_vector<byte> der = rsa.private_key_bits(); const byte* der_ptr = der.data(); m_openssl_rsa.reset(d2i_RSAPrivateKey(nullptr, &der_ptr, der.size())); if(!m_openssl_rsa) diff --git a/src/lib/prov/pkcs11/info.txt b/src/lib/prov/pkcs11/info.txt index e5a471b25..a8146133c 100644 --- a/src/lib/prov/pkcs11/info.txt +++ b/src/lib/prov/pkcs11/info.txt @@ -31,18 +31,3 @@ p11_session.h p11_slot.h p11_x509.h </header:public> - -<source> -p11.cpp -p11_ecc_key.cpp -p11_ecdh.cpp -p11_ecdsa.cpp -p11_mechanism.cpp -p11_module.cpp -p11_object.cpp -p11_randomgenerator.cpp -p11_rsa.cpp -p11_session.cpp -p11_slot.cpp -p11_x509.cpp -</source> diff --git a/src/lib/prov/pkcs11/p11_ecc_key.cpp b/src/lib/prov/pkcs11/p11_ecc_key.cpp index 52f98b079..527daceaf 100644 --- a/src/lib/prov/pkcs11/p11_ecc_key.cpp +++ b/src/lib/prov/pkcs11/p11_ecc_key.cpp @@ -106,7 +106,7 @@ size_t PKCS11_EC_PrivateKey::key_length() const return m_domain_params.get_order().bits(); } -std::vector<byte> PKCS11_EC_PrivateKey::x509_subject_public_key() const +std::vector<byte> PKCS11_EC_PrivateKey::public_key_bits() const { return unlock(EC2OSP(public_point(), PointGFp::COMPRESSED)); } diff --git a/src/lib/prov/pkcs11/p11_ecc_key.h b/src/lib/prov/pkcs11/p11_ecc_key.h index 0a222cb79..69e612c33 100644 --- a/src/lib/prov/pkcs11/p11_ecc_key.h +++ b/src/lib/prov/pkcs11/p11_ecc_key.h @@ -201,7 +201,7 @@ class BOTAN_DLL PKCS11_EC_PrivateKey : public virtual Private_Key, // Private_Key methods - std::vector<byte> x509_subject_public_key() const override; + std::vector<byte> public_key_bits() const override; std::size_t key_length() const override; diff --git a/src/lib/prov/pkcs11/p11_ecdh.cpp b/src/lib/prov/pkcs11/p11_ecdh.cpp index 474d1dac0..50aa964d5 100644 --- a/src/lib/prov/pkcs11/p11_ecdh.cpp +++ b/src/lib/prov/pkcs11/p11_ecdh.cpp @@ -13,7 +13,7 @@ #include <botan/internal/p11_mechanism.h> #include <botan/ber_dec.h> #include <botan/der_enc.h> -#include <botan/internal/pk_ops.h> +#include <botan/pk_ops.h> #include <botan/rng.h> namespace Botan { @@ -33,9 +33,9 @@ ECDH_PrivateKey PKCS11_ECDH_PrivateKey::export_key() const return ECDH_PrivateKey(rng, domain(), BigInt::decode(priv_key)); } -secure_vector<byte> PKCS11_ECDH_PrivateKey::pkcs8_private_key() const +secure_vector<byte> PKCS11_ECDH_PrivateKey::private_key_bits() const { - return export_key().pkcs8_private_key(); + return export_key().private_key_bits(); } namespace { diff --git a/src/lib/prov/pkcs11/p11_ecdh.h b/src/lib/prov/pkcs11/p11_ecdh.h index ef9ccb250..7fc21ad46 100644 --- a/src/lib/prov/pkcs11/p11_ecdh.h +++ b/src/lib/prov/pkcs11/p11_ecdh.h @@ -101,7 +101,7 @@ class BOTAN_DLL PKCS11_ECDH_PrivateKey final : public virtual PKCS11_EC_PrivateK /// @return the exported ECDH private key ECDH_PrivateKey export_key() const; - secure_vector<byte> pkcs8_private_key() const override; + secure_vector<byte> private_key_bits() const override; std::unique_ptr<PK_Ops::Key_Agreement> create_key_agreement_op(RandomNumberGenerator& rng, diff --git a/src/lib/prov/pkcs11/p11_ecdsa.cpp b/src/lib/prov/pkcs11/p11_ecdsa.cpp index c2ba02e0f..cbdd4d007 100644 --- a/src/lib/prov/pkcs11/p11_ecdsa.cpp +++ b/src/lib/prov/pkcs11/p11_ecdsa.cpp @@ -11,7 +11,7 @@ #if defined(BOTAN_HAS_ECDSA) #include <botan/internal/p11_mechanism.h> -#include <botan/internal/pk_ops.h> +#include <botan/pk_ops.h> #include <botan/keypair.h> #include <botan/rng.h> @@ -47,9 +47,9 @@ ECDSA_PrivateKey PKCS11_ECDSA_PrivateKey::export_key() const return ECDSA_PrivateKey(rng, domain(), BigInt::decode(priv_key)); } -secure_vector<byte> PKCS11_ECDSA_PrivateKey::pkcs8_private_key() const +secure_vector<byte> PKCS11_ECDSA_PrivateKey::private_key_bits() const { - return export_key().pkcs8_private_key(); + return export_key().private_key_bits(); } namespace { diff --git a/src/lib/prov/pkcs11/p11_ecdsa.h b/src/lib/prov/pkcs11/p11_ecdsa.h index a4c3df3ea..73ee900db 100644 --- a/src/lib/prov/pkcs11/p11_ecdsa.h +++ b/src/lib/prov/pkcs11/p11_ecdsa.h @@ -98,7 +98,7 @@ class BOTAN_DLL PKCS11_ECDSA_PrivateKey final : public PKCS11_EC_PrivateKey /// @return the exported ECDSA private key ECDSA_PrivateKey export_key() const; - secure_vector<byte> pkcs8_private_key() const override; + secure_vector<byte> private_key_bits() const override; bool check_key(RandomNumberGenerator&, bool) const override; diff --git a/src/lib/prov/pkcs11/p11_rsa.cpp b/src/lib/prov/pkcs11/p11_rsa.cpp index 0312f76bf..1edbde83b 100644 --- a/src/lib/prov/pkcs11/p11_rsa.cpp +++ b/src/lib/prov/pkcs11/p11_rsa.cpp @@ -11,8 +11,7 @@ #if defined(BOTAN_HAS_RSA) #include <botan/internal/p11_mechanism.h> -#include <botan/internal/pk_ops.h> -#include <botan/internal/pk_ops.h> +#include <botan/pk_ops.h> #include <botan/rng.h> #include <botan/blinding.h> @@ -102,9 +101,9 @@ RSA_PrivateKey PKCS11_RSA_PrivateKey::export_key() const , BigInt::decode(n)); } -secure_vector<byte> PKCS11_RSA_PrivateKey::pkcs8_private_key() const +secure_vector<byte> PKCS11_RSA_PrivateKey::private_key_bits() const { - return export_key().pkcs8_private_key(); + return export_key().private_key_bits(); } diff --git a/src/lib/prov/pkcs11/p11_rsa.h b/src/lib/prov/pkcs11/p11_rsa.h index 6d80e45a7..13b9d9dc1 100644 --- a/src/lib/prov/pkcs11/p11_rsa.h +++ b/src/lib/prov/pkcs11/p11_rsa.h @@ -200,7 +200,7 @@ class BOTAN_DLL PKCS11_RSA_PrivateKey final : public Private_Key, /// @return the exported RSA private key RSA_PrivateKey export_key() const; - secure_vector<byte> pkcs8_private_key() const override; + secure_vector<byte> private_key_bits() const override; std::unique_ptr<PK_Ops::Decryption> create_decryption_op(RandomNumberGenerator& rng, diff --git a/src/lib/prov/tpm/tpm.cpp b/src/lib/prov/tpm/tpm.cpp index cb5a242eb..e1f214952 100644 --- a/src/lib/prov/tpm/tpm.cpp +++ b/src/lib/prov/tpm/tpm.cpp @@ -11,7 +11,7 @@ #include <botan/hash_id.h> #include <botan/der_enc.h> #include <botan/workfactor.h> -#include <botan/internal/pk_ops.h> +#include <botan/pk_ops.h> #include <sstream> #include <tss/platform.h> @@ -349,7 +349,7 @@ AlgorithmIdentifier TPM_PrivateKey::algorithm_identifier() const AlgorithmIdentifier::USE_NULL_PARAM); } -std::vector<byte> TPM_PrivateKey::x509_subject_public_key() const +std::vector<byte> TPM_PrivateKey::public_key_bits() const { return DER_Encoder() .start_cons(SEQUENCE) @@ -359,9 +359,9 @@ std::vector<byte> TPM_PrivateKey::x509_subject_public_key() const .get_contents_unlocked(); } -secure_vector<byte> TPM_PrivateKey::pkcs8_private_key() const +secure_vector<byte> TPM_PrivateKey::private_key_bits() const { - throw TPM_Error("PKCS #8 export not supported for TPM keys"); + throw TPM_Error("Private key export not supported for TPM keys"); } std::vector<uint8_t> TPM_PrivateKey::export_blob() const diff --git a/src/lib/prov/tpm/tpm.h b/src/lib/prov/tpm/tpm.h index 804d42e70..de0fa364f 100644 --- a/src/lib/prov/tpm/tpm.h +++ b/src/lib/prov/tpm/tpm.h @@ -154,9 +154,9 @@ class BOTAN_DLL TPM_PrivateKey : public Private_Key AlgorithmIdentifier algorithm_identifier() const override; - std::vector<byte> x509_subject_public_key() const override; + std::vector<byte> public_key_bits() const override; - secure_vector<byte> pkcs8_private_key() const override; + secure_vector<byte> private_key_bits() const override; bool check_key(RandomNumberGenerator& rng, bool) const override; diff --git a/src/lib/pubkey/curve25519/curve25519.cpp b/src/lib/pubkey/curve25519/curve25519.cpp index dd97e1f1d..bad961b40 100644 --- a/src/lib/pubkey/curve25519/curve25519.cpp +++ b/src/lib/pubkey/curve25519/curve25519.cpp @@ -58,7 +58,7 @@ Curve25519_PublicKey::Curve25519_PublicKey(const AlgorithmIdentifier&, size_check(m_public.size(), "public key"); } -std::vector<byte> Curve25519_PublicKey::x509_subject_public_key() const +std::vector<byte> Curve25519_PublicKey::public_key_bits() const { return DER_Encoder() .start_cons(SEQUENCE) @@ -88,7 +88,7 @@ Curve25519_PrivateKey::Curve25519_PrivateKey(const AlgorithmIdentifier&, size_check(m_private.size(), "private key"); } -secure_vector<byte> Curve25519_PrivateKey::pkcs8_private_key() const +secure_vector<byte> Curve25519_PrivateKey::private_key_bits() const { return DER_Encoder() .start_cons(SEQUENCE) diff --git a/src/lib/pubkey/curve25519/curve25519.h b/src/lib/pubkey/curve25519/curve25519.h index 40d9d81da..41f32c931 100644 --- a/src/lib/pubkey/curve25519/curve25519.h +++ b/src/lib/pubkey/curve25519/curve25519.h @@ -25,7 +25,7 @@ class BOTAN_DLL Curve25519_PublicKey : public virtual Public_Key AlgorithmIdentifier algorithm_identifier() const override; - std::vector<byte> x509_subject_public_key() const override; + std::vector<byte> public_key_bits() const override; std::vector<byte> public_value() const { return m_public; } @@ -86,7 +86,7 @@ class BOTAN_DLL Curve25519_PrivateKey : public Curve25519_PublicKey, const secure_vector<byte>& get_x() const { return m_private; } - secure_vector<byte> pkcs8_private_key() const override; + secure_vector<byte> private_key_bits() const override; bool check_key(RandomNumberGenerator& rng, bool strong) const override; diff --git a/src/lib/pubkey/dh/info.txt b/src/lib/pubkey/dh/info.txt index 13ee41d5b..960872fe3 100644 --- a/src/lib/pubkey/dh/info.txt +++ b/src/lib/pubkey/dh/info.txt @@ -4,10 +4,6 @@ define DIFFIE_HELLMAN 20131128 dh.h </header:public> -<source> -dh.cpp -</source> - <requires> dl_algo dl_group diff --git a/src/lib/pubkey/dl_algo/dl_algo.cpp b/src/lib/pubkey/dl_algo/dl_algo.cpp index f5c6ddabb..baa8a66f4 100644 --- a/src/lib/pubkey/dl_algo/dl_algo.cpp +++ b/src/lib/pubkey/dl_algo/dl_algo.cpp @@ -29,7 +29,7 @@ AlgorithmIdentifier DL_Scheme_PublicKey::algorithm_identifier() const m_group.DER_encode(group_format())); } -std::vector<byte> DL_Scheme_PublicKey::x509_subject_public_key() const +std::vector<byte> DL_Scheme_PublicKey::public_key_bits() const { return DER_Encoder().encode(m_y).get_contents_unlocked(); } @@ -43,7 +43,7 @@ DL_Scheme_PublicKey::DL_Scheme_PublicKey(const AlgorithmIdentifier& alg_id, BER_Decoder(key_bits).decode(m_y); } -secure_vector<byte> DL_Scheme_PrivateKey::pkcs8_private_key() const +secure_vector<byte> DL_Scheme_PrivateKey::private_key_bits() const { return DER_Encoder().encode(m_x).get_contents(); } diff --git a/src/lib/pubkey/dl_algo/dl_algo.h b/src/lib/pubkey/dl_algo/dl_algo.h index 7e90bc3b7..46f86a1bb 100644 --- a/src/lib/pubkey/dl_algo/dl_algo.h +++ b/src/lib/pubkey/dl_algo/dl_algo.h @@ -23,7 +23,7 @@ class BOTAN_DLL DL_Scheme_PublicKey : public virtual Public_Key AlgorithmIdentifier algorithm_identifier() const override; - std::vector<byte> x509_subject_public_key() const override; + std::vector<byte> public_key_bits() const override; /** * Get the DL domain parameters of this key. @@ -102,7 +102,7 @@ class BOTAN_DLL DL_Scheme_PrivateKey : public virtual DL_Scheme_PublicKey, */ const BigInt& get_x() const { return m_x; } - secure_vector<byte> pkcs8_private_key() const override; + secure_vector<byte> private_key_bits() const override; /** * Create a private key. diff --git a/src/lib/pubkey/dl_group/named.cpp b/src/lib/pubkey/dl_group/dl_named.cpp index 9c084c80b..9c084c80b 100644 --- a/src/lib/pubkey/dl_group/named.cpp +++ b/src/lib/pubkey/dl_group/dl_named.cpp diff --git a/src/lib/pubkey/ec_group/named.cpp b/src/lib/pubkey/ec_group/ec_named.cpp index c19b8ed37..c19b8ed37 100644 --- a/src/lib/pubkey/ec_group/named.cpp +++ b/src/lib/pubkey/ec_group/ec_named.cpp diff --git a/src/lib/pubkey/ecc_key/ecc_key.cpp b/src/lib/pubkey/ecc_key/ecc_key.cpp index ea2bb48e9..195da0a63 100644 --- a/src/lib/pubkey/ecc_key/ecc_key.cpp +++ b/src/lib/pubkey/ecc_key/ecc_key.cpp @@ -55,7 +55,7 @@ AlgorithmIdentifier EC_PublicKey::algorithm_identifier() const return AlgorithmIdentifier(get_oid(), DER_domain()); } -std::vector<byte> EC_PublicKey::x509_subject_public_key() const +std::vector<byte> EC_PublicKey::public_key_bits() const { return unlock(EC2OSP(public_point(), PointGFp::COMPRESSED)); } @@ -110,7 +110,7 @@ EC_PrivateKey::EC_PrivateKey(RandomNumberGenerator& rng, "Generated public key point was on the curve"); } -secure_vector<byte> EC_PrivateKey::pkcs8_private_key() const +secure_vector<byte> EC_PrivateKey::private_key_bits() const { return DER_Encoder() .start_cons(SEQUENCE) diff --git a/src/lib/pubkey/ecc_key/ecc_key.h b/src/lib/pubkey/ecc_key/ecc_key.h index 375c8e85c..c2d1b057c 100644 --- a/src/lib/pubkey/ecc_key/ecc_key.h +++ b/src/lib/pubkey/ecc_key/ecc_key.h @@ -55,7 +55,7 @@ class BOTAN_DLL EC_PublicKey : public virtual Public_Key AlgorithmIdentifier algorithm_identifier() const override; - std::vector<byte> x509_subject_public_key() const override; + std::vector<byte> public_key_bits() const override; bool check_key(RandomNumberGenerator& rng, bool strong) const override; @@ -132,7 +132,7 @@ class BOTAN_DLL EC_PrivateKey : public virtual EC_PublicKey, const secure_vector<byte>& key_bits, bool with_modular_inverse=false); - secure_vector<byte> pkcs8_private_key() const override; + secure_vector<byte> private_key_bits() const override; /** * Get the private key value of this key object. diff --git a/src/lib/pubkey/gost_3410/gost_3410.cpp b/src/lib/pubkey/gost_3410/gost_3410.cpp index ed01450c8..d10ad0575 100644 --- a/src/lib/pubkey/gost_3410/gost_3410.cpp +++ b/src/lib/pubkey/gost_3410/gost_3410.cpp @@ -15,7 +15,7 @@ namespace Botan { -std::vector<byte> GOST_3410_PublicKey::x509_subject_public_key() const +std::vector<byte> GOST_3410_PublicKey::public_key_bits() const { const BigInt x = public_point().get_affine_x(); const BigInt y = public_point().get_affine_y(); diff --git a/src/lib/pubkey/gost_3410/gost_3410.h b/src/lib/pubkey/gost_3410/gost_3410.h index c844e0fab..a80b41fc7 100644 --- a/src/lib/pubkey/gost_3410/gost_3410.h +++ b/src/lib/pubkey/gost_3410/gost_3410.h @@ -46,7 +46,7 @@ class BOTAN_DLL GOST_3410_PublicKey : public virtual EC_PublicKey AlgorithmIdentifier algorithm_identifier() const override; - std::vector<byte> x509_subject_public_key() const override; + std::vector<byte> public_key_bits() const override; size_t message_parts() const override { return 2; } diff --git a/src/lib/pubkey/info.txt b/src/lib/pubkey/info.txt index d74adddf1..d598e7b25 100644 --- a/src/lib/pubkey/info.txt +++ b/src/lib/pubkey/info.txt @@ -1,20 +1,10 @@ define PUBLIC_KEY_CRYPTO 20131128 -<source> -blinding.cpp -pk_algs.cpp -pk_keys.cpp -pk_ops.cpp -pkcs8.cpp -pubkey.cpp -workfactor.cpp -x509_key.cpp -</source> - <header:public> blinding.h pk_algs.h pk_keys.h +pk_ops.h pk_ops_fwd.h pkcs8.h pubkey.h @@ -23,7 +13,6 @@ x509_key.h </header:public> <header:internal> -pk_ops.h pk_ops_impl.h </header:internal> diff --git a/src/lib/pubkey/mce/code_based_key_gen.cpp b/src/lib/pubkey/mce/code_based_key_gen.cpp index 8fb290386..839ebc977 100644 --- a/src/lib/pubkey/mce/code_based_key_gen.cpp +++ b/src/lib/pubkey/mce/code_based_key_gen.cpp @@ -1,4 +1,4 @@ -/** +/* * (C) Copyright Projet SECRET, INRIA, Rocquencourt * (C) Bhaskar Biswas and Nicolas Sendrier * diff --git a/src/lib/pubkey/mce/code_based_util.h b/src/lib/pubkey/mce/code_based_util.h index 31c962746..9b5395f41 100644 --- a/src/lib/pubkey/mce/code_based_util.h +++ b/src/lib/pubkey/mce/code_based_util.h @@ -1,4 +1,4 @@ -/** +/* * (C) Copyright Projet SECRET, INRIA, Rocquencourt * (C) Bhaskar Biswas and Nicolas Sendrier * @@ -18,7 +18,7 @@ namespace Botan { /** * Expand an input to a bit mask depending on it being being zero or non-zero -* @ param tst the input +* @param tst the input * @return the mask 0xFFFF if tst is non-zero and 0 otherwise */ template<typename T> diff --git a/src/lib/pubkey/mce/gf2m_rootfind_dcmp.cpp b/src/lib/pubkey/mce/gf2m_rootfind_dcmp.cpp index c9d82fdbf..74cb1c64b 100644 --- a/src/lib/pubkey/mce/gf2m_rootfind_dcmp.cpp +++ b/src/lib/pubkey/mce/gf2m_rootfind_dcmp.cpp @@ -1,4 +1,4 @@ -/** +/* * (C) 2014 cryptosource GmbH * (C) 2014 Falko Strenzke [email protected] * diff --git a/src/lib/pubkey/mce/gf2m_small_m.h b/src/lib/pubkey/mce/gf2m_small_m.h index 0b27a82e3..595ef3999 100644 --- a/src/lib/pubkey/mce/gf2m_small_m.h +++ b/src/lib/pubkey/mce/gf2m_small_m.h @@ -1,4 +1,4 @@ -/** +/* * (C) Copyright Projet SECRET, INRIA, Rocquencourt * (C) Bhaskar Biswas and Nicolas Sendrier * diff --git a/src/lib/pubkey/mce/goppa_code.cpp b/src/lib/pubkey/mce/goppa_code.cpp index e866a1631..cbec6302a 100644 --- a/src/lib/pubkey/mce/goppa_code.cpp +++ b/src/lib/pubkey/mce/goppa_code.cpp @@ -1,4 +1,4 @@ -/** +/* * (C) Copyright Projet SECRET, INRIA, Rocquencourt * (C) Bhaskar Biswas and Nicolas Sendrier * diff --git a/src/lib/pubkey/mce/mce_internal.h b/src/lib/pubkey/mce/mce_internal.h index 526552944..fb995e758 100644 --- a/src/lib/pubkey/mce/mce_internal.h +++ b/src/lib/pubkey/mce/mce_internal.h @@ -1,4 +1,4 @@ -/** +/* * (C) Copyright Projet SECRET, INRIA, Rocquencourt * (C) Bhaskar Biswas and Nicolas Sendrier * @@ -14,7 +14,7 @@ #include <botan/secmem.h> #include <botan/types.h> -#include <botan/internal/pk_ops.h> +#include <botan/pk_ops.h> #include <botan/mceliece.h> namespace Botan { diff --git a/src/lib/pubkey/mce/workfactor.cpp b/src/lib/pubkey/mce/mce_workfactor.cpp index 9594c0aab..51cfcc269 100644 --- a/src/lib/pubkey/mce/workfactor.cpp +++ b/src/lib/pubkey/mce/mce_workfactor.cpp @@ -1,4 +1,4 @@ -/** +/* * (C) Copyright Projet SECRET, INRIA, Rocquencourt * (C) Bhaskar Biswas and Nicolas Sendrier * (C) 2014 Jack Lloyd diff --git a/src/lib/pubkey/mce/mceliece.cpp b/src/lib/pubkey/mce/mceliece.cpp index dd05b8212..7617ff11f 100644 --- a/src/lib/pubkey/mce/mceliece.cpp +++ b/src/lib/pubkey/mce/mceliece.cpp @@ -1,4 +1,4 @@ -/** +/* * (C) Copyright Projet SECRET, INRIA, Rocquencourt * (C) Bhaskar Biswas and Nicolas Sendrier * diff --git a/src/lib/pubkey/mce/mceliece.h b/src/lib/pubkey/mce/mceliece.h index c46be4a49..0731e0c68 100644 --- a/src/lib/pubkey/mce/mceliece.h +++ b/src/lib/pubkey/mce/mceliece.h @@ -1,4 +1,4 @@ -/** +/* * (C) Copyright Projet SECRET, INRIA, Rocquencourt * (C) Bhaskar Biswas and Nicolas Sendrier * @@ -40,7 +40,7 @@ class BOTAN_DLL McEliece_PublicKey : public virtual Public_Key size_t key_length() const override; size_t estimated_strength() const override; - std::vector<byte> x509_subject_public_key() const override; + std::vector<byte> public_key_bits() const override; bool check_key(RandomNumberGenerator&, bool) const override { return true; } @@ -104,7 +104,7 @@ class BOTAN_DLL McEliece_PrivateKey : public virtual McEliece_PublicKey, inline u32bit get_codimension() const { return m_codimension; } - secure_vector<byte> pkcs8_private_key() const override; + secure_vector<byte> private_key_bits() const override; bool operator==(const McEliece_PrivateKey & other) const; diff --git a/src/lib/pubkey/mce/mceliece_key.cpp b/src/lib/pubkey/mce/mceliece_key.cpp index da92479ef..409688153 100644 --- a/src/lib/pubkey/mce/mceliece_key.cpp +++ b/src/lib/pubkey/mce/mceliece_key.cpp @@ -1,4 +1,4 @@ -/** +/* * (C) Copyright Projet SECRET, INRIA, Rocquencourt * (C) Bhaskar Biswas and Nicolas Sendrier * @@ -69,7 +69,7 @@ AlgorithmIdentifier McEliece_PublicKey::algorithm_identifier() const return AlgorithmIdentifier(get_oid(), std::vector<byte>()); } -std::vector<byte> McEliece_PublicKey::x509_subject_public_key() const +std::vector<byte> McEliece_PublicKey::public_key_bits() const { return DER_Encoder() .start_cons(SEQUENCE) @@ -115,7 +115,7 @@ McEliece_PublicKey::McEliece_PublicKey(const std::vector<byte>& key_bits) m_code_length = n; } -secure_vector<byte> McEliece_PrivateKey::pkcs8_private_key() const +secure_vector<byte> McEliece_PrivateKey::private_key_bits() const { DER_Encoder enc; enc.start_cons(SEQUENCE) diff --git a/src/lib/pubkey/mce/polyn_gf2m.cpp b/src/lib/pubkey/mce/polyn_gf2m.cpp index e0d1c5a65..2815181c1 100644 --- a/src/lib/pubkey/mce/polyn_gf2m.cpp +++ b/src/lib/pubkey/mce/polyn_gf2m.cpp @@ -1,4 +1,4 @@ -/** +/* * (C) Copyright Projet SECRET, INRIA, Rocquencourt * (C) Bhaskar Biswas and Nicolas Sendrier * diff --git a/src/lib/pubkey/mce/polyn_gf2m.h b/src/lib/pubkey/mce/polyn_gf2m.h index 62264e480..73e495fba 100644 --- a/src/lib/pubkey/mce/polyn_gf2m.h +++ b/src/lib/pubkey/mce/polyn_gf2m.h @@ -1,4 +1,4 @@ -/** +/* * (C) Copyright Projet SECRET, INRIA, Rocquencourt * (C) Bhaskar Biswas and Nicolas Sendrier * diff --git a/src/lib/pubkey/pk_algs.cpp b/src/lib/pubkey/pk_algs.cpp index 7cccd0168..178001316 100644 --- a/src/lib/pubkey/pk_algs.cpp +++ b/src/lib/pubkey/pk_algs.cpp @@ -242,7 +242,7 @@ create_private_key(const std::string& alg_name, if(alg_name == "XMSS") { return std::unique_ptr<Private_Key>( - new XMSS_PrivateKey(XMSS_Parameters(params).oid(), rng)); + new XMSS_PrivateKey(XMSS_Parameters(params.empty() ? "XMSS_SHA2-512_W16_H10" : params).oid(), rng)); } #endif diff --git a/src/lib/pubkey/pk_keys.cpp b/src/lib/pubkey/pk_keys.cpp index 22b8cf0c0..06833958d 100644 --- a/src/lib/pubkey/pk_keys.cpp +++ b/src/lib/pubkey/pk_keys.cpp @@ -6,7 +6,7 @@ */ #include <botan/pk_keys.h> -#include <botan/internal/pk_ops.h> +#include <botan/pk_ops.h> #include <botan/der_enc.h> #include <botan/oids.h> #include <botan/hash.h> @@ -14,6 +14,16 @@ namespace Botan { +std::vector<byte> Public_Key::subject_public_key() const + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(algorithm_identifier()) + .encode(public_key_bits(), BIT_STRING) + .end_cons() + .get_contents_unlocked(); + } + /* * Default OID access */ @@ -28,12 +38,25 @@ OID Public_Key::get_oid() const } } +secure_vector<byte> Private_Key::private_key_info() const + { + const size_t PKCS8_VERSION = 0; + + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(PKCS8_VERSION) + .encode(pkcs8_algorithm_identifier()) + .encode(private_key_bits(), OCTET_STRING) + .end_cons() + .get_contents(); + } + /* * Hash of the PKCS #8 encoding for this key object */ std::string Private_Key::fingerprint(const std::string& alg) const { - secure_vector<byte> buf = pkcs8_private_key(); + secure_vector<byte> buf = private_key_bits(); std::unique_ptr<HashFunction> hash(HashFunction::create(alg)); hash->update(buf); const auto hex_print = hex_encode(hash->final()); diff --git a/src/lib/pubkey/pk_keys.h b/src/lib/pubkey/pk_keys.h index 613fbb7dd..f8242f429 100644 --- a/src/lib/pubkey/pk_keys.h +++ b/src/lib/pubkey/pk_keys.h @@ -74,9 +74,14 @@ class BOTAN_DLL Public_Key virtual AlgorithmIdentifier algorithm_identifier() const = 0; /** + * @return BER encoded public key bits + */ + virtual std::vector<byte> public_key_bits() const = 0; + + /** * @return X.509 subject key encoding for this key object */ - virtual std::vector<byte> x509_subject_public_key() const = 0; + std::vector<byte> subject_public_key() const; // Internal or non-public declarations follow @@ -159,9 +164,14 @@ class BOTAN_DLL Private_Key : public virtual Public_Key { public: /** + * @return BER encoded private key bits + */ + virtual secure_vector<byte> private_key_bits() const = 0; + + /** * @return PKCS #8 private key encoding for this key object */ - virtual secure_vector<byte> pkcs8_private_key() const = 0; + secure_vector<byte> private_key_info() const; /** * @return PKCS #8 AlgorithmIdentifier for this key diff --git a/src/lib/pubkey/pk_ops.h b/src/lib/pubkey/pk_ops.h index 57774c3f4..4a136d90f 100644 --- a/src/lib/pubkey/pk_ops.h +++ b/src/lib/pubkey/pk_ops.h @@ -1,5 +1,4 @@ /* -* PK Operation Types * (C) 2010,2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) @@ -8,6 +7,17 @@ #ifndef BOTAN_PK_OPERATIONS_H__ #define BOTAN_PK_OPERATIONS_H__ +/** +* Ordinary applications should never need to include or use this +* header. It is exposed only for specialized applications which want +* to implement new versions of public key crypto without merging them +* as changes to the library. One actual example of such usage is an +* application which creates RSA signatures using a custom TPM library. +* Unless you're doing something like that, you don't need anything +* here. Instead use pubkey.h which wraps these types safely and +* provides a stable application-oriented API. +*/ + #include <botan/pk_keys.h> #include <botan/secmem.h> #include <botan/rng.h> diff --git a/src/lib/pubkey/pk_ops_impl.h b/src/lib/pubkey/pk_ops_impl.h index bde119ab4..48552afab 100644 --- a/src/lib/pubkey/pk_ops_impl.h +++ b/src/lib/pubkey/pk_ops_impl.h @@ -8,7 +8,7 @@ #ifndef BOTAN_PK_OPERATION_IMPL_H__ #define BOTAN_PK_OPERATION_IMPL_H__ -#include <botan/internal/pk_ops.h> +#include <botan/pk_ops.h> namespace Botan { diff --git a/src/lib/pubkey/pkcs8.cpp b/src/lib/pubkey/pkcs8.cpp index f74eb4387..7857e3ee0 100644 --- a/src/lib/pubkey/pkcs8.cpp +++ b/src/lib/pubkey/pkcs8.cpp @@ -129,15 +129,8 @@ secure_vector<byte> PKCS8_decode( */ secure_vector<byte> BER_encode(const Private_Key& key) { - const size_t PKCS8_VERSION = 0; - - return DER_Encoder() - .start_cons(SEQUENCE) - .encode(PKCS8_VERSION) - .encode(key.pkcs8_algorithm_identifier()) - .encode(key.pkcs8_private_key(), OCTET_STRING) - .end_cons() - .get_contents(); + // keeping around for compat + return key.private_key_info(); } /* diff --git a/src/lib/pubkey/pubkey.cpp b/src/lib/pubkey/pubkey.cpp index 580f990a1..dc98d6551 100644 --- a/src/lib/pubkey/pubkey.cpp +++ b/src/lib/pubkey/pubkey.cpp @@ -8,7 +8,7 @@ #include <botan/der_enc.h> #include <botan/ber_dec.h> #include <botan/bigint.h> -#include <botan/internal/pk_ops.h> +#include <botan/pk_ops.h> #include <botan/internal/ct_utils.h> namespace Botan { diff --git a/src/lib/pubkey/pubkey.h b/src/lib/pubkey/pubkey.h index 398db82d2..f80e761dd 100644 --- a/src/lib/pubkey/pubkey.h +++ b/src/lib/pubkey/pubkey.h @@ -30,6 +30,7 @@ enum Signature_Format { IEEE_1363, DER_SEQUENCE }; /** * Public Key Encryptor +* This is the primary interface for public key encryption */ class BOTAN_DLL PK_Encryptor { diff --git a/src/lib/pubkey/rsa/rsa.cpp b/src/lib/pubkey/rsa/rsa.cpp index 4302aa88a..59f3ed142 100644 --- a/src/lib/pubkey/rsa/rsa.cpp +++ b/src/lib/pubkey/rsa/rsa.cpp @@ -41,7 +41,7 @@ AlgorithmIdentifier RSA_PublicKey::algorithm_identifier() const AlgorithmIdentifier::USE_NULL_PARAM); } -std::vector<byte> RSA_PublicKey::x509_subject_public_key() const +std::vector<byte> RSA_PublicKey::public_key_bits() const { return DER_Encoder() .start_cons(SEQUENCE) @@ -72,7 +72,7 @@ bool RSA_PublicKey::check_key(RandomNumberGenerator&, bool) const return true; } -secure_vector<byte> RSA_PrivateKey::pkcs8_private_key() const +secure_vector<byte> RSA_PrivateKey::private_key_bits() const { return DER_Encoder() .start_cons(SEQUENCE) diff --git a/src/lib/pubkey/rsa/rsa.h b/src/lib/pubkey/rsa/rsa.h index f576a5f07..0a779b56a 100644 --- a/src/lib/pubkey/rsa/rsa.h +++ b/src/lib/pubkey/rsa/rsa.h @@ -41,7 +41,7 @@ class BOTAN_DLL RSA_PublicKey : public virtual Public_Key AlgorithmIdentifier algorithm_identifier() const override; - std::vector<byte> x509_subject_public_key() const override; + std::vector<byte> public_key_bits() const override; /** * @return public modulus @@ -138,7 +138,7 @@ class BOTAN_DLL RSA_PrivateKey : public Private_Key, public RSA_PublicKey const BigInt& get_d1() const { return m_d1; } const BigInt& get_d2() const { return m_d2; } - secure_vector<byte> pkcs8_private_key() const override; + secure_vector<byte> private_key_bits() const override; std::unique_ptr<PK_Ops::Decryption> create_decryption_op(RandomNumberGenerator& rng, diff --git a/src/lib/pubkey/workfactor.h b/src/lib/pubkey/workfactor.h index eb86b6d88..1fccc1a1b 100644 --- a/src/lib/pubkey/workfactor.h +++ b/src/lib/pubkey/workfactor.h @@ -17,7 +17,7 @@ namespace Botan { * @param prime_group_size size of the group in bits * @return estimated security level for this group */ -size_t dl_work_factor(size_t prime_group_size); +BOTAN_DLL size_t dl_work_factor(size_t prime_group_size); /** * Return the appropriate exponent size to use for a particular prime @@ -29,21 +29,21 @@ size_t dl_work_factor(size_t prime_group_size); * algorithm can compute the DL in sqrt(x) operations) while minimizing * the exponent size for performance reasons. */ -size_t dl_exponent_size(size_t prime_group_size); +BOTAN_DLL size_t dl_exponent_size(size_t prime_group_size); /** * Estimate work factor for integer factorization * @param n_bits size of modulus in bits * @return estimated security level for this modulus */ -size_t if_work_factor(size_t n_bits); +BOTAN_DLL size_t if_work_factor(size_t n_bits); /** * Estimate work factor for EC discrete logarithm * @param prime_group_size size of the group in bits * @return estimated security level for this group */ -size_t ecp_work_factor(size_t prime_group_size); +BOTAN_DLL size_t ecp_work_factor(size_t prime_group_size); } diff --git a/src/lib/pubkey/x509_key.cpp b/src/lib/pubkey/x509_key.cpp index f4cfe805e..f1db29bc4 100644 --- a/src/lib/pubkey/x509_key.cpp +++ b/src/lib/pubkey/x509_key.cpp @@ -18,12 +18,8 @@ namespace X509 { std::vector<byte> BER_encode(const Public_Key& key) { - return DER_Encoder() - .start_cons(SEQUENCE) - .encode(key.algorithm_identifier()) - .encode(key.x509_subject_public_key(), BIT_STRING) - .end_cons() - .get_contents_unlocked(); + // keeping it around for compat + return key.subject_public_key(); } /* @@ -31,7 +27,7 @@ std::vector<byte> BER_encode(const Public_Key& key) */ std::string PEM_encode(const Public_Key& key) { - return PEM_Code::encode(X509::BER_encode(key), + return PEM_Code::encode(key.subject_public_key(), "PUBLIC KEY"); } diff --git a/src/lib/pubkey/xmss/atomic.h b/src/lib/pubkey/xmss/atomic.h index 485728d54..cf3f5528c 100644 --- a/src/lib/pubkey/xmss/atomic.h +++ b/src/lib/pubkey/xmss/atomic.h @@ -1,4 +1,4 @@ -/** +/* * Atomic * (C) 2016 Matthias Gierlings * diff --git a/src/lib/pubkey/xmss/info.txt b/src/lib/pubkey/xmss/info.txt index bab541625..8a834ffeb 100644 --- a/src/lib/pubkey/xmss/info.txt +++ b/src/lib/pubkey/xmss/info.txt @@ -1,20 +1,5 @@ define XMSS 20161008 -<source> -xmss_common_ops.cpp -xmss_hash.cpp -xmss_index_registry.cpp -xmss_parameters.cpp -xmss_privatekey.cpp -xmss_publickey.cpp -xmss_signature.cpp -xmss_signature_operation.cpp -xmss_verification_operation.cpp -xmss_wots_parameters.cpp -xmss_wots_privatekey.cpp -xmss_wots_publickey.cpp -</source> - <header:public> atomic.h xmss.h @@ -33,6 +18,11 @@ xmss_wots_publickey.h </header:public> <header:internal> +xmss_wots_addressed_privatekey.h +xmss_wots_addressed_publickey.h +xmss_wots_common_ops.h +xmss_wots_signature_operation.h +xmss_wots_verification_operation.h xmss_signature.h xmss_signature_operation.h xmss_verification_operation.h @@ -42,4 +32,5 @@ xmss_verification_operation.h asn1 rng hash +sha2_32 </requires> diff --git a/src/lib/pubkey/xmss/xmss.h b/src/lib/pubkey/xmss/xmss.h index f12871672..bad7f2aad 100644 --- a/src/lib/pubkey/xmss/xmss.h +++ b/src/lib/pubkey/xmss/xmss.h @@ -1,4 +1,4 @@ -/** +/* * XMSS * Includes XMSS headers. * (C) 2016 Matthias Gierlings diff --git a/src/lib/pubkey/xmss/xmss_address.h b/src/lib/pubkey/xmss/xmss_address.h index 438059cba..07bfd1dbf 100644 --- a/src/lib/pubkey/xmss/xmss_address.h +++ b/src/lib/pubkey/xmss/xmss_address.h @@ -1,4 +1,4 @@ -/** +/* * XMSS Address * (C) 2016 Matthias Gierlings * diff --git a/src/lib/pubkey/xmss/xmss_common_ops.cpp b/src/lib/pubkey/xmss/xmss_common_ops.cpp index dd139a349..aec584201 100644 --- a/src/lib/pubkey/xmss/xmss_common_ops.cpp +++ b/src/lib/pubkey/xmss/xmss_common_ops.cpp @@ -1,4 +1,4 @@ -/** +/* * XMSS Common Ops * Operations shared by XMSS signature generation and verification operations. * (C) 2016 Matthias Gierlings diff --git a/src/lib/pubkey/xmss/xmss_common_ops.h b/src/lib/pubkey/xmss/xmss_common_ops.h index 74ae52a78..bcf036f5c 100644 --- a/src/lib/pubkey/xmss/xmss_common_ops.h +++ b/src/lib/pubkey/xmss/xmss_common_ops.h @@ -1,4 +1,4 @@ -/** +/* * XMSS Common Ops * (C) 2016 Matthias Gierlings * diff --git a/src/lib/pubkey/xmss/xmss_hash.cpp b/src/lib/pubkey/xmss/xmss_hash.cpp index 2dfcabbbc..3731f7751 100644 --- a/src/lib/pubkey/xmss/xmss_hash.cpp +++ b/src/lib/pubkey/xmss/xmss_hash.cpp @@ -1,4 +1,4 @@ -/** +/* * XMSS Hash * A collection of pseudorandom hash functions required for XMSS and WOTS * computations. @@ -8,6 +8,7 @@ **/ #include <botan/xmss_hash.h> +#include <botan/exceptn.h> namespace Botan { @@ -16,14 +17,19 @@ XMSS_Hash::XMSS_Hash(const XMSS_Hash& hash) { } -XMSS_Hash::XMSS_Hash(const std::string& h_func_name) - : m_hash(HashFunction::create(h_func_name)), - m_msg_hash(HashFunction::create(h_func_name)), - m_output_length(m_hash->output_length()), - m_zero_padding(m_output_length - 1, 0x00), - m_hash_func_name(h_func_name) +XMSS_Hash::XMSS_Hash(const std::string& h_func_name) : + m_hash_func_name(h_func_name), + m_hash(HashFunction::create(h_func_name)) { + if(!m_hash) + throw Lookup_Error("XMSS cannot use hash " + h_func_name + + " because it is unavailable"); + + m_output_length = m_hash->output_length(); BOTAN_ASSERT(m_output_length > 0, "Hash output length of zero is invalid."); + + m_zero_padding.resize(m_output_length - 1); + m_msg_hash.reset(m_hash->clone()); } void diff --git a/src/lib/pubkey/xmss/xmss_hash.h b/src/lib/pubkey/xmss/xmss_hash.h index 1af9feb25..2cca26658 100644 --- a/src/lib/pubkey/xmss/xmss_hash.h +++ b/src/lib/pubkey/xmss/xmss_hash.h @@ -1,4 +1,4 @@ -/** +/* * XMSS Hash * (C) 2016 Matthias Gierlings * @@ -147,17 +147,18 @@ class XMSS_Hash size_t output_length() const { return m_output_length; }; private: + static const byte m_id_f = 0x00; + static const byte m_id_h = 0x01; + static const byte m_id_hmsg = 0x02; + static const byte m_id_prf = 0x03; + + const std::string m_hash_func_name; std::unique_ptr<HashFunction> m_hash; std::unique_ptr<HashFunction> m_msg_hash; size_t m_output_length; //32 byte id prefixes prepended to the hash input. std::vector<byte> m_zero_padding; - static const byte m_id_f = 0x00; - static const byte m_id_h = 0x01; - static const byte m_id_hmsg = 0x02; - static const byte m_id_prf = 0x03; - const std::string m_hash_func_name; }; } diff --git a/src/lib/pubkey/xmss/xmss_index_registry.cpp b/src/lib/pubkey/xmss/xmss_index_registry.cpp index a85bc7c9f..e26cfdad4 100644 --- a/src/lib/pubkey/xmss/xmss_index_registry.cpp +++ b/src/lib/pubkey/xmss/xmss_index_registry.cpp @@ -1,4 +1,4 @@ -/** +/* * XMSS Index Registry * A registry for XMSS private keys, keeps track of the leaf index for * independend copies of the same key. diff --git a/src/lib/pubkey/xmss/xmss_index_registry.h b/src/lib/pubkey/xmss/xmss_index_registry.h index 8759ca03b..77842e4f3 100644 --- a/src/lib/pubkey/xmss/xmss_index_registry.h +++ b/src/lib/pubkey/xmss/xmss_index_registry.h @@ -1,4 +1,4 @@ -/** +/* * XMSS Index Registry * (C) 2016 Matthias Gierlings * diff --git a/src/lib/pubkey/xmss/xmss_key_pair.h b/src/lib/pubkey/xmss/xmss_key_pair.h index 4d86f1766..d6c82af60 100644 --- a/src/lib/pubkey/xmss/xmss_key_pair.h +++ b/src/lib/pubkey/xmss/xmss_key_pair.h @@ -1,4 +1,4 @@ -/** +/* * XMSS Key Pair * (C) 2016 Matthias Gierlings * diff --git a/src/lib/pubkey/xmss/xmss_parameters.cpp b/src/lib/pubkey/xmss/xmss_parameters.cpp index 5a106320b..cc4d923dd 100644 --- a/src/lib/pubkey/xmss/xmss_parameters.cpp +++ b/src/lib/pubkey/xmss/xmss_parameters.cpp @@ -1,4 +1,4 @@ -/** +/* * XMSS Parameters * Descibes a signature method for XMSS, as defined in: * [1] XMSS: Extended Hash-Based Signatures, @@ -16,26 +16,41 @@ namespace Botan { -const std::map<std::string, XMSS_Parameters::xmss_algorithm_t> - XMSS_Parameters::m_oid_name_lut = - { - { "XMSS_SHA2-256_W16_H10", XMSS_SHA2_256_W16_H10 }, - { "XMSS_SHA2-256_W16_H16", XMSS_SHA2_256_W16_H16 }, - { "XMSS_SHA2-256_W16_H20", XMSS_SHA2_256_W16_H20 }, - { "XMSS_SHA2-512_W16_H10", XMSS_SHA2_512_W16_H10 }, - { "XMSS_SHA2-512_W16_H16", XMSS_SHA2_512_W16_H16 }, - { "XMSS_SHA2-512_W16_H20", XMSS_SHA2_512_W16_H20 } -// { "XMSS_SHAKE128_W16_H10", xmss_algorithm_t::XMSS_SHAKE128_W16_H10 }, -// { "XMSS_SHAKE128_W16_H16", xmss_algorithm_t::XMSS_SHAKE128_W16_H16 }, -// { "XMSS_SHAKE128_W16_H20", xmss_algorithm_t::XMSS_SHAKE128_W16_H20 }, -// { "XMSS_SHAKE256_W16_H10", xmss_algorithm_t::XMSS_SHAKE256_W16_H10 }, -// { "XMSS_SHAKE256_W16_H16", xmss_algorithm_t::XMSS_SHAKE256_W16_H16 }, -// { "XMSS_SHAKE256_W16_H20", xmss_algorithm_t::XMSS_SHAKE256_W16_H20 } - }; +//static +XMSS_Parameters::xmss_algorithm_t XMSS_Parameters::xmss_id_from_string(const std::string& param_set) + { + if(param_set == "XMSS_SHA2-256_W16_H10") + return XMSS_SHA2_256_W16_H10; + if(param_set == "XMSS_SHA2-256_W16_H16") + return XMSS_SHA2_256_W16_H16; + if(param_set == "XMSS_SHA2-256_W16_H20") + return XMSS_SHA2_256_W16_H20; + if(param_set == "XMSS_SHA2-512_W16_H10") + return XMSS_SHA2_512_W16_H10; + if(param_set == "XMSS_SHA2-512_W16_H16") + return XMSS_SHA2_512_W16_H16; + if(param_set == "XMSS_SHA2-512_W16_H20") + return XMSS_SHA2_512_W16_H20; + if(param_set == "XMSS_SHAKE128_W16_H10") + return XMSS_SHAKE128_W16_H10; + if(param_set == "XMSS_SHAKE128_W16_H16") + return XMSS_SHAKE128_W16_H16; + if(param_set == "XMSS_SHAKE128_W16_H20") + return XMSS_SHAKE128_W16_H20; + if(param_set == "XMSS_SHAKE256_W16_H10") + return XMSS_SHAKE256_W16_H10; + if(param_set == "XMSS_SHAKE256_W16_H16") + return XMSS_SHAKE256_W16_H16; + if(param_set == "XMSS_SHAKE256_W16_H20") + return XMSS_SHAKE256_W16_H20; + throw Lookup_Error("Unknown XMSS algorithm param '" + param_set + "'"); + } + +XMSS_Parameters::XMSS_Parameters(const std::string& param_set) + : XMSS_Parameters(XMSS_Parameters::xmss_id_from_string(param_set)) + { + } -XMSS_Parameters::XMSS_Parameters(const std::string& algo_name) - : XMSS_Parameters(m_oid_name_lut.at(algo_name)) - {} XMSS_Parameters::XMSS_Parameters(xmss_algorithm_t oid) : m_oid(oid) @@ -102,73 +117,66 @@ XMSS_Parameters::XMSS_Parameters(xmss_algorithm_t oid) m_strength = 512; m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHA2_512_W16; break; -// FIXME: Uncomment once SHAKE128/256 implementation is available in Botan. -// case XMSS_SHAKE128_W16_H10: -// m_element_size = 32; -// m_w = 16; -// m_len = 67; -// m_tree_height = 10; -// m_name = "XMSS_SHAKE128_W16_H10"; -// m_hash_name = ""; -// m_strength = 256; -// m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHAKE128_W16; -// BOTAN_ASSERT(false, "XMSS_SHAKE128_W16_H10 not implemented."); -// break; -// case XMSS_SHAKE128_W16_H16: -// m_element_size = 32; -// m_w = 16; -// m_len = 67; -// m_tree_height = 16; -// m_name = "XMSS_SHAKE128_W16_H16"; -// m_hash_name = ""; -// m_strength = 256; -// m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHAKE128_W16; -// BOTAN_ASSERT(false, "XMSS_SHAKE128_W16_H16 not implemented."); -// break; -// case XMSS_SHAKE128_W16_H20: -// m_element_size = 32; -// m_w = 16; -// m_len = 67; -// m_tree_height = 20; -// m_name = "XMSS_SHAKE128_W16_H20"; -// m_hash_name = ""; -// m_strength = 256; -// m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHAKE128_W16; -// BOTAN_ASSERT(false, "XMSS_SHAKE128_W16_H20 not implemented."); -// break; -// case XMSS_SHAKE256_W16_H10: -// m_element_size = 64; -// m_w = 16; -// m_len = 131; -// m_tree_height = 10; -// m_name = "XMSS_SHAKE256_W16_H10"; -// m_hash_name = ""; -// m_strength = 512; -// m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHAKE256_W16; -// BOTAN_ASSERT(false, "XMSS_SHAKE256_W16_H10 not implemented."); -// break; -// case XMSS_SHAKE256_W16_H16: -// m_element_size = 64; -// m_w = 16; -// m_len = 131; -// m_tree_height = 16; -// m_name = "XMSS_SHAKE256_W16_H16"; -// m_hash_name = ""; -// m_strength = 512; -// m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHAKE256_W16; -// BOTAN_ASSERT(false, "XMSS_SHAKE256_W16_H16 not implemented."); -// break; -// case XMSS_SHAKE256_W16_H20: -// m_element_size = 64; -// m_w = 16; -// m_len = 131; -// m_tree_height = 20; -// m_name = "XMSS_SHAKE256_W16_H20"; -// m_hash_name = ""; -// m_strength = 512; -// m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHAKE256_W16; -// BOTAN_ASSERT(false, "XMSS_SHAKE256_W16_H20 not implemented."); -// break; + case XMSS_SHAKE128_W16_H10: + m_element_size = 32; + m_w = 16; + m_len = 67; + m_tree_height = 10; + m_name = "XMSS_SHAKE128_W16_H10"; + m_hash_name = "SHAKE-128(256)"; + m_strength = 256; + m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHAKE128_W16; + break; + case XMSS_SHAKE128_W16_H16: + m_element_size = 32; + m_w = 16; + m_len = 67; + m_tree_height = 16; + m_name = "XMSS_SHAKE128_W16_H16"; + m_hash_name = "SHAKE-128(256)"; + m_strength = 256; + m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHAKE128_W16; + break; + case XMSS_SHAKE128_W16_H20: + m_element_size = 32; + m_w = 16; + m_len = 67; + m_tree_height = 20; + m_name = "XMSS_SHAKE128_W16_H20"; + m_hash_name = "SHAKE-128(256)"; + m_strength = 256; + m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHAKE128_W16; + break; + case XMSS_SHAKE256_W16_H10: + m_element_size = 64; + m_w = 16; + m_len = 131; + m_tree_height = 10; + m_name = "XMSS_SHAKE256_W16_H10"; + m_hash_name = "SHAKE-256(512)"; + m_strength = 512; + m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHAKE256_W16; + break; + case XMSS_SHAKE256_W16_H16: + m_element_size = 64; + m_w = 16; + m_len = 131; + m_tree_height = 16; + m_name = "XMSS_SHAKE256_W16_H16"; + m_hash_name = "SHAKE-256(512)"; + m_strength = 512; + m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHAKE256_W16; + break; + case XMSS_SHAKE256_W16_H20: + m_element_size = 64; + m_w = 16; + m_len = 131; + m_tree_height = 20; + m_name = "XMSS_SHAKE256_W16_H20"; + m_hash_name = "SHAKE-256(512)"; + m_strength = 512; + m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHAKE256_W16; + break; default: throw Unsupported_Argument( "Algorithm id does not match any XMSS algorithm id."); diff --git a/src/lib/pubkey/xmss/xmss_parameters.h b/src/lib/pubkey/xmss/xmss_parameters.h index eb5ff4422..1e8048217 100644 --- a/src/lib/pubkey/xmss/xmss_parameters.h +++ b/src/lib/pubkey/xmss/xmss_parameters.h @@ -1,4 +1,4 @@ -/** +/* * XMSS Parameters * (C) 2016 Matthias Gierlings * @@ -36,15 +36,16 @@ class BOTAN_DLL XMSS_Parameters XMSS_SHA2_512_W16_H10 = 0x04000004, XMSS_SHA2_512_W16_H16 = 0x05000005, XMSS_SHA2_512_W16_H20 = 0x06000006, -// FIXME: Uncomment once SHAKE128/256 implementation is available in Botan. -// XMSS_SHAKE128_W16_H10 = 0x07000007, -// XMSS_SHAKE128_W16_H16 = 0x08000008, -// XMSS_SHAKE128_W16_H20 = 0x09000009, -// XMSS_SHAKE256_W16_H10 = 0x0a00000a, -// XMSS_SHAKE256_W16_H16 = 0x0b00000b, -// XMSS_SHAKE256_W16_H20 = 0x0c00000c + XMSS_SHAKE128_W16_H10 = 0x07000007, + XMSS_SHAKE128_W16_H16 = 0x08000008, + XMSS_SHAKE128_W16_H20 = 0x09000009, + XMSS_SHAKE256_W16_H10 = 0x0a00000a, + XMSS_SHAKE256_W16_H16 = 0x0b00000b, + XMSS_SHAKE256_W16_H20 = 0x0c00000c }; + static xmss_algorithm_t xmss_id_from_string(const std::string& algo_name); + XMSS_Parameters(const std::string& algo_name); XMSS_Parameters(xmss_algorithm_t oid); @@ -107,8 +108,6 @@ class BOTAN_DLL XMSS_Parameters } private: - static const std::map<std::string, xmss_algorithm_t> - m_oid_name_lut; xmss_algorithm_t m_oid; XMSS_WOTS_Parameters::ots_algorithm_t m_wots_oid; std::string m_name; diff --git a/src/lib/pubkey/xmss/xmss_privatekey.cpp b/src/lib/pubkey/xmss/xmss_privatekey.cpp index 18d712a5f..4e4ff73b7 100644 --- a/src/lib/pubkey/xmss/xmss_privatekey.cpp +++ b/src/lib/pubkey/xmss/xmss_privatekey.cpp @@ -1,4 +1,4 @@ -/** +/* * XMSS Private Key * An XMSS: Extended Hash-Based Siganture private key. * The XMSS private key does not support the X509 and PKCS7 standard. Instead diff --git a/src/lib/pubkey/xmss/xmss_privatekey.h b/src/lib/pubkey/xmss/xmss_privatekey.h index a0abb87e7..79959c247 100644 --- a/src/lib/pubkey/xmss/xmss_privatekey.h +++ b/src/lib/pubkey/xmss/xmss_privatekey.h @@ -1,4 +1,4 @@ -/** +/* * XMSS_PrivateKey.h * (C) 2016 Matthias Gierlings * @@ -203,7 +203,7 @@ class BOTAN_DLL XMSS_PrivateKey : public virtual XMSS_PublicKey, const std::string&, const std::string& provider) const override; - virtual secure_vector<byte> pkcs8_private_key() const override + virtual secure_vector<byte> private_key_bits() const override { return raw_private_key(); } diff --git a/src/lib/pubkey/xmss/xmss_publickey.cpp b/src/lib/pubkey/xmss/xmss_publickey.cpp index 4ec33e5f3..9bf166779 100644 --- a/src/lib/pubkey/xmss/xmss_publickey.cpp +++ b/src/lib/pubkey/xmss/xmss_publickey.cpp @@ -1,4 +1,4 @@ -/** +/* * XMSS Public Key * An XMSS: Extended Hash-Based Siganture public key. * The XMSS public key does not support the X509 standard. Instead the diff --git a/src/lib/pubkey/xmss/xmss_publickey.h b/src/lib/pubkey/xmss/xmss_publickey.h index 049a617ca..23c8032c2 100644 --- a/src/lib/pubkey/xmss/xmss_publickey.h +++ b/src/lib/pubkey/xmss/xmss_publickey.h @@ -1,4 +1,4 @@ -/** +/* * XMSS Public Key * (C) 2016 Matthias Gierlings * @@ -23,7 +23,7 @@ #include <botan/pk_keys.h> #include <botan/xmss_parameters.h> #include <botan/xmss_wots_parameters.h> -#include <botan/internal/pk_ops.h> +#include <botan/pk_ops.h> namespace Botan { @@ -216,13 +216,12 @@ class BOTAN_DLL XMSS_PublicKey : public virtual Public_Key } /** - * Currently x509 is not suppoerted for XMSS. x509_subject_public_key() - * returns a raw byte sequence as defined in [1]. This method acts as - * alias for raw_public_key(). + * Returns a raw byte sequence as defined in [1]. + * This method acts as an alias for raw_public_key(). * - * @return raw non x509 compliant public key. + * @return raw public key bits. **/ - virtual std::vector<byte> x509_subject_public_key() const override + virtual std::vector<byte> public_key_bits() const override { return raw_public_key(); } diff --git a/src/lib/pubkey/xmss/xmss_signature.cpp b/src/lib/pubkey/xmss/xmss_signature.cpp index f31dcd8bb..a54d8d9cd 100644 --- a/src/lib/pubkey/xmss/xmss_signature.cpp +++ b/src/lib/pubkey/xmss/xmss_signature.cpp @@ -1,4 +1,4 @@ -/** +/* * XMSS Signature * (C) 2016 Matthias Gierlings * diff --git a/src/lib/pubkey/xmss/xmss_signature.h b/src/lib/pubkey/xmss/xmss_signature.h index 3194ad28c..662aa8988 100644 --- a/src/lib/pubkey/xmss/xmss_signature.h +++ b/src/lib/pubkey/xmss/xmss_signature.h @@ -1,4 +1,4 @@ -/** +/* * XMSS Signature * (C) 2016 Matthias Gierlings * diff --git a/src/lib/pubkey/xmss/xmss_signature_operation.cpp b/src/lib/pubkey/xmss/xmss_signature_operation.cpp index 07121db14..80b9c4746 100644 --- a/src/lib/pubkey/xmss/xmss_signature_operation.cpp +++ b/src/lib/pubkey/xmss/xmss_signature_operation.cpp @@ -1,4 +1,4 @@ -/** +/* * XMSS Signature Operation * Signature generation operation for Extended Hash-Based Signatures (XMSS) as * defined in: @@ -101,7 +101,7 @@ void XMSS_Signature_Operation::initialize() m_randomness = m_hash.prf(m_priv_key.prf(), index_bytes); index_bytes.clear(); XMSS_Tools::concat(index_bytes, m_leaf_idx, - m_priv_key.xmss_parameters().element_size()); + m_priv_key.xmss_parameters().element_size()); m_hash.h_msg_init(m_randomness, m_priv_key.root(), index_bytes); diff --git a/src/lib/pubkey/xmss/xmss_signature_operation.h b/src/lib/pubkey/xmss/xmss_signature_operation.h index 8015e8e12..bd22f3428 100644 --- a/src/lib/pubkey/xmss/xmss_signature_operation.h +++ b/src/lib/pubkey/xmss/xmss_signature_operation.h @@ -1,4 +1,4 @@ -/** +/* * XMSS Signature Operation * (C) 2016 Matthias Gierlings * @@ -17,7 +17,7 @@ #include <botan/xmss_privatekey.h> #include <botan/xmss_address.h> #include <botan/xmss_common_ops.h> -#include <botan/internal/pk_ops.h> +#include <botan/pk_ops.h> #include <botan/internal/xmss_signature.h> #include <botan/xmss_wots_publickey.h> diff --git a/src/lib/pubkey/xmss/xmss_tools.h b/src/lib/pubkey/xmss/xmss_tools.h index 773953fae..66eaf28e2 100644 --- a/src/lib/pubkey/xmss/xmss_tools.h +++ b/src/lib/pubkey/xmss/xmss_tools.h @@ -1,4 +1,4 @@ -/** +/* * XMSS Address * (C) 2016 Matthias Gierlings * @@ -64,13 +64,17 @@ void XMSS_Tools::concat(secure_vector<byte>& target, const T& src) { const byte* src_bytes = reinterpret_cast<const byte*>(&src); if(CPUID::is_little_endian()) + { std::reverse_copy(src_bytes, src_bytes + sizeof(src), std::back_inserter(target)); + } else + { std::copy(src_bytes, src_bytes + sizeof(src), std::back_inserter(target)); + } } @@ -87,13 +91,17 @@ void XMSS_Tools::concat(secure_vector<byte>& target, const byte* src_bytes = reinterpret_cast<const byte*>(&src); if(CPUID::is_little_endian()) + { std::reverse_copy(src_bytes, src_bytes + c, std::back_inserter(target)); + } else + { std::copy(src_bytes + sizeof(src) - c, src_bytes + sizeof(src), std::back_inserter(target)); + } } } diff --git a/src/lib/pubkey/xmss/xmss_verification_operation.cpp b/src/lib/pubkey/xmss/xmss_verification_operation.cpp index 79bd61d17..34d7ee647 100644 --- a/src/lib/pubkey/xmss/xmss_verification_operation.cpp +++ b/src/lib/pubkey/xmss/xmss_verification_operation.cpp @@ -1,4 +1,4 @@ -/** +/* * XMSS Verification Operation * Provides signature verification capabilities for Extended Hash-Based * Signatures (XMSS). @@ -78,8 +78,8 @@ XMSS_Verification_Operation::verify(const XMSS_Signature& sig, XMSS_Address adrs; secure_vector<byte> index_bytes; XMSS_Tools::concat(index_bytes, - sig.unused_leaf_index(), - m_xmss_params.element_size()); + sig.unused_leaf_index(), + m_xmss_params.element_size()); secure_vector<byte> msg_digest = m_hash.h_msg(sig.randomness(), public_key.root(), diff --git a/src/lib/pubkey/xmss/xmss_verification_operation.h b/src/lib/pubkey/xmss/xmss_verification_operation.h index 0f45fd55f..35720f73d 100644 --- a/src/lib/pubkey/xmss/xmss_verification_operation.h +++ b/src/lib/pubkey/xmss/xmss_verification_operation.h @@ -1,4 +1,4 @@ -/** +/* * XMSS Verification Operation * (C) 2016 Matthias Gierlings * @@ -16,7 +16,7 @@ #include <botan/types.h> #include <botan/xmss_publickey.h> #include <botan/xmss_common_ops.h> -#include <botan/internal/pk_ops.h> +#include <botan/pk_ops.h> #include <botan/internal/xmss_signature.h> namespace Botan { diff --git a/src/lib/pubkey/xmss/xmss_wots_addressed_privatekey.h b/src/lib/pubkey/xmss/xmss_wots_addressed_privatekey.h new file mode 100644 index 000000000..deb5d7f87 --- /dev/null +++ b/src/lib/pubkey/xmss/xmss_wots_addressed_privatekey.h @@ -0,0 +1,68 @@ +/** + * XMSS WOTS Addressed Private Key + * (C) 2016 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#ifndef BOTAN_XMSS_WOTS_ADDRESSED_PRIVATEKEY_H__ +#define BOTAN_XMSS_WOTS_ADDRESSED_PRIVATEKEY_H__ + +#include <botan/xmss_address.h> +#include <botan/internal/xmss_wots_addressed_publickey.h> +#include <botan/xmss_wots_privatekey.h> + +namespace Botan { + +/** + * Wrapper class to pair an XMSS_WOTS_PrivateKey with an XMSS Address. Since + * the PK_Ops::Signature interface does not allow an extra address + * parameter to be passed to the sign(RandomNumberGenerator&), the address + * needs to be stored together with the key and passed to the + * XMSS_WOTS_Signature_Operation() on creation. + **/ +class XMSS_WOTS_Addressed_PrivateKey + : public virtual XMSS_WOTS_Addressed_PublicKey, + public virtual Private_Key + { + public: + XMSS_WOTS_Addressed_PrivateKey(const XMSS_WOTS_PrivateKey& private_key) + : XMSS_WOTS_Addressed_PublicKey(private_key), + m_priv_key(private_key) {} + + XMSS_WOTS_Addressed_PrivateKey(const XMSS_WOTS_PrivateKey& private_key, + const XMSS_Address& adrs) + : XMSS_WOTS_Addressed_PublicKey(private_key, adrs), + m_priv_key(private_key) {} + + XMSS_WOTS_Addressed_PrivateKey(XMSS_WOTS_PrivateKey&& private_key) + : XMSS_WOTS_Addressed_PublicKey(XMSS_WOTS_PublicKey(private_key)), + m_priv_key(std::move(private_key)) {} + + XMSS_WOTS_Addressed_PrivateKey(XMSS_WOTS_PrivateKey&& private_key, + XMSS_Address&& adrs) + : XMSS_WOTS_Addressed_PublicKey(XMSS_WOTS_PublicKey(private_key), + std::move(adrs)), + m_priv_key(std::move(private_key)) {} + + const XMSS_WOTS_PrivateKey& private_key() const { return m_priv_key; } + XMSS_WOTS_PrivateKey& private_key() { return m_priv_key; } + + virtual AlgorithmIdentifier + pkcs8_algorithm_identifier() const override + { + return m_priv_key.pkcs8_algorithm_identifier(); + } + + virtual secure_vector<byte> private_key_bits() const override + { + return m_priv_key.private_key_bits(); + } + + private: + XMSS_WOTS_PrivateKey m_priv_key; + }; + +} + +#endif diff --git a/src/lib/pubkey/xmss/xmss_wots_addressed_publickey.h b/src/lib/pubkey/xmss/xmss_wots_addressed_publickey.h new file mode 100644 index 000000000..74e686f9f --- /dev/null +++ b/src/lib/pubkey/xmss/xmss_wots_addressed_publickey.h @@ -0,0 +1,97 @@ +/** + * XMSS WOTS Addressed Public Key + * (C) 2016 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + + +#ifndef BOTAN_XMSS_WOTS_ADDRESSED_PUBLICKEY_H__ +#define BOTAN_XMSS_WOTS_ADDRESSED_PUBLICKEY_H__ + +#include <botan/xmss_address.h> +#include <botan/xmss_wots_publickey.h> + +namespace Botan { + +/** + * Wrapper class to pair a XMSS_WOTS_PublicKey with an XMSS Address. Since + * the PK_Ops::Verification interface does not allow an extra address + * parameter to be passed to the sign(RandomNumberGenerator&), the address + * needs to be stored together with the key and passed to the + * XMSS_WOTS_Verification_Operation() on creation. + **/ +class XMSS_WOTS_Addressed_PublicKey : public virtual Public_Key + { + public: + XMSS_WOTS_Addressed_PublicKey(const XMSS_WOTS_PublicKey& public_key) + : m_pub_key(public_key), m_adrs() {} + + XMSS_WOTS_Addressed_PublicKey(const XMSS_WOTS_PublicKey& public_key, + const XMSS_Address& adrs) + : m_pub_key(public_key), m_adrs(adrs) {} + + XMSS_WOTS_Addressed_PublicKey(XMSS_WOTS_PublicKey&& public_key) + : m_pub_key(std::move(public_key)), m_adrs() {} + + XMSS_WOTS_Addressed_PublicKey(XMSS_WOTS_PublicKey&& public_key, + XMSS_Address&& adrs) + : m_pub_key(std::move(public_key)), m_adrs(std::move(adrs)) {} + + const XMSS_WOTS_PublicKey& public_key() const { return m_pub_key; } + XMSS_WOTS_PublicKey& public_key() { return m_pub_key; } + + const XMSS_Address& address() const { return m_adrs; } + XMSS_Address& address() { return m_adrs; } + + virtual std::string algo_name() const override + { + return m_pub_key.algo_name(); + } + + virtual AlgorithmIdentifier algorithm_identifier() const override + { + return m_pub_key.algorithm_identifier(); + } + + virtual bool check_key(RandomNumberGenerator& rng, + bool strong) const override + { + return m_pub_key.check_key(rng, strong); + } + + virtual std::unique_ptr<PK_Ops::Verification> + create_verification_op(const std::string& params, + const std::string& provider) const override + { + return m_pub_key.create_verification_op(params, provider); + } + + virtual OID get_oid() const override + { + return m_pub_key.get_oid(); + } + + virtual size_t estimated_strength() const override + { + return m_pub_key.estimated_strength(); + } + + virtual size_t key_length() const override + { + return m_pub_key.estimated_strength(); + } + + virtual std::vector<byte> public_key_bits() const override + { + return m_pub_key.public_key_bits(); + } + + protected: + XMSS_WOTS_PublicKey m_pub_key; + XMSS_Address m_adrs; + }; + +} + +#endif diff --git a/src/lib/pubkey/xmss/xmss_wots_common_ops.cpp b/src/lib/pubkey/xmss/xmss_wots_common_ops.cpp new file mode 100644 index 000000000..5d0349677 --- /dev/null +++ b/src/lib/pubkey/xmss/xmss_wots_common_ops.cpp @@ -0,0 +1,40 @@ +/** + * XMSS WOTS Common Ops + * Operations shared by XMSS WOTS signature generation and verification + * operations. + * + * (C) 2016 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#include <botan/internal/xmss_wots_common_ops.h> + +namespace Botan { + +void +XMSS_WOTS_Common_Ops::chain(secure_vector<byte>& result, + size_t start_idx, + size_t steps, + XMSS_Address& adrs, + const secure_vector<byte>& seed) + { + for(size_t i = start_idx; + i < (start_idx + steps) && i < m_wots_params.wots_parameter(); + i++) + { + adrs.set_hash_address(i); + + //Calculate tmp XOR bitmask + adrs.set_key_mask_mode(XMSS_Address::Key_Mask::Mask_Mode); + xor_buf(result, m_hash.prf(seed, adrs.bytes()), result.size()); + + // Calculate key + adrs.set_key_mask_mode(XMSS_Address::Key_Mask::Key_Mode); + + //Calculate f(key, tmp XOR bitmask) + m_hash.f(result, m_hash.prf(seed, adrs.bytes()), result); + } + } + +} diff --git a/src/lib/pubkey/xmss/xmss_wots_common_ops.h b/src/lib/pubkey/xmss/xmss_wots_common_ops.h new file mode 100644 index 000000000..f3153515c --- /dev/null +++ b/src/lib/pubkey/xmss/xmss_wots_common_ops.h @@ -0,0 +1,55 @@ +/** + * XMSS WOTS Common Operations + * (C) 2016 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#ifndef BOTAN_XMSS_WOTS_COMMON_OPS_H__ +#define BOTAN_XMSS_WOTS_COMMON_OPS_H__ + +#include <cstddef> +#include <botan/types.h> +#include <botan/xmss_wots_parameters.h> +#include <botan/xmss_address.h> +#include <botan/xmss_hash.h> + +namespace Botan { + +/** + * Operations shared by XMSS WOTS signature generation and verification + * operations. + **/ +class XMSS_WOTS_Common_Ops + { + public: + XMSS_WOTS_Common_Ops(XMSS_WOTS_Parameters::ots_algorithm_t oid) + : m_wots_params(oid), m_hash(m_wots_params.hash_function_name()) {} + + + protected: + /** + * Algorithm 2: Chaining Function. + * + * @param[out] result Contains the n-byte input string "x" upon call to chain(), + * that will be replaced with the value obtained by iterating + * the cryptographic hash function "F" steps times on the + * input x using the outputs of the PRNG "G". + * @param[in] start_idx The start index. + * @param[in] steps A number of steps. + * @param[in] adrs An OTS Hash Address. + * @param[in] seed A Seed. + **/ + void chain(secure_vector<byte>& result, + size_t start_idx, + size_t steps, + XMSS_Address& adrs, + const secure_vector<byte>& seed); + + XMSS_WOTS_Parameters m_wots_params; + XMSS_Hash m_hash; + }; + +} + +#endif diff --git a/src/lib/pubkey/xmss/xmss_wots_parameters.cpp b/src/lib/pubkey/xmss/xmss_wots_parameters.cpp index 903885d72..3a1c1902d 100644 --- a/src/lib/pubkey/xmss/xmss_wots_parameters.cpp +++ b/src/lib/pubkey/xmss/xmss_wots_parameters.cpp @@ -1,4 +1,4 @@ -/** +/* * XMSS WOTS Parameters * Descibes a signature method for XMSS Winternitz One Time Signatures, * as defined in: @@ -17,15 +17,23 @@ namespace Botan { -const std::map<std::string, XMSS_WOTS_Parameters::ots_algorithm_t> - XMSS_WOTS_Parameters::m_oid_name_lut = +//static +XMSS_WOTS_Parameters::ots_algorithm_t +XMSS_WOTS_Parameters::xmss_wots_id_from_string(const std::string& param_set) { - { "WOTSP_SHA2-256_W16", WOTSP_SHA2_256_W16 }, - { "WOTSP_SHA2-512_W16", WOTSP_SHA2_512_W16 } - }; + if(param_set == "WOTSP_SHA2-256_W16") + return WOTSP_SHA2_256_W16; + if(param_set == "WOTSP_SHA2-512_W16") + return WOTSP_SHA2_512_W16; + if(param_set == "WOTSP_SHAKE128_W16") + return WOTSP_SHAKE128_W16; + if(param_set == "WOTSP_SHAKE256_W16") + return WOTSP_SHAKE256_W16; + throw Invalid_Argument("Unknown XMSS-WOTS algorithm param '" + param_set + "'"); + } -XMSS_WOTS_Parameters::XMSS_WOTS_Parameters(const std::string& algo_name) - : XMSS_WOTS_Parameters(m_oid_name_lut.at(algo_name)) +XMSS_WOTS_Parameters::XMSS_WOTS_Parameters(const std::string& param_set) + : XMSS_WOTS_Parameters(xmss_wots_id_from_string(param_set)) {} XMSS_WOTS_Parameters::XMSS_WOTS_Parameters(ots_algorithm_t oid) @@ -49,23 +57,22 @@ XMSS_WOTS_Parameters::XMSS_WOTS_Parameters(ots_algorithm_t oid) m_hash_name = "SHA-512"; m_strength = 512; break; -// FIXME: Uncomment once SHAKE128/256 implementation is available in Botan. -// case WOTSP_SHAKE128_W16: -// m_element_size = 32; -// m_w = 16; -// m_len = 67; -// m_name = "WOTSP_SHAKE128_W16"; -// m_hash_name = "<MISSING>"; -// m_strength = 256; -// break; -// case WOTSP_SHAKE256_W16: -// m_element_size = 64; -// m_w = 16; -// m_len = 131; -// m_name = "WOTSP_SHAKE256_W16"; -// m_hash_name = "<MISSING>"; -// m_strength = 512; -// break; + case WOTSP_SHAKE128_W16: + m_element_size = 32; + m_w = 16; + m_len = 67; + m_name = "WOTSP_SHAKE128_W16"; + m_hash_name = "SHAKE-128(256)"; + m_strength = 256; + break; + case WOTSP_SHAKE256_W16: + m_element_size = 64; + m_w = 16; + m_len = 131; + m_name = "WOTSP_SHAKE256_W16"; + m_hash_name = "SHAKE-256(512)"; + m_strength = 512; + break; default: throw Unsupported_Argument( "Algorithm id does not match any XMSS WOTS algorithm id."); diff --git a/src/lib/pubkey/xmss/xmss_wots_parameters.h b/src/lib/pubkey/xmss/xmss_wots_parameters.h index a4840c354..cc89c3d4a 100644 --- a/src/lib/pubkey/xmss/xmss_wots_parameters.h +++ b/src/lib/pubkey/xmss/xmss_wots_parameters.h @@ -1,4 +1,4 @@ -/** +/* * XMSS WOTS Parameters * (C) 2016 Matthias Gierlings * @@ -38,14 +38,15 @@ class XMSS_WOTS_Parameters { WOTSP_SHA2_256_W16 = 0x01000001, WOTSP_SHA2_512_W16 = 0x02000002, -// FIXME: Uncomment once SHAKE128/256 implementation is available in Botan. -// WOTSP_SHAKE128_W16 = 0x03000003, -// WOTSP_SHAKE256_W16 = 0x04000004 + WOTSP_SHAKE128_W16 = 0x03000003, + WOTSP_SHAKE256_W16 = 0x04000004 }; XMSS_WOTS_Parameters(const std::string& algo_name); XMSS_WOTS_Parameters(ots_algorithm_t ots_spec); + static ots_algorithm_t xmss_wots_id_from_string(const std::string& param_set); + /** * Algorithm 1: convert input string to base. * diff --git a/src/lib/pubkey/xmss/xmss_wots_privatekey.cpp b/src/lib/pubkey/xmss/xmss_wots_privatekey.cpp index 1a68b187d..e3f4cab94 100644 --- a/src/lib/pubkey/xmss/xmss_wots_privatekey.cpp +++ b/src/lib/pubkey/xmss/xmss_wots_privatekey.cpp @@ -1,4 +1,4 @@ -/** +/* * XMSS WOTS Private Key * A Winternitz One Time Signature private key for use with Extended Hash-Based * Signatures. @@ -8,6 +8,7 @@ * Botan is released under the Simplified BSD License (see license.txt) **/ +#include <botan/internal/xmss_wots_signature_operation.h> #include <botan/xmss_wots_privatekey.h> namespace Botan { @@ -77,4 +78,16 @@ XMSS_WOTS_PrivateKey::sign( return sig; } +std::unique_ptr<PK_Ops::Signature> +XMSS_WOTS_PrivateKey::create_signature_op(RandomNumberGenerator&, + const std::string&, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + return std::unique_ptr<PK_Ops::Signature>( + new XMSS_WOTS_Signature_Operation(*this)); + + throw Provider_Not_Found(algo_name(), provider); + } + } diff --git a/src/lib/pubkey/xmss/xmss_wots_privatekey.h b/src/lib/pubkey/xmss/xmss_wots_privatekey.h index 1a6e50fe8..cf84fd076 100644 --- a/src/lib/pubkey/xmss/xmss_wots_privatekey.h +++ b/src/lib/pubkey/xmss/xmss_wots_privatekey.h @@ -1,4 +1,4 @@ -/** +/* * XMSS WOTS Private Key * (C) 2016 Matthias Gierlings * @@ -12,6 +12,7 @@ #include <memory> #include <botan/alg_id.h> #include <botan/assert.h> +#include <botan/exceptn.h> #include <botan/pk_keys.h> #include <botan/types.h> #include <botan/xmss_wots_parameters.h> @@ -150,8 +151,7 @@ class BOTAN_DLL XMSS_WOTS_PrivateKey : public virtual XMSS_WOTS_PublicKey, * * @return A XMSS_WOTS_PublicKey. **/ - XMSS_WOTS_PublicKey generate_public_key( - XMSS_Address& adrs); + XMSS_WOTS_PublicKey generate_public_key(XMSS_Address& adrs); /** * Algorithm 4: "WOTS_genPK" @@ -165,10 +165,9 @@ class BOTAN_DLL XMSS_WOTS_PrivateKey : public virtual XMSS_WOTS_PublicKey, * @param adrs Hash function address encoding the address of * the WOTS+ key pair within a greater structure. **/ - void generate_public_key( - XMSS_WOTS_PublicKey& pub_key, - wots_keysig_t&& in_key_data, - XMSS_Address& adrs); + void generate_public_key(XMSS_WOTS_PublicKey& pub_key, + wots_keysig_t&& in_key_data, + XMSS_Address& adrs); /** * Algorithm 5: "WOTS_sign" @@ -180,9 +179,8 @@ class BOTAN_DLL XMSS_WOTS_PrivateKey : public virtual XMSS_WOTS_PublicKey, * * @return signature for msg. **/ - wots_keysig_t sign( - const secure_vector<byte>& msg, - XMSS_Address& adrs); + wots_keysig_t sign(const secure_vector<byte>& msg, + XMSS_Address& adrs); /** * Retrieves the secret seed used to generate WOTS+ chains. The seed @@ -195,14 +193,6 @@ class BOTAN_DLL XMSS_WOTS_PrivateKey : public virtual XMSS_WOTS_PublicKey, return m_private_seed; } - ///** - // * Retrieves the secret seed used to generate WOTS+ chains. The seed - // * should be a uniformly random n-byte value. - // * - // * @return secret seed. - // **/ - //secure_vector<byte>& private_seed() { return m_private_seed; } - /** * Sets the secret seed used to generate WOTS+ chains. The seed * should be a uniformly random n-byte value. @@ -228,20 +218,17 @@ class BOTAN_DLL XMSS_WOTS_PrivateKey : public virtual XMSS_WOTS_PublicKey, virtual AlgorithmIdentifier pkcs8_algorithm_identifier() const override { - BOTAN_ASSERT(false, "No AlgorithmIdentifier available for XMSS-WOTS."); + throw Not_Implemented("No AlgorithmIdentifier available for XMSS-WOTS."); } virtual std::unique_ptr<PK_Ops::Signature> create_signature_op(RandomNumberGenerator&, const std::string&, - const std::string&) const override - { - BOTAN_ASSERT(false, "XMSS_WOTS_Signature_Operation not available."); - } + const std::string& provider) const override; - virtual secure_vector<byte> pkcs8_private_key() const override + virtual secure_vector<byte> private_key_bits() const override { - BOTAN_ASSERT(false, "No PKCS8 key format defined for XMSS-WOTS."); + throw Not_Implemented("No PKCS8 key format defined for XMSS-WOTS."); } private: diff --git a/src/lib/pubkey/xmss/xmss_wots_publickey.cpp b/src/lib/pubkey/xmss/xmss_wots_publickey.cpp index aa0240be8..0eea59ea3 100644 --- a/src/lib/pubkey/xmss/xmss_wots_publickey.cpp +++ b/src/lib/pubkey/xmss/xmss_wots_publickey.cpp @@ -1,4 +1,4 @@ -/** +/* * XMSS WOTS Public Key * A Winternitz One Time Signature public key for use with Extended Hash-Based * Signatures. @@ -8,6 +8,7 @@ * Botan is released under the Simplified BSD License (see license.txt) **/ +#include <botan/internal/xmss_wots_verification_operation.h> #include <botan/xmss_wots_publickey.h> namespace Botan { @@ -63,4 +64,16 @@ XMSS_WOTS_PublicKey::pub_key_from_signature(const secure_vector<byte>& msg, return result; } +std::unique_ptr<PK_Ops::Verification> +XMSS_WOTS_PublicKey::create_verification_op(const std::string&, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + { + return std::unique_ptr<PK_Ops::Verification>( + new XMSS_WOTS_Verification_Operation(*this)); + } + throw Provider_Not_Found(algo_name(), provider); + } + } diff --git a/src/lib/pubkey/xmss/xmss_wots_publickey.h b/src/lib/pubkey/xmss/xmss_wots_publickey.h index bf3a8110d..4f414de27 100644 --- a/src/lib/pubkey/xmss/xmss_wots_publickey.h +++ b/src/lib/pubkey/xmss/xmss_wots_publickey.h @@ -1,4 +1,4 @@ -/** +/* * XMSS WOTS Public Key * (C) 2016 Matthias Gierlings * @@ -14,6 +14,7 @@ #include <botan/alg_id.h> #include <botan/asn1_oid.h> #include <botan/assert.h> +#include <botan/exceptn.h> #include <botan/pk_keys.h> #include <botan/types.h> #include <botan/xmss_wots_parameters.h> @@ -199,22 +200,28 @@ class BOTAN_DLL XMSS_WOTS_PublicKey : virtual public Public_Key operator wots_keysig_t& () { return m_key; } const secure_vector<byte>& public_seed() const { return m_public_seed; } + secure_vector<byte>& public_seed() { return m_public_seed; } + void set_public_seed(const secure_vector<byte>& public_seed) { m_public_seed = public_seed; } + void set_public_seed(secure_vector<byte>&& public_seed) { m_public_seed = std::move(public_seed); } const wots_keysig_t& key_data() const { return m_key; } + wots_keysig_t& key_data() { return m_key; } + void set_key_data(const wots_keysig_t& key_data) { m_key = key_data; } + void set_key_data(wots_keysig_t&& key_data) { m_key = std::move(key_data); @@ -232,20 +239,17 @@ class BOTAN_DLL XMSS_WOTS_PublicKey : virtual public Public_Key virtual AlgorithmIdentifier algorithm_identifier() const override { - BOTAN_ASSERT(false, "No AlgorithmIdentifier available for XMSS-WOTS."); + throw Not_Implemented("No AlgorithmIdentifier available for XMSS-WOTS."); } virtual bool check_key(RandomNumberGenerator&, bool) const override { - BOTAN_ASSERT(false, "No key strength check implemented for XMSS-WOTS."); + return true; } virtual std::unique_ptr<PK_Ops::Verification> create_verification_op(const std::string&, - const std::string&) const override - { - BOTAN_ASSERT(false, "XMSS_WOTS_Verification_Operation not available."); - } + const std::string& provider) const override; virtual size_t estimated_strength() const override { @@ -257,19 +261,9 @@ class BOTAN_DLL XMSS_WOTS_PublicKey : virtual public Public_Key return m_wots_params.estimated_strength(); } - virtual size_t message_part_size() const override - { - return m_wots_params.element_size(); - } - - virtual size_t message_parts() const override - { - return 1; - } - - virtual std::vector<byte> x509_subject_public_key() const override + virtual std::vector<byte> public_key_bits() const override { - BOTAN_ASSERT(false, "No x509 key format defined for XMSS-WOTS."); + throw Not_Implemented("No key format defined for XMSS-WOTS"); } bool operator==(const XMSS_WOTS_PublicKey& key) diff --git a/src/lib/pubkey/xmss/xmss_wots_signature_operation.cpp b/src/lib/pubkey/xmss/xmss_wots_signature_operation.cpp new file mode 100644 index 000000000..532e4d782 --- /dev/null +++ b/src/lib/pubkey/xmss/xmss_wots_signature_operation.cpp @@ -0,0 +1,54 @@ +/** + * XMSS WOTS Signature Operation + * Signature generation operation for Winternitz One Time Signatures for use + * in Extended Hash-Based Signatures (XMSS). + * + * This operation is not intended for stand-alone use and thus not registered + * in the Botan algorithm registry. + * + * (C) 2016 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#include <botan/internal/xmss_wots_signature_operation.h> + +namespace Botan { + +XMSS_WOTS_Signature_Operation::XMSS_WOTS_Signature_Operation( + const XMSS_WOTS_Addressed_PrivateKey& private_key) + : XMSS_WOTS_Common_Ops(private_key.private_key().wots_parameters().oid()), + m_priv_key(private_key), + m_msg_buf(0) + { + m_msg_buf.reserve( + m_priv_key.private_key().wots_parameters().element_size()); + } + +void +XMSS_WOTS_Signature_Operation::update(const byte msg[], size_t msg_len) + { + BOTAN_ASSERT(msg_len == m_priv_key.private_key().wots_parameters(). + element_size() && + m_msg_buf.size() == 0, + "XMSS WOTS only supports one message part of size n."); + + for(size_t i = 0; i < msg_len; i++) + m_msg_buf.push_back(msg[i]); + } + +secure_vector<byte> +XMSS_WOTS_Signature_Operation::sign(RandomNumberGenerator&) + { + secure_vector<byte> result(0); + result.reserve(m_wots_params.len() * m_wots_params.element_size()); + XMSS_WOTS_PrivateKey& priv_key = m_priv_key.private_key(); + for(const auto& node : priv_key.sign(m_msg_buf, m_priv_key.address())) + { + std::copy(node.begin(), node.end(), std::back_inserter(result)); + } + + return result; + } + +} diff --git a/src/lib/pubkey/xmss/xmss_wots_signature_operation.h b/src/lib/pubkey/xmss/xmss_wots_signature_operation.h new file mode 100644 index 000000000..59de4ea34 --- /dev/null +++ b/src/lib/pubkey/xmss/xmss_wots_signature_operation.h @@ -0,0 +1,62 @@ +/** + * XMSS WOTS Signature Operation + * (C) 2016 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#ifndef BOTAN_XMSS_WOTS_SIGNATURE_OPERATION_H__ +#define BOTAN_XMSS_WOTS_SIGNATURE_OPERATION_H__ + +#include <cstddef> +#include <iterator> +#include <botan/assert.h> +#include <botan/types.h> +#include <botan/pk_ops.h> +#include <botan/internal/xmss_wots_addressed_privatekey.h> +#include <botan/internal/xmss_wots_common_ops.h> + +namespace Botan { + +/** + * Signature generation operation for Winternitz One Time Signatures for use + * in Extended Hash-Based Signatures (XMSS). + * + * This operation is not intended for stand-alone use and thus not registered + * in the Botan algorithm registry. + ***/ +class XMSS_WOTS_Signature_Operation : public virtual PK_Ops::Signature, + public XMSS_WOTS_Common_Ops + { + public: + XMSS_WOTS_Signature_Operation( + const XMSS_WOTS_Addressed_PrivateKey& private_key); + + virtual ~XMSS_WOTS_Signature_Operation() {} + + /** + * Creates a XMSS WOTS signature for the message provided through call + * to update(). XMSS wots only supports one message part and a fixed + * message size of "n" bytes where "n" equals the element size of + * the chosen XMSS WOTS signature method. The random number generator + * argument is supplied for interface compatibility and remains unused. + * + * @return serialized Winternitz One Time Signature. + **/ + secure_vector<byte> sign(RandomNumberGenerator&) override; + + void update(const byte msg[], size_t msg_len) override; + + private: + wots_keysig_t sign(const secure_vector<byte>& msg, + const wots_keysig_t& priv_key, + XMSS_Address& adrs, + const secure_vector<byte>& seed); + XMSS_WOTS_Addressed_PrivateKey m_priv_key; + secure_vector<byte> m_msg_buf; + }; + +} + +#endif + diff --git a/src/lib/pubkey/xmss/xmss_wots_verification_operation.cpp b/src/lib/pubkey/xmss/xmss_wots_verification_operation.cpp new file mode 100644 index 000000000..d66c508bb --- /dev/null +++ b/src/lib/pubkey/xmss/xmss_wots_verification_operation.cpp @@ -0,0 +1,72 @@ +/** + * XMSS WOTS Verification Operation + * Provides signature verification capabilities for Winternitz One Time + * Signatures used in Extended Hash-Based Signatures (XMSS). + * + * This operation is not intended for stand-alone use and thus not registered + * in the Botan algorithm registry. + * + * (C) 2016 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#include <botan/internal/xmss_wots_verification_operation.h> + +namespace Botan { + +XMSS_WOTS_Verification_Operation::XMSS_WOTS_Verification_Operation( + const XMSS_WOTS_Addressed_PublicKey& public_key) + : XMSS_WOTS_Common_Ops(public_key.public_key().wots_parameters().oid()), + m_pub_key(public_key), + m_msg_buf(0) + { + m_msg_buf.reserve(m_pub_key.public_key().wots_parameters(). + element_size()); + } + +void +XMSS_WOTS_Verification_Operation::update(const byte msg[], size_t msg_len) + { + BOTAN_ASSERT(msg_len == m_pub_key.public_key().wots_parameters(). + element_size() && + m_msg_buf.size() == 0, + "XMSS WOTS only supports one message part of size n."); + + for(size_t i = 0; i < msg_len; i++) + { + m_msg_buf.push_back(msg[i]); + } + } + +bool XMSS_WOTS_Verification_Operation::is_valid_signature(const byte sig[], + size_t sig_len) + { + const XMSS_WOTS_Parameters& w = m_pub_key.public_key().wots_parameters(); + + BOTAN_ASSERT(sig_len == w.element_size() * w.len(), + "Invalid signature size."); + + wots_keysig_t signature(0); + signature.reserve(sig_len); + + size_t begin = 0; + size_t end = 0; + while(signature.size() < w.len()) + { + begin = end; + end = begin + w.element_size(); + signature.push_back(secure_vector<byte>(sig + begin, sig + end)); + } + + XMSS_WOTS_PublicKey pubkey_msg(w.oid(), + m_msg_buf, + signature, + m_pub_key.address(), + m_pub_key.public_key().public_seed()); + + return pubkey_msg.key_data() == m_pub_key.public_key().key_data(); + } + +} + diff --git a/src/lib/pubkey/xmss/xmss_wots_verification_operation.h b/src/lib/pubkey/xmss/xmss_wots_verification_operation.h new file mode 100644 index 000000000..a0cb0709f --- /dev/null +++ b/src/lib/pubkey/xmss/xmss_wots_verification_operation.h @@ -0,0 +1,49 @@ +/** + * XMSS_WOTS_Verification_Operation.h + * (C) 2016 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#ifndef BOTAN_XMSS_WOTS_VERIFICATION_OPERATION_H__ +#define BOTAN_XMSS_WOTS_VERIFICATION_OPERATION_H__ + +#include <cstddef> +#include <iterator> +#include <botan/types.h> +#include <botan/pk_ops.h> +#include <botan/internal/xmss_wots_addressed_publickey.h> +#include <botan/internal/xmss_wots_common_ops.h> + +namespace Botan { + +/** + * Provides signature verification capabilities for Winternitz One Time + * Signatures used in Extended Merkle Tree Signatures (XMSS). + * + * This operation is not intended for stand-alone use and thus not registered + * in the Botan algorithm registry. + **/ +class XMSS_WOTS_Verification_Operation + : public virtual PK_Ops::Verification, + public XMSS_WOTS_Common_Ops + { + public: + XMSS_WOTS_Verification_Operation( + const XMSS_WOTS_Addressed_PublicKey& public_key); + + virtual ~XMSS_WOTS_Verification_Operation() {} + + virtual bool is_valid_signature(const byte sig[], + size_t sig_len) override; + + void update(const byte msg[], size_t msg_len) override; + + private: + XMSS_WOTS_Addressed_PublicKey m_pub_key; + secure_vector<byte> m_msg_buf; + }; + +} + +#endif diff --git a/src/lib/rng/auto_rng/info.txt b/src/lib/rng/auto_rng/info.txt index b66aafb45..4dd51c2b0 100644 --- a/src/lib/rng/auto_rng/info.txt +++ b/src/lib/rng/auto_rng/info.txt @@ -1,4 +1,5 @@ define AUTO_SEEDING_RNG 20160821 +define AUTO_RNG 20161126 <requires> hmac_drbg diff --git a/src/lib/rng/rdrand_rng/rdrand_rng.cpp b/src/lib/rng/rdrand_rng/rdrand_rng.cpp index 1ee857c6c..d807bd81d 100644 --- a/src/lib/rng/rdrand_rng/rdrand_rng.cpp +++ b/src/lib/rng/rdrand_rng/rdrand_rng.cpp @@ -1,4 +1,4 @@ -/** +/* * RDRAND RNG * (C) 2016 Jack Lloyd * diff --git a/src/lib/rng/rdrand_rng/rdrand_rng.h b/src/lib/rng/rdrand_rng/rdrand_rng.h index 94363b89c..73616637e 100644 --- a/src/lib/rng/rdrand_rng/rdrand_rng.h +++ b/src/lib/rng/rdrand_rng/rdrand_rng.h @@ -1,4 +1,4 @@ -/** +/* * RDRAND RNG * (C) 2016 Jack Lloyd * diff --git a/src/lib/rng/rng.h b/src/lib/rng/rng.h index 98ac4982f..acd131b18 100644 --- a/src/lib/rng/rng.h +++ b/src/lib/rng/rng.h @@ -193,7 +193,7 @@ class BOTAN_DLL Null_RNG final : public RandomNumberGenerator void randomize(byte[], size_t) override { - throw Exception("Null_RNG called"); + throw PRNG_Unseeded("Null_RNG called"); } void add_entropy(const byte[], size_t) override {} diff --git a/src/lib/rng/system_rng/system_rng.cpp b/src/lib/rng/system_rng/system_rng.cpp index 1ea749327..12b087661 100644 --- a/src/lib/rng/system_rng/system_rng.cpp +++ b/src/lib/rng/system_rng/system_rng.cpp @@ -10,9 +10,8 @@ #if defined(BOTAN_TARGET_OS_HAS_CRYPTGENRANDOM) #include <windows.h> +#define NOMINMAX 1 #include <wincrypt.h> -#undef min -#undef max #else @@ -136,8 +135,11 @@ void System_RNG_Impl::add_entropy(const uint8_t input[], size_t len) * by the OS or sysadmin that additional entropy is not wanted * in the system pool, so we accept that and return here, * since there is no corrective action possible. + * + * In Linux EBADF or EPERM is returned if m_fd is not opened for + * writing. */ - if(errno == EPERM) + if(errno == EPERM || errno == EBADF) return; // maybe just ignore any failure here and return? diff --git a/src/lib/stream/chacha/chacha_sse2/chacha_sse2.cpp b/src/lib/stream/chacha/chacha_sse2/chacha_sse2.cpp index bf01cc879..f28257fb8 100644 --- a/src/lib/stream/chacha/chacha_sse2/chacha_sse2.cpp +++ b/src/lib/stream/chacha/chacha_sse2/chacha_sse2.cpp @@ -37,20 +37,17 @@ void ChaCha::chacha_sse2_x4(byte output[64*4], u32bit input[16], size_t rounds) __m128i r1_0 = input0; __m128i r1_1 = input1; __m128i r1_2 = input2; - __m128i r1_3 = input3; - r1_3 = _mm_add_epi64(r0_3, _mm_set_epi32(0, 0, 0, 1)); + __m128i r1_3 = _mm_add_epi64(r0_3, _mm_set_epi32(0, 0, 0, 1)); __m128i r2_0 = input0; __m128i r2_1 = input1; __m128i r2_2 = input2; - __m128i r2_3 = input3; - r2_3 = _mm_add_epi64(r0_3, _mm_set_epi32(0, 0, 0, 2)); + __m128i r2_3 = _mm_add_epi64(r0_3, _mm_set_epi32(0, 0, 0, 2)); __m128i r3_0 = input0; __m128i r3_1 = input1; __m128i r3_2 = input2; - __m128i r3_3 = input3; - r3_3 = _mm_add_epi64(r0_3, _mm_set_epi32(0, 0, 0, 3)); + __m128i r3_3 = _mm_add_epi64(r0_3, _mm_set_epi32(0, 0, 0, 3)); for(size_t r = 0; r != rounds / 2; ++r) { diff --git a/src/lib/tls/credentials_manager.cpp b/src/lib/tls/credentials_manager.cpp index 650d922ce..a42fb5789 100644 --- a/src/lib/tls/credentials_manager.cpp +++ b/src/lib/tls/credentials_manager.cpp @@ -93,53 +93,4 @@ Credentials_Manager::trusted_certificate_authorities( return std::vector<Certificate_Store*>(); } -namespace { - -bool cert_in_some_store(const std::vector<Certificate_Store*>& trusted_CAs, - const X509_Certificate& trust_root) - { - for(auto CAs : trusted_CAs) - if(CAs->certificate_known(trust_root)) - return true; - return false; - } - -Usage_Type choose_leaf_usage(const std::string& ctx) - { - // These are reversed because ctx is denoting the current perspective - if(ctx == "tls-client") - return Usage_Type::TLS_SERVER_AUTH; - else if(ctx == "tls-server") - return Usage_Type::TLS_CLIENT_AUTH; - else - return Usage_Type::UNSPECIFIED; - } - -} - -void Credentials_Manager::verify_certificate_chain( - const std::string& type, - const std::string& purported_hostname, - const std::vector<X509_Certificate>& cert_chain) - { - if(cert_chain.empty()) - throw Invalid_Argument("Certificate chain was empty"); - - auto trusted_CAs = trusted_certificate_authorities(type, purported_hostname); - - Path_Validation_Restrictions restrictions; - - Path_Validation_Result result = x509_path_validate(cert_chain, - restrictions, - trusted_CAs, - purported_hostname, - choose_leaf_usage(type)); - - if(!result.successful_validation()) - throw Exception("Certificate validation failure: " + result.result_string()); - - if(!cert_in_some_store(trusted_CAs, result.trust_root())) - throw Exception("Certificate chain roots in unknown/untrusted CA"); - } - } diff --git a/src/lib/tls/credentials_manager.h b/src/lib/tls/credentials_manager.h index 96e840d13..0e2fe0dea 100644 --- a/src/lib/tls/credentials_manager.h +++ b/src/lib/tls/credentials_manager.h @@ -44,25 +44,6 @@ class BOTAN_DLL Credentials_Manager const std::string& context); /** - * Check the certificate chain is valid up to a trusted root, and - * optionally (if hostname != "") that the hostname given is - * consistent with the leaf certificate. - * - * This function should throw an exception derived from - * std::exception with an informative what() result if the - * certificate chain cannot be verified. - - * @param type specifies the type of operation occurring - * @param hostname specifies the purported hostname - * @param cert_chain specifies a certificate chain leading to a - * trusted root CA certificate. - */ - virtual void verify_certificate_chain( - const std::string& type, - const std::string& hostname, - const std::vector<X509_Certificate>& cert_chain); - - /** * Return a cert chain we can use, ordered from leaf to root, * or else an empty vector. * diff --git a/src/lib/tls/msg_cert_status.cpp b/src/lib/tls/msg_cert_status.cpp new file mode 100644 index 000000000..f28fe10d2 --- /dev/null +++ b/src/lib/tls/msg_cert_status.cpp @@ -0,0 +1,65 @@ +/* +* Certificate Status +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/internal/tls_messages.h> +#include <botan/internal/tls_reader.h> +#include <botan/internal/tls_extensions.h> +#include <botan/internal/tls_handshake_io.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> + +namespace Botan { + +namespace TLS { + +Certificate_Status::Certificate_Status(const std::vector<byte>& buf) + { + if(buf.size() < 5) + throw Decoding_Error("Invalid Certificate_Status message: too small"); + + if(buf[0] != 1) + throw Decoding_Error("Unexpected Certificate_Status message: unexpected message type"); + + size_t len = make_u32bit(0, buf[1], buf[2], buf[3]); + + // Verify the redundant length field... + if(buf.size() != len + 4) + throw Decoding_Error("Invalid Certificate_Status: invalid length field"); + + m_response = std::make_shared<OCSP::Response>(buf.data() + 4, buf.size() - 4); + } + +Certificate_Status::Certificate_Status(Handshake_IO& io, + Handshake_Hash& hash, + std::shared_ptr<const OCSP::Response> ocsp) : + m_response(ocsp) + { + hash.update(io.send(*this)); + } + +std::vector<byte> Certificate_Status::serialize() const + { + BOTAN_ASSERT_NONNULL(m_response); + const std::vector<byte>& m_resp_bits = m_response->raw_bits(); + + if(m_resp_bits.size() > 0xFFFFFF) // unlikely + throw Encoding_Error("OCSP response too long to encode in TLS"); + + const uint32_t m_resp_bits_len = static_cast<u32bit>(m_resp_bits.size()); + + std::vector<byte> buf; + buf.push_back(1); // type OCSP + for(size_t i = 1; i < 4; ++i) + buf[i] = get_byte(i, m_resp_bits_len); + + buf += m_resp_bits; + return buf; + } + +} + +} diff --git a/src/lib/tls/msg_client_hello.cpp b/src/lib/tls/msg_client_hello.cpp index 2a42e1144..870307217 100644 --- a/src/lib/tls/msg_client_hello.cpp +++ b/src/lib/tls/msg_client_hello.cpp @@ -76,8 +76,7 @@ Client_Hello::Client_Hello(Handshake_IO& io, const std::vector<std::string>& next_protocols) : m_version(client_settings.protocol_version()), m_random(make_hello_random(rng, policy)), - m_suites(policy.ciphersuite_list(m_version, - client_settings.srp_identifier() != "")), + m_suites(policy.ciphersuite_list(m_version, !client_settings.srp_identifier().empty())), m_comp_methods(policy.compression()) { BOTAN_ASSERT(policy.acceptable_protocol_version(client_settings.protocol_version()), @@ -89,12 +88,16 @@ Client_Hello::Client_Hello(Handshake_IO& io, */ m_extensions.add(new Extended_Master_Secret); m_extensions.add(new Session_Ticket()); + m_extensions.add(new Certificate_Status_Request); + if(policy.negotiate_encrypt_then_mac()) m_extensions.add(new Encrypt_then_MAC); m_extensions.add(new Renegotiation_Extension(reneg_info)); m_extensions.add(new Server_Name_Indicator(client_settings.hostname())); + m_extensions.add(new Certificate_Status_Request({}, {})); + if(reneg_info.empty() && !next_protocols.empty()) m_extensions.add(new Application_Layer_Protocol_Notification(next_protocols)); @@ -159,6 +162,7 @@ Client_Hello::Client_Hello(Handshake_IO& io, attempt and upgrade us to a new session with the EMS protection. */ m_extensions.add(new Extended_Master_Secret); + m_extensions.add(new Certificate_Status_Request); m_extensions.add(new Renegotiation_Extension(reneg_info)); m_extensions.add(new Server_Name_Indicator(session.server_info().hostname())); diff --git a/src/lib/tls/msg_server_hello.cpp b/src/lib/tls/msg_server_hello.cpp index 3e8a8dda9..37e521403 100644 --- a/src/lib/tls/msg_server_hello.cpp +++ b/src/lib/tls/msg_server_hello.cpp @@ -35,12 +35,15 @@ Server_Hello::Server_Hello(Handshake_IO& io, if(client_hello.supports_extended_master_secret()) m_extensions.add(new Extended_Master_Secret); + // Sending the extension back does not commit us to sending a stapled response + if(client_hello.supports_cert_status_message()) + m_extensions.add(new Certificate_Status_Request); + Ciphersuite c = Ciphersuite::by_id(m_ciphersuite); - if(client_hello.supports_encrypt_then_mac() && policy.negotiate_encrypt_then_mac()) + if(c.cbc_ciphersuite() && client_hello.supports_encrypt_then_mac() && policy.negotiate_encrypt_then_mac()) { - if(c.cbc_ciphersuite()) - m_extensions.add(new Encrypt_then_MAC); + m_extensions.add(new Encrypt_then_MAC); } if(c.ecc_ciphersuite()) @@ -100,6 +103,10 @@ Server_Hello::Server_Hello(Handshake_IO& io, if(client_hello.supports_extended_master_secret()) m_extensions.add(new Extended_Master_Secret); + // Sending the extension back does not commit us to sending a stapled response + if(client_hello.supports_cert_status_message()) + m_extensions.add(new Certificate_Status_Request); + if(client_hello.supports_encrypt_then_mac() && policy.negotiate_encrypt_then_mac()) { Ciphersuite c = resumed_session.ciphersuite(); @@ -107,6 +114,11 @@ Server_Hello::Server_Hello(Handshake_IO& io, m_extensions.add(new Encrypt_then_MAC); } + if(client_hello.supports_cert_status_message()) + { + m_extensions.add(new Certificate_Status_Request); + } + if(resumed_session.ciphersuite().ecc_ciphersuite()) { m_extensions.add(new Supported_Point_Formats(policy.use_ecc_point_compression())); diff --git a/src/lib/tls/tls_callbacks.cpp b/src/lib/tls/tls_callbacks.cpp new file mode 100644 index 000000000..f25f392b3 --- /dev/null +++ b/src/lib/tls/tls_callbacks.cpp @@ -0,0 +1,56 @@ +/* +* TLS Callbacks +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/tls_callbacks.h> +#include <botan/tls_policy.h> +#include <botan/x509path.h> +#include <botan/ocsp.h> +#include <botan/certstor.h> + +namespace Botan { + +TLS::Callbacks::~Callbacks() {} + +void TLS::Callbacks::tls_inspect_handshake_msg(const Handshake_Message&) + { + // default is no op + } + +std::string TLS::Callbacks::tls_server_choose_app_protocol(const std::vector<std::string>&) + { + return ""; + } + +void TLS::Callbacks::tls_verify_cert_chain( + const std::vector<X509_Certificate>& cert_chain, + const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_responses, + const std::vector<Certificate_Store*>& trusted_roots, + Usage_Type usage, + const std::string& hostname, + const TLS::Policy& policy) + { + if(cert_chain.empty()) + throw Invalid_Argument("Certificate chain was empty"); + + Path_Validation_Restrictions restrictions(policy.require_cert_revocation_info(), + policy.minimum_signature_strength()); + + Path_Validation_Result result = + x509_path_validate(cert_chain, + restrictions, + trusted_roots, + (usage == Usage_Type::TLS_SERVER_AUTH ? hostname : ""), + usage, + std::chrono::system_clock::now(), + tls_verify_cert_chain_ocsp_timeout(), + ocsp_responses); + + if(!result.successful_validation()) + throw Exception("Certificate validation failure: " + result.result_string()); + } + +} diff --git a/src/lib/tls/tls_callbacks.h b/src/lib/tls/tls_callbacks.h index f81071a05..89e4aaa5d 100644 --- a/src/lib/tls/tls_callbacks.h +++ b/src/lib/tls/tls_callbacks.h @@ -11,11 +11,22 @@ #include <botan/tls_session.h> #include <botan/tls_alert.h> + namespace Botan { +class Certificate_Store; +class X509_Certificate; + +namespace OCSP { + +class Response; + +} + namespace TLS { class Handshake_Message; +class Policy; /** * Encapsulates the callbacks that a TLS channel will make which are due to @@ -53,7 +64,7 @@ class BOTAN_DLL Callbacks virtual void tls_record_received(u64bit seq_no, const uint8_t data[], size_t size) = 0; /** - * Mandary callback: alert received + * Mandatory callback: alert received * Called when an alert is received from the peer * If fatal, the connection is closing. If not fatal, the connection may * still be closing (depending on the error and the peer). @@ -81,6 +92,53 @@ class BOTAN_DLL Callbacks virtual void tls_session_activated() {} /** + * Optional callback with default impl: verify cert chain + * + * Default implementation performs a standard PKIX validation + * and initiates network OCSP request for end-entity cert. + * Override to provide different behavior. + * + * Check the certificate chain is valid up to a trusted root, and + * optionally (if hostname != "") that the hostname given is + * consistent with the leaf certificate. + * + * This function should throw an exception derived from + * std::exception with an informative what() result if the + * certificate chain cannot be verified. + * + * @param cert_chain specifies a certificate chain leading to a + * trusted root CA certificate. + * @param ocsp_responses the server may have provided some + * @param trusted_roots the list of trusted certificates + * @param usage what this cert chain is being used for + * Usage_Type::TLS_SERVER_AUTH for server chains, + * Usage_Type::TLS_CLIENT_AUTH for client chains, + * Usage_Type::UNSPECIFIED for other uses + * @param hostname when authenticating a server, this is the hostname + * the client requested (eg via SNI). When authenticating a client, + * this is the server name the client is authenticating *to*. + * Empty in other cases or if no hostname was used. + * @param policy the TLS policy associated with the session being authenticated + * using the certificate chain + */ + virtual void tls_verify_cert_chain( + const std::vector<X509_Certificate>& cert_chain, + const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_responses, + const std::vector<Certificate_Store*>& trusted_roots, + Usage_Type usage, + const std::string& hostname, + const TLS::Policy& policy); + + /** + * Called by default `tls_verify_cert_chain` to get the timeout to use for OCSP + * requests. Return 0 to disable online OCSP checks. + */ + virtual std::chrono::milliseconds tls_verify_cert_chain_ocsp_timeout() const + { + return std::chrono::milliseconds(0); + } + + /** * Optional callback: inspect handshake message * Throw an exception to abort the handshake. * Default simply ignores the message. diff --git a/src/lib/tls/tls_channel.cpp b/src/lib/tls/tls_channel.cpp index 95b151ad2..c8fe407e2 100644 --- a/src/lib/tls/tls_channel.cpp +++ b/src/lib/tls/tls_channel.cpp @@ -19,18 +19,6 @@ namespace Botan { namespace TLS { -Callbacks::~Callbacks() {} - -void Callbacks::tls_inspect_handshake_msg(const Handshake_Message&) - { - // default is no op - } - -std::string Callbacks::tls_server_choose_app_protocol(const std::vector<std::string>&) - { - return ""; - } - size_t TLS::Channel::IO_BUF_DEFAULT_SIZE = 10*1024; Channel::Channel(Callbacks& callbacks, diff --git a/src/lib/tls/tls_channel.h b/src/lib/tls/tls_channel.h index 2f4793211..110269e80 100644 --- a/src/lib/tls/tls_channel.h +++ b/src/lib/tls/tls_channel.h @@ -71,8 +71,9 @@ class BOTAN_DLL Channel /** * DEPRECATED. This constructor is only provided for backward * compatibility and should not be used in new implementations. + * (Not marked deprecated since it is only called internally, by + * other deprecated constructors) */ - BOTAN_DEPRECATED("Use TLS::Channel(TLS::Callbacks ...)") Channel(output_fn out, data_cb app_data_cb, alert_cb alert_cb, diff --git a/src/lib/tls/tls_ciphersuite.cpp b/src/lib/tls/tls_ciphersuite.cpp index 3c29c3c2b..08ef8e812 100644 --- a/src/lib/tls/tls_ciphersuite.cpp +++ b/src/lib/tls/tls_ciphersuite.cpp @@ -37,9 +37,7 @@ bool Ciphersuite::ecc_ciphersuite() const bool Ciphersuite::cbc_ciphersuite() const { - return (cipher_algo() == "3DES" || cipher_algo() == "SEED" || - cipher_algo() == "AES-128" || cipher_algo() == "AES-256" || - cipher_algo() == "Camellia-128" || cipher_algo() == "Camellia-256"); + return (mac_algo() != "AEAD"); } Ciphersuite Ciphersuite::by_id(u16bit suite) @@ -47,7 +45,7 @@ Ciphersuite Ciphersuite::by_id(u16bit suite) const std::vector<Ciphersuite>& all_suites = all_known_ciphersuites(); auto s = std::lower_bound(all_suites.begin(), all_suites.end(), suite); - if(s->ciphersuite_code() == suite) + if(s != all_suites.end() && s->ciphersuite_code() == suite) { return *s; } diff --git a/src/lib/tls/tls_client.cpp b/src/lib/tls/tls_client.cpp index 183886c66..37dd37812 100644 --- a/src/lib/tls/tls_client.cpp +++ b/src/lib/tls/tls_client.cpp @@ -13,6 +13,8 @@ #include <iterator> #include <sstream> +#include <botan/hex.h> + namespace Botan { namespace TLS { @@ -26,7 +28,7 @@ class Client_Handshake_State : public Handshake_State Client_Handshake_State(Handshake_IO* io, Callbacks& cb) : Handshake_State(io, cb) {} - const Public_Key& get_server_public_Key() const + const Public_Key& get_server_public_key() const { BOTAN_ASSERT(server_public_key, "Server sent us a certificate"); return *server_public_key.get(); @@ -370,16 +372,6 @@ void Client::process_handshake_msg(const Handshake_State* active_state, } else if(type == CERTIFICATE) { - if(state.ciphersuite().kex_algo() != "RSA") - { - state.set_expected_next(SERVER_KEX); - } - else - { - state.set_expected_next(CERTIFICATE_REQUEST); // optional - state.set_expected_next(SERVER_HELLO_DONE); - } - state.server_certs(new Certificate(contents, policy())); const std::vector<X509_Certificate>& server_certs = @@ -389,14 +381,10 @@ void Client::process_handshake_msg(const Handshake_State* active_state, throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Client: No certificates sent by server"); - try - { - m_creds.verify_certificate_chain("tls-client", m_info.hostname(), server_certs); - } - catch(std::exception& e) - { - throw TLS_Exception(Alert::BAD_CERTIFICATE, e.what()); - } + /* + Certificate verification happens after we receive the server hello done, + in case an OCSP response was also available + */ std::unique_ptr<Public_Key> peer_key(server_certs[0].subject_public_key()); @@ -405,6 +393,35 @@ void Client::process_handshake_msg(const Handshake_State* active_state, "Certificate key type did not match ciphersuite"); state.server_public_key.reset(peer_key.release()); + + if(state.ciphersuite().kex_algo() != "RSA") + { + state.set_expected_next(SERVER_KEX); + } + else + { + state.set_expected_next(CERTIFICATE_REQUEST); // optional + state.set_expected_next(SERVER_HELLO_DONE); + } + + if(state.server_hello()->supports_certificate_status_message()) + { + state.set_expected_next(CERTIFICATE_STATUS); // optional + } + } + else if(type == CERTIFICATE_STATUS) + { + state.server_cert_status(new Certificate_Status(contents)); + + if(state.ciphersuite().kex_algo() != "RSA") + { + state.set_expected_next(SERVER_KEX); + } + else + { + state.set_expected_next(CERTIFICATE_REQUEST); // optional + state.set_expected_next(SERVER_HELLO_DONE); + } } else if(type == SERVER_KEX) { @@ -420,7 +437,7 @@ void Client::process_handshake_msg(const Handshake_State* active_state, if(state.ciphersuite().sig_algo() != "") { - const Public_Key& server_key = state.get_server_public_Key(); + const Public_Key& server_key = state.get_server_public_key(); if(!state.server_kex()->verify(server_key, state, policy())) { @@ -438,6 +455,29 @@ void Client::process_handshake_msg(const Handshake_State* active_state, { state.server_hello_done(new Server_Hello_Done(contents)); + if(state.server_certs() != nullptr) + { + try + { + auto trusted_CAs = m_creds.trusted_certificate_authorities("tls-client", m_info.hostname()); + + std::vector<std::shared_ptr<const OCSP::Response>> ocsp; + if(state.server_cert_status() != nullptr) + ocsp.push_back(state.server_cert_status()->response()); + + callbacks().tls_verify_cert_chain(state.server_certs()->cert_chain(), + ocsp, + trusted_CAs, + Usage_Type::TLS_SERVER_AUTH, + m_info.hostname(), + policy()); + } + catch(std::exception& e) + { + throw TLS_Exception(Alert::BAD_CERTIFICATE, e.what()); + } + } + if(state.received_handshake_msg(CERTIFICATE_REQUEST)) { const auto& types = state.cert_req()->acceptable_cert_types(); diff --git a/src/lib/tls/tls_extensions.cpp b/src/lib/tls/tls_extensions.cpp index 712527fc4..731e149b2 100644 --- a/src/lib/tls/tls_extensions.cpp +++ b/src/lib/tls/tls_extensions.cpp @@ -16,9 +16,7 @@ namespace TLS { namespace { -Extension* make_extension(TLS_Data_Reader& reader, - u16bit code, - u16bit size) +Extension* make_extension(TLS_Data_Reader& reader, u16bit code, u16bit size) { switch(code) { @@ -33,6 +31,9 @@ Extension* make_extension(TLS_Data_Reader& reader, case TLSEXT_USABLE_ELLIPTIC_CURVES: return new Supported_Elliptic_Curves(reader, size); + case TLSEXT_CERT_STATUS_REQUEST: + return new Certificate_Status_Request(reader, size); + case TLSEXT_EC_POINT_FORMATS: return new Supported_Point_Formats(reader, size); @@ -56,10 +57,9 @@ Extension* make_extension(TLS_Data_Reader& reader, case TLSEXT_SESSION_TICKET: return new Session_Ticket(reader, size); - - default: - return nullptr; // not known } + + return nullptr; // not known } } @@ -606,7 +606,7 @@ std::vector<byte> Extended_Master_Secret::serialize() const } Encrypt_then_MAC::Encrypt_then_MAC(TLS_Data_Reader&, - u16bit extension_size) + u16bit extension_size) { if(extension_size != 0) throw Decoding_Error("Invalid encrypt_then_mac extension"); @@ -617,6 +617,63 @@ std::vector<byte> Encrypt_then_MAC::serialize() const return std::vector<byte>(); } +std::vector<byte> Certificate_Status_Request::serialize() const + { + std::vector<byte> buf; + + if(m_server_side) + return buf; // server reply is empty + + /* + opaque ResponderID<1..2^16-1>; + opaque Extensions<0..2^16-1>; + + CertificateStatusType status_type = ocsp(1) + ResponderID responder_id_list<0..2^16-1> + Extensions request_extensions; + */ + + buf.push_back(1); // CertificateStatusType ocsp + + buf.push_back(0); + buf.push_back(0); + buf.push_back(0); + buf.push_back(0); + + return buf; + } + +Certificate_Status_Request::Certificate_Status_Request(TLS_Data_Reader& reader, + u16bit extension_size) + { + if(extension_size > 0) + { + const byte type = reader.get_byte(); + if(type == 1) + { + reader.discard_next(extension_size - 1); // fixme + } + else + { + reader.discard_next(extension_size - 1); + } + } + } + +Certificate_Status_Request::Certificate_Status_Request(const std::vector<X509_DN>& ocsp_responder_ids, + const std::vector<std::vector<byte>>& ocsp_key_ids) : + m_ocsp_names(ocsp_responder_ids), + m_ocsp_keys(ocsp_key_ids), + m_server_side(false) + { + + } + +Certificate_Status_Request::Certificate_Status_Request() : m_server_side(true) + { + + } + } } diff --git a/src/lib/tls/tls_extensions.h b/src/lib/tls/tls_extensions.h index 119170797..f766a3b1b 100644 --- a/src/lib/tls/tls_extensions.h +++ b/src/lib/tls/tls_extensions.h @@ -12,6 +12,7 @@ #include <botan/secmem.h> #include <botan/tls_magic.h> +#include <botan/ocsp.h> #include <vector> #include <string> #include <map> @@ -25,10 +26,7 @@ class TLS_Data_Reader; enum Handshake_Extension_Type { TLSEXT_SERVER_NAME_INDICATION = 0, - // 1 is maximum fragment length - TLSEXT_CLIENT_CERT_URL = 2, - TLSEXT_TRUSTED_CA_KEYS = 3, - TLSEXT_TRUNCATED_HMAC = 4, + TLSEXT_CERT_STATUS_REQUEST = 5, TLSEXT_CERTIFICATE_TYPES = 9, TLSEXT_USABLE_ELLIPTIC_CURVES = 10, @@ -397,6 +395,36 @@ class Encrypt_then_MAC final : public Extension }; /** +* Certificate Status Request (RFC 6066) +*/ +class Certificate_Status_Request final : public Extension + { + public: + static Handshake_Extension_Type static_type() + { return TLSEXT_CERT_STATUS_REQUEST; } + + Handshake_Extension_Type type() const override { return static_type(); } + + std::vector<byte> serialize() const override; + + bool empty() const override { return false; } + + // Server generated version: empty + Certificate_Status_Request(); + + // Client version, both lists can be empty + Certificate_Status_Request(const std::vector<X509_DN>& ocsp_responder_ids, + const std::vector<std::vector<byte>>& ocsp_key_ids); + + Certificate_Status_Request(TLS_Data_Reader& reader, u16bit extension_size); + private: + std::vector<X509_DN> m_ocsp_names; + std::vector<std::vector<byte>> m_ocsp_keys; + std::vector<byte> m_extension_bytes; + bool m_server_side; + }; + +/** * Represents a block of extensions in a hello message */ class BOTAN_DLL Extensions diff --git a/src/lib/tls/tls_handshake_hash.cpp b/src/lib/tls/tls_handshake_hash.cpp index 540f1de14..7bac87bc8 100644 --- a/src/lib/tls/tls_handshake_hash.cpp +++ b/src/lib/tls/tls_handshake_hash.cpp @@ -19,16 +19,12 @@ namespace TLS { secure_vector<byte> Handshake_Hash::final(Protocol_Version version, const std::string& mac_algo) const { - auto choose_hash = [=]() { - if(!version.supports_ciphersuite_specific_prf()) - return "Parallel(MD5,SHA-160)"; + std::string hash_algo = mac_algo; + if(!version.supports_ciphersuite_specific_prf()) + hash_algo = "Parallel(MD5,SHA-160)"; + else if(mac_algo == "MD5" || mac_algo == "SHA-1") + hash_algo = "SHA-256"; - if(mac_algo == "MD5" || mac_algo == "SHA-1") - return "SHA-256"; - return mac_algo.c_str(); - }; - - const std::string hash_algo = choose_hash(); std::unique_ptr<HashFunction> hash(HashFunction::create_or_throw(hash_algo)); hash->update(m_data); return hash->final(); diff --git a/src/lib/tls/tls_handshake_state.cpp b/src/lib/tls/tls_handshake_state.cpp index 71cacdabd..039d5b326 100644 --- a/src/lib/tls/tls_handshake_state.cpp +++ b/src/lib/tls/tls_handshake_state.cpp @@ -218,6 +218,12 @@ void Handshake_State::server_certs(Certificate* server_certs) note_message(*m_server_certs); } +void Handshake_State::server_cert_status(Certificate_Status* server_cert_status) + { + m_server_cert_status.reset(server_cert_status); + note_message(*m_server_cert_status); + } + void Handshake_State::server_kex(Server_Key_Exchange* server_kex) { m_server_kex.reset(server_kex); diff --git a/src/lib/tls/tls_handshake_state.h b/src/lib/tls/tls_handshake_state.h index bdec10d14..bdfc0d5d5 100644 --- a/src/lib/tls/tls_handshake_state.h +++ b/src/lib/tls/tls_handshake_state.h @@ -31,6 +31,7 @@ class Hello_Verify_Request; class Client_Hello; class Server_Hello; class Certificate; +class Certificate_Status; class Server_Key_Exchange; class Certificate_Req; class Server_Hello_Done; @@ -105,6 +106,7 @@ class Handshake_State void client_hello(Client_Hello* client_hello); void server_hello(Server_Hello* server_hello); void server_certs(Certificate* server_certs); + void server_cert_status(Certificate_Status* server_cert_status); void server_kex(Server_Key_Exchange* server_kex); void cert_req(Certificate_Req* cert_req); void server_hello_done(Server_Hello_Done* server_hello_done); @@ -142,6 +144,9 @@ class Handshake_State const Certificate_Verify* client_verify() const { return m_client_verify.get(); } + const Certificate_Status* server_cert_status() const + { return m_server_cert_status.get(); } + const New_Session_Ticket* new_session_ticket() const { return m_new_session_ticket.get(); } @@ -180,6 +185,7 @@ class Handshake_State std::unique_ptr<Client_Hello> m_client_hello; std::unique_ptr<Server_Hello> m_server_hello; std::unique_ptr<Certificate> m_server_certs; + std::unique_ptr<Certificate_Status> m_server_cert_status; std::unique_ptr<Server_Key_Exchange> m_server_kex; std::unique_ptr<Certificate_Req> m_cert_req; std::unique_ptr<Server_Hello_Done> m_server_hello_done; diff --git a/src/lib/tls/tls_messages.h b/src/lib/tls/tls_messages.h index 5e6962329..82fa22320 100644 --- a/src/lib/tls/tls_messages.h +++ b/src/lib/tls/tls_messages.h @@ -184,6 +184,11 @@ class BOTAN_DLL Client_Hello final : public Handshake_Message return m_extensions.has<Extended_Master_Secret>(); } + bool supports_cert_status_message() const + { + return m_extensions.has<Certificate_Status_Request>(); + } + bool supports_encrypt_then_mac() const { return m_extensions.has<Encrypt_then_MAC>(); @@ -313,6 +318,11 @@ class BOTAN_DLL Server_Hello final : public Handshake_Message return m_extensions.has<Encrypt_then_MAC>(); } + bool supports_certificate_status_message() const + { + return m_extensions.has<Certificate_Status_Request>(); + } + bool supports_session_ticket() const { return m_extensions.has<Session_Ticket>(); @@ -439,6 +449,27 @@ class Certificate final : public Handshake_Message }; /** +* Certificate Status (RFC 6066) +*/ +class Certificate_Status final : public Handshake_Message + { + public: + Handshake_Type type() const override { return CERTIFICATE_STATUS; } + + std::shared_ptr<const OCSP::Response> response() const { return m_response; } + + Certificate_Status(const std::vector<byte>& buf); + + Certificate_Status(Handshake_IO& io, + Handshake_Hash& hash, + std::shared_ptr<const OCSP::Response> response); + + private: + std::vector<byte> serialize() const override; + std::shared_ptr<const OCSP::Response> m_response; + }; + +/** * Certificate Request Message */ class Certificate_Req final : public Handshake_Message diff --git a/src/lib/tls/tls_policy.cpp b/src/lib/tls/tls_policy.cpp index 49a8ad1fc..84ba5e4bf 100644 --- a/src/lib/tls/tls_policy.cpp +++ b/src/lib/tls/tls_policy.cpp @@ -156,6 +156,16 @@ size_t Policy::minimum_ecdh_group_size() const return 255; } +size_t Policy::minimum_signature_strength() const + { + return 110; + } + +bool Policy::require_cert_revocation_info() const + { + return true; + } + size_t Policy::minimum_rsa_bits() const { /* Default assumption is all end-entity certificates should @@ -466,6 +476,14 @@ void Policy::print(std::ostream& o) const o << "minimum_dh_group_size = " << minimum_dh_group_size() << '\n'; o << "minimum_ecdh_group_size = " << minimum_ecdh_group_size() << '\n'; o << "minimum_rsa_bits = " << minimum_rsa_bits() << '\n'; + o << "minimum_signature_strength = " << minimum_signature_strength() << '\n'; + } + +std::string Policy::to_string() const + { + std::ostringstream oss; + this->print(oss); + return oss.str(); } std::vector<std::string> Strict_Policy::allowed_ciphers() const @@ -485,7 +503,7 @@ std::vector<std::string> Strict_Policy::allowed_macs() const std::vector<std::string> Strict_Policy::allowed_key_exchange_methods() const { - return { "ECDH" }; + return { "CECPQ1", "ECDH" }; } bool Strict_Policy::allow_tls10() const { return false; } diff --git a/src/lib/tls/tls_policy.h b/src/lib/tls/tls_policy.h index efef7e1f7..b577eb265 100644 --- a/src/lib/tls/tls_policy.h +++ b/src/lib/tls/tls_policy.h @@ -57,6 +57,22 @@ class BOTAN_DLL Policy */ virtual std::vector<std::string> allowed_signature_methods() const; + /** + * The minimum signature strength we will accept + * Returning 80 allows RSA 1024 and SHA-1. Values larger than 80 disable SHA-1 support. + * Returning 110 allows RSA 2048. + * Return 128 to force ECC (P-256) or large (~3000 bit) RSA keys. + * Default is 110 + */ + virtual size_t minimum_signature_strength() const; + + /** + * Return if cert revocation info (CRL/OCSP) is required + * If true, validation will fail unless a valid CRL or OCSP response + * was examined. + */ + virtual bool require_cert_revocation_info() const; + bool allowed_signature_method(const std::string& sig_method) const; /** @@ -275,6 +291,12 @@ class BOTAN_DLL Policy */ virtual void print(std::ostream& o) const; + /** + * Convert this policy to a printable format. + * Same as calling `print` on a ostringstream and reading o.str() + */ + std::string to_string() const; + virtual ~Policy() {} }; @@ -301,7 +323,9 @@ class BOTAN_DLL NSA_Suite_B_128 : public Policy std::vector<std::string> allowed_ecc_curves() const override { return std::vector<std::string>({"secp256r1"}); } - + + size_t minimum_signature_strength() const override { return 128; } + bool allow_tls10() const override { return false; } bool allow_tls11() const override { return false; } bool allow_tls12() const override { return true; } @@ -419,7 +443,10 @@ class BOTAN_DLL Text_Policy : public Policy size_t minimum_rsa_bits() const override { return get_len("minimum_rsa_bits", Policy::minimum_rsa_bits()); } - + + size_t minimum_signature_strength() const override + { return get_len("minimum_signature_strength", Policy::minimum_signature_strength()); } + bool hide_unknown_users() const override { return get_bool("hide_unknown_users", Policy::hide_unknown_users()); } diff --git a/src/lib/tls/tls_server.cpp b/src/lib/tls/tls_server.cpp index 5e3b222f1..78c7704cc 100644 --- a/src/lib/tls/tls_server.cpp +++ b/src/lib/tls/tls_server.cpp @@ -523,7 +523,15 @@ void Server::process_certificate_verify_msg(Server_Handshake_State& pending_stat try { - m_creds.verify_certificate_chain ( "tls-server", "", client_certs ); + const std::string sni_hostname = pending_state.client_hello()->sni_hostname(); + auto trusted_CAs = m_creds.trusted_certificate_authorities("tls-server", sni_hostname); + + callbacks().tls_verify_cert_chain(client_certs, + {}, // ocsp + trusted_CAs, + Usage_Type::TLS_CLIENT_AUTH, + sni_hostname, + policy()); } catch ( std::exception& e ) { diff --git a/src/lib/utils/compiler.h b/src/lib/utils/compiler.h new file mode 100644 index 000000000..50441208b --- /dev/null +++ b/src/lib/utils/compiler.h @@ -0,0 +1,169 @@ +/* +* Define useful compiler-specific macros +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_UTIL_COMPILER_FLAGS_H__ +#define BOTAN_UTIL_COMPILER_FLAGS_H__ + +/* Should we use GCC-style inline assembler? */ +#if !defined(BOTAN_USE_GCC_INLINE_ASM) && defined(__GNUC__) + #define BOTAN_USE_GCC_INLINE_ASM 1 +#endif + +/* +* Define BOTAN_GCC_VERSION +*/ +#ifdef __GNUC__ + #define BOTAN_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__ * 10 + __GNUC_PATCHLEVEL__) +#else + #define BOTAN_GCC_VERSION 0 +#endif + +/* +* Define BOTAN_CLANG_VERSION +*/ +#ifdef __clang__ + #define BOTAN_CLANG_VERSION (__clang_major__ * 10 + __clang_minor__) +#else + #define BOTAN_CLANG_VERSION 0 +#endif + +/* +* Define BOTAN_FUNC_ISA +*/ +#if defined(__GNUG__) || defined(__clang__) + #define BOTAN_FUNC_ISA(isa) __attribute__ ((target(isa))) +#else + #define BOTAN_FUNC_ISA(isa) +#endif + +/* +* Define BOTAN_WARN_UNUSED_RESULT +*/ +#if defined(__GNUG__) || defined(__clang__) + #define BOTAN_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result)) +#else + #define BOTAN_WARN_UNUSED_RESULT +#endif + +/* +* Define BOTAN_DEPRECATED +*/ +#if !defined(BOTAN_NO_DEPRECATED_WARNINGS) + + #if defined(__clang__) + #define BOTAN_DEPRECATED(msg) __attribute__ ((deprecated)) + + #elif defined(_MSC_VER) + #define BOTAN_DEPRECATED(msg) __declspec(deprecated(msg)) + + #elif defined(__GNUG__) + // msg supported since GCC 4.5, earliest we support is 4.8 + #define BOTAN_DEPRECATED(msg) __attribute__ ((deprecated(msg))) + #endif + +#endif + +#if !defined(BOTAN_DEPRECATED) + #define BOTAN_DEPRECATED(msg) +#endif + +/* +* Define BOTAN_NORETURN +*/ +#if !defined(BOTAN_NORETURN) + + #if defined (__clang__) || defined (__GNUG__) + #define BOTAN_NORETURN __attribute__ ((__noreturn__)) + + #elif defined (_MSC_VER) + #define BOTAN_NORETURN __declspec(noreturn) + + #else + #define BOTAN_NORETURN + #endif + +#endif + +/* +* Define BOTAN_CURRENT_FUNCTION +*/ +#if defined(_MSC_VER) + #define BOTAN_CURRENT_FUNCTION __FUNCTION__ +#else + #define BOTAN_CURRENT_FUNCTION __func__ +#endif + +/* +* Define BOTAN_NOEXCEPT (for MSVC 2013) +*/ +#if defined(_MSC_VER) && (_MSC_VER < 1900) + // noexcept is not supported in VS 2013 + #include <yvals.h> + #define BOTAN_NOEXCEPT _NOEXCEPT +#else + #define BOTAN_NOEXCEPT noexcept +#endif + +/* +* Define BOTAN_PARALLEL_FOR +*/ +#if !defined(BOTAN_PARALLEL_FOR) + +#if defined(BOTAN_TARGET_HAS_CILKPLUS) + #define BOTAN_PARALLEL_FOR _Cilk_for +#elif defined(BOTAN_TARGET_HAS_OPENMP) + #define BOTAN_PARALLEL_FOR _Pragma("omp parallel for") for +#else + #define BOTAN_PARALLEL_FOR for +#endif + +#endif + +/* +* Define BOTAN_PARALLEL_SIMD_FOR +*/ +#if !defined(BOTAN_PARALLEL_SIMD_FOR) + +#if defined(BOTAN_TARGET_HAS_CILKPLUS) + #define BOTAN_PARALLEL_SIMD_FOR _Pragma("simd") for +#elif defined(BOTAN_TARGET_HAS_OPENMP) + #define BOTAN_PARALLEL_SIMD_FOR _Pragma("omp simd") for +#elif defined(BOTAN_TARGET_COMPILER_IS_GCC) + #define BOTAN_PARALLEL_FOR _Pragma("GCC ivdep") for +#else + #define BOTAN_PARALLEL_SIMD_FOR for +#endif + +#endif + +/* +* Define BOTAN_PARALLEL_SPAWN +*/ +#if !defined(BOTAN_PARALLEL_SPAWN) + +#if defined(BOTAN_TARGET_HAS_CILKPLUS) + #define BOTAN_PARALLEL_SPAWN _Cilk_spawn +#else + #define BOTAN_PARALLEL_SPAWN +#endif + +#endif + +/* +* Define BOTAN_PARALLEL_SYNC +*/ +#if !defined(BOTAN_PARALLEL_SYNC) + +#if defined(BOTAN_TARGET_HAS_CILKPLUS) + #define BOTAN_PARALLEL_SYNC _Cilk_sync +#else + #define BOTAN_PARALLEL_SYNC BOTAN_FORCE_SEMICOLON +#endif + +#endif + +#endif diff --git a/src/lib/utils/dyn_load/dyn_load.cpp b/src/lib/utils/dyn_load/dyn_load.cpp index ce6b61a1d..1f33dc761 100644 --- a/src/lib/utils/dyn_load/dyn_load.cpp +++ b/src/lib/utils/dyn_load/dyn_load.cpp @@ -1,4 +1,4 @@ -/** +/* * Dynamically Loaded Object * (C) 2010 Jack Lloyd * @@ -12,6 +12,7 @@ #if defined(BOTAN_TARGET_OS_HAS_DLOPEN) #include <dlfcn.h> #elif defined(BOTAN_TARGET_OS_HAS_LOADLIBRARY) + #define NOMINMAX 1 #include <windows.h> #endif diff --git a/src/lib/utils/filesystem.cpp b/src/lib/utils/filesystem.cpp index c67668288..36e1f5446 100644 --- a/src/lib/utils/filesystem.cpp +++ b/src/lib/utils/filesystem.cpp @@ -118,6 +118,7 @@ std::vector<std::string> get_files_recursive(const std::string& dir) #elif defined(BOTAN_TARGET_OS_HAS_READDIR) files = impl_readdir(dir); #else + BOTAN_UNUSED(dir); throw No_Filesystem_Access(); #endif diff --git a/src/lib/utils/http_util/http_util.cpp b/src/lib/utils/http_util/http_util.cpp index 970b90238..c699b786f 100644 --- a/src/lib/utils/http_util/http_util.cpp +++ b/src/lib/utils/http_util/http_util.cpp @@ -26,6 +26,9 @@ #include <sys/socket.h> #include <netdb.h> #include <unistd.h> + #include <netinet/in.h> +#else + //#warning "No network support enabled in http_util" #endif namespace Botan { @@ -101,7 +104,7 @@ std::string http_transact(const std::string& hostname, ssize_t sent = ::write(fd, &message[sent_so_far], left); if(sent < 0) - throw HTTP_Error("HTTP server hung up on us"); + throw HTTP_Error("write to HTTP server failed, error '" + std::string(::strerror(errno)) + "'"); else sent_so_far += static_cast<size_t>(sent); } @@ -113,7 +116,7 @@ std::string http_transact(const std::string& hostname, ssize_t got = ::read(fd, buf.data(), buf.size()); if(got < 0) - throw HTTP_Error("HTTP server hung up on us"); + throw HTTP_Error("read from HTTP server failed, error '" + std::string(::strerror(errno)) + "'"); else if(got > 0) oss.write(buf.data(), static_cast<std::streamsize>(got)); else @@ -122,8 +125,7 @@ std::string http_transact(const std::string& hostname, return oss.str(); #else - throw HTTP_Error("Cannot connect to " + hostname + - ": network code disabled in build"); + throw HTTP_Error("Cannot connect to " + hostname + ": network code disabled in build"); #endif } @@ -167,9 +169,12 @@ Response http_sync(http_exch_fn http_transact, const std::vector<byte>& body, size_t allowable_redirects) { + if(url.empty()) + throw HTTP_Error("URL empty"); + const auto protocol_host_sep = url.find("://"); if(protocol_host_sep == std::string::npos) - throw HTTP_Error("Invalid URL " + url); + throw HTTP_Error("Invalid URL '" + url + "'"); const auto host_loc_sep = url.find('/', protocol_host_sep + 3); diff --git a/src/lib/utils/info.txt b/src/lib/utils/info.txt index 75a428a83..306e6e9ad 100644 --- a/src/lib/utils/info.txt +++ b/src/lib/utils/info.txt @@ -1,4 +1,4 @@ -define UTIL_FUNCTIONS 20150919 +define UTIL_FUNCTIONS 20161127 load_on always @@ -8,6 +8,7 @@ bswap.h calendar.h charset.h cpuid.h +compiler.h data_src.h database.h exceptn.h @@ -30,6 +31,7 @@ filesystem.h os_utils.h prefetch.h rounding.h +safeint.h semaphore.h stl_util.h </header:internal> diff --git a/src/lib/utils/loadstor.h b/src/lib/utils/loadstor.h index 9ae9fda0e..15ff6a708 100644 --- a/src/lib/utils/loadstor.h +++ b/src/lib/utils/loadstor.h @@ -324,10 +324,10 @@ inline void load_le(T out[], { if(count > 0) { -#if defined(BOTAN_TARGET_CPU_HAS_KNOWN_ENDIANNESS) +#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN) + std::memcpy(out, in, sizeof(T)*count); +#elif defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN) std::memcpy(out, in, sizeof(T)*count); - -#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN) const size_t blocks = count - (count % 4); const size_t left = count - blocks; @@ -336,8 +336,6 @@ inline void load_le(T out[], for(size_t i = 0; i != left; ++i) out[blocks+i] = reverse_bytes(out[blocks+i]); -#endif - #else for(size_t i = 0; i != count; ++i) out[i] = load_le<T>(in, i); @@ -416,10 +414,10 @@ inline void load_be(T out[], { if(count > 0) { -#if defined(BOTAN_TARGET_CPU_HAS_KNOWN_ENDIANNESS) +#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN) + std::memcpy(out, in, sizeof(T)*count); +#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN) std::memcpy(out, in, sizeof(T)*count); - -#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN) const size_t blocks = count - (count % 4); const size_t left = count - blocks; @@ -428,8 +426,6 @@ inline void load_be(T out[], for(size_t i = 0; i != left; ++i) out[blocks+i] = reverse_bytes(out[blocks+i]); -#endif - #else for(size_t i = 0; i != count; ++i) out[i] = load_be<T>(in, i); diff --git a/src/lib/utils/mem_ops.cpp b/src/lib/utils/mem_ops.cpp index 461b03d6b..a0cd3124f 100644 --- a/src/lib/utils/mem_ops.cpp +++ b/src/lib/utils/mem_ops.cpp @@ -8,6 +8,7 @@ #include <botan/mem_ops.h> #if defined(BOTAN_TARGET_OS_HAS_RTLSECUREZEROMEMORY) + #define NOMINMAX 1 #include <windows.h> #endif diff --git a/src/lib/utils/os_utils.cpp b/src/lib/utils/os_utils.cpp index f40426613..d072b2c2b 100644 --- a/src/lib/utils/os_utils.cpp +++ b/src/lib/utils/os_utils.cpp @@ -20,6 +20,7 @@ #endif #if defined(BOTAN_TARGET_OS_IS_WINDOWS) || defined(BOTAN_TARGET_OS_IS_MINGW) + #define NOMINMAX 1 #include <windows.h> #endif @@ -273,6 +274,7 @@ void* allocate_locked_pages(size_t length) return ptr; #else + BOTAN_UNUSED(length); return nullptr; /* not implemented */ #endif } diff --git a/src/lib/utils/os_utils.h b/src/lib/utils/os_utils.h index 590ed4ae7..c8cd599d0 100644 --- a/src/lib/utils/os_utils.h +++ b/src/lib/utils/os_utils.h @@ -20,11 +20,17 @@ namespace OS { uint32_t get_process_id(); /** +* Return the highest resolution clock available on the system. +* +* The epoch and update rate of this clock is arbitrary and depending +* on the hardware it may not tick at a constant rate. +* * Returns the value of the hardware cycle counter, if available. -* Returns 0 if not available. On Windows uses QueryPerformanceCounter. -* On other platforms reads the native cycle counter directly. -* The epoch and update rate are arbitrary and may not be constant -* (depending on the hardware). +* On Windows calls QueryPerformanceCounter. +* Under GCC or Clang on supported platforms the hardware cycle counter is queried: +* x86, PPC, Alpha, SPARC, IA-64, S/390x, and HP-PA +* On other platforms clock_gettime is used with some monotonic timer, if available. +* As a final callback std::chrono::high_resolution_clock is used. */ uint64_t get_processor_timestamp(); diff --git a/src/lib/utils/safeint.h b/src/lib/utils/safeint.h new file mode 100644 index 000000000..e0bd66232 --- /dev/null +++ b/src/lib/utils/safeint.h @@ -0,0 +1,39 @@ +/* +* Safe(r) Integer Handling +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_UTILS_SAFE_INT_H__ +#define BOTAN_UTILS_SAFE_INT_H__ + +#include <botan/exceptn.h> +#include <string> + +namespace Botan { + +class Integer_Overflow_Detected : public Exception + { + public: + Integer_Overflow_Detected(const std::string& file, int line) : + Exception("Integer overflow detected at " + file + ":" + std::to_string(line)) + {} + }; + +inline size_t checked_add(size_t x, size_t y, const char* file, int line) + { + // TODO: use __builtin_x_overflow on GCC and Clang + size_t z = x + y; + if(z < x) + { + throw Integer_Overflow_Detected(file, line); + } + return z; + } + +#define BOTAN_CHECKED_ADD(x,y) checked_add(x,y,__FILE__,__LINE__) + +} + +#endif diff --git a/src/lib/x509/cert_status.cpp b/src/lib/x509/cert_status.cpp new file mode 100644 index 000000000..76a102aef --- /dev/null +++ b/src/lib/x509/cert_status.cpp @@ -0,0 +1,100 @@ +/* +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/cert_status.h> + +namespace Botan { + +//static +const char* to_string(Certificate_Status_Code code) + { + switch(code) + { + case Certificate_Status_Code::VERIFIED: + return "Verified"; + case Certificate_Status_Code::OCSP_RESPONSE_GOOD: + return "OCSP response accepted as affirming unrevoked status for certificate"; + case Certificate_Status_Code::OCSP_SIGNATURE_OK: + return "Signature on OCSP response was found valid"; + case Certificate_Status_Code::VALID_CRL_CHECKED: + return "Valid CRL examined"; + + case Certificate_Status_Code::NO_REVOCATION_DATA: + return "No revocation data"; + case Certificate_Status_Code::SIGNATURE_METHOD_TOO_WEAK: + return "Signature method too weak"; + case Certificate_Status_Code::UNTRUSTED_HASH: + return "Hash function used is considered too weak for security"; + + case Certificate_Status_Code::CERT_NOT_YET_VALID: + return "Certificate is not yet valid"; + case Certificate_Status_Code::CERT_HAS_EXPIRED: + return "Certificate has expired"; + case Certificate_Status_Code::OCSP_NOT_YET_VALID: + return "OCSP is not yet valid"; + case Certificate_Status_Code::OCSP_HAS_EXPIRED: + return "OCSP response has expired"; + case Certificate_Status_Code::CRL_NOT_YET_VALID: + return "CRL response is not yet valid"; + case Certificate_Status_Code::CRL_HAS_EXPIRED: + return "CRL has expired"; + + case Certificate_Status_Code::CERT_ISSUER_NOT_FOUND: + return "Certificate issuer not found"; + case Certificate_Status_Code::CANNOT_ESTABLISH_TRUST: + return "Cannot establish trust"; + case Certificate_Status_Code::CERT_CHAIN_LOOP: + return "Loop in certificate chain"; + case Certificate_Status_Code::CHAIN_LACKS_TRUST_ROOT: + return "Certificate chain does not end in a CA certificate"; + case Certificate_Status_Code::CHAIN_NAME_MISMATCH: + return "Certificate issuer does not match subject of issuing cert"; + + case Certificate_Status_Code::POLICY_ERROR: + return "Certificate policy error"; + case Certificate_Status_Code::INVALID_USAGE: + return "Certificate does not allow the requested usage"; + case Certificate_Status_Code::CERT_CHAIN_TOO_LONG: + return "Certificate chain too long"; + case Certificate_Status_Code::CA_CERT_NOT_FOR_CERT_ISSUER: + return "CA certificate not allowed to issue certs"; + case Certificate_Status_Code::CA_CERT_NOT_FOR_CRL_ISSUER: + return "CA certificate not allowed to issue CRLs"; + case Certificate_Status_Code::OCSP_CERT_NOT_LISTED: + return "OCSP cert not listed"; + case Certificate_Status_Code::OCSP_BAD_STATUS: + return "OCSP bad status"; + case Certificate_Status_Code::CERT_NAME_NOMATCH: + return "Certificate does not match provided name"; + case Certificate_Status_Code::NAME_CONSTRAINT_ERROR: + return "Certificate does not pass name constraint"; + case Certificate_Status_Code::UNKNOWN_CRITICAL_EXTENSION: + return "Unknown critical extension encountered"; + case Certificate_Status_Code::OCSP_SIGNATURE_ERROR: + return "OCSP signature error"; + case Certificate_Status_Code::OCSP_ISSUER_NOT_FOUND: + return "Unable to find certificate issusing OCSP response"; + case Certificate_Status_Code::OCSP_RESPONSE_MISSING_KEYUSAGE: + return "OCSP issuer's keyusage prohibits OCSP"; + case Certificate_Status_Code::OCSP_RESPONSE_INVALID: + return "OCSP parsing valid"; + case Certificate_Status_Code::OCSP_NO_HTTP: + return "OCSP requests not available, no HTTP support compiled in"; + case Certificate_Status_Code::CERT_IS_REVOKED: + return "Certificate is revoked"; + case Certificate_Status_Code::CRL_BAD_SIGNATURE: + return "CRL bad signature"; + case Certificate_Status_Code::SIGNATURE_ERROR: + return "Signature error"; + case Certificate_Status_Code::CERT_PUBKEY_INVALID: + return "Certificate public key invalid"; + // intentionally no default so we are warned + } + + return nullptr; + } + +} diff --git a/src/lib/x509/cert_status.h b/src/lib/x509/cert_status.h index b69bd1832..8f514c092 100644 --- a/src/lib/x509/cert_status.h +++ b/src/lib/x509/cert_status.h @@ -1,5 +1,5 @@ /* -* Result enums +* Path validation result enums * (C) 2013 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) @@ -8,56 +8,79 @@ #ifndef BOTAN_X509_PATH_RESULT_H__ #define BOTAN_X509_PATH_RESULT_H__ +#include <botan/build.h> + namespace Botan { /** * Certificate validation status code */ enum class Certificate_Status_Code { - VERIFIED = 0x00000000, - OCSP_RESPONSE_GOOD, - NO_REVOCATION_DATA, + OK = 0, + VERIFIED = 0, + + // Revocation status + OCSP_RESPONSE_GOOD = 1, + OCSP_SIGNATURE_OK = 2, + VALID_CRL_CHECKED = 3, + OCSP_NO_HTTP = 4, + + // Errors + FIRST_ERROR_STATUS = 1000, - // Local policy failures SIGNATURE_METHOD_TOO_WEAK = 1000, - UNTRUSTED_HASH, + UNTRUSTED_HASH = 1001, + NO_REVOCATION_DATA = 1002, // Time problems CERT_NOT_YET_VALID = 2000, - CERT_HAS_EXPIRED, - OCSP_NOT_YET_VALID, - OCSP_HAS_EXPIRED, - CRL_NOT_YET_VALID, - CRL_HAS_EXPIRED, + CERT_HAS_EXPIRED = 2001, + OCSP_NOT_YET_VALID = 2002, + OCSP_HAS_EXPIRED = 2003, + CRL_NOT_YET_VALID = 2004, + CRL_HAS_EXPIRED = 2005, // Chain generation problems CERT_ISSUER_NOT_FOUND = 3000, - CANNOT_ESTABLISH_TRUST, - - CERT_CHAIN_LOOP, + CANNOT_ESTABLISH_TRUST = 3001, + CERT_CHAIN_LOOP = 3002, + CHAIN_LACKS_TRUST_ROOT = 3003, + CHAIN_NAME_MISMATCH = 3004, // Validation errors POLICY_ERROR = 4000, - INVALID_USAGE, - CERT_CHAIN_TOO_LONG, - CA_CERT_NOT_FOR_CERT_ISSUER, - NAME_CONSTRAINT_ERROR, + INVALID_USAGE = 4001, + CERT_CHAIN_TOO_LONG = 4002, + CA_CERT_NOT_FOR_CERT_ISSUER = 4003, + NAME_CONSTRAINT_ERROR = 4004, // Revocation errors - CA_CERT_NOT_FOR_CRL_ISSUER, - OCSP_CERT_NOT_LISTED, - OCSP_BAD_STATUS, + CA_CERT_NOT_FOR_CRL_ISSUER = 4005, + OCSP_CERT_NOT_LISTED = 4006, + OCSP_BAD_STATUS = 4007, - CERT_NAME_NOMATCH, - - UNKNOWN_CRITICAL_EXTENSION, + // Other problems + CERT_NAME_NOMATCH = 4008, + UNKNOWN_CRITICAL_EXTENSION = 4009, + OCSP_SIGNATURE_ERROR = 4501, + OCSP_ISSUER_NOT_FOUND = 4502, + OCSP_RESPONSE_MISSING_KEYUSAGE = 4503, + OCSP_RESPONSE_INVALID = 4504, // Hard failures CERT_IS_REVOKED = 5000, - CRL_BAD_SIGNATURE, - SIGNATURE_ERROR, + CRL_BAD_SIGNATURE = 5001, + SIGNATURE_ERROR = 5002, + CERT_PUBKEY_INVALID = 5003, }; +/** +* Convert a status code to a human readable diagnostic message +* @param code the certifcate status +* @return string literal constant, or nullptr if code unknown +*/ +BOTAN_DLL const char* to_string(Certificate_Status_Code code); + } #endif diff --git a/src/lib/x509/certstor.cpp b/src/lib/x509/certstor.cpp index 24cd84de7..1f7275675 100644 --- a/src/lib/x509/certstor.cpp +++ b/src/lib/x509/certstor.cpp @@ -7,6 +7,7 @@ #include <botan/certstor.h> #include <botan/internal/filesystem.h> +#include <botan/hash.h> namespace Botan { @@ -23,7 +24,18 @@ void Certificate_Store_In_Memory::add_certificate(const X509_Certificate& cert) return; } - m_certs.push_back(std::make_shared<X509_Certificate>(cert)); + m_certs.push_back(std::make_shared<const X509_Certificate>(cert)); + } + +void Certificate_Store_In_Memory::add_certificate(std::shared_ptr<const X509_Certificate> cert) + { + for(size_t i = 0; i != m_certs.size(); ++i) + { + if(*m_certs[i] == *cert) + return; + } + + m_certs.push_back(cert); } std::vector<X509_DN> Certificate_Store_In_Memory::all_subjects() const @@ -34,57 +46,70 @@ std::vector<X509_DN> Certificate_Store_In_Memory::all_subjects() const return subjects; } -namespace { - -template<typename T> std::shared_ptr<const X509_Certificate> -cert_search(const X509_DN& subject_dn, const std::vector<byte>& key_id, - const std::vector<std::shared_ptr<T>>& certs) +Certificate_Store_In_Memory::find_cert(const X509_DN& subject_dn, + const std::vector<byte>& key_id) const { - for(size_t i = 0; i != certs.size(); ++i) + for(size_t i = 0; i != m_certs.size(); ++i) { // Only compare key ids if set in both call and in the cert if(key_id.size()) { - std::vector<byte> skid = certs[i]->subject_key_id(); + std::vector<byte> skid = m_certs[i]->subject_key_id(); if(skid.size() && skid != key_id) // no match continue; } - if(certs[i]->subject_dn() == subject_dn) - return certs[i]; + if(m_certs[i]->subject_dn() == subject_dn) + return m_certs[i]; } return std::shared_ptr<const X509_Certificate>(); } -} std::shared_ptr<const X509_Certificate> -Certificate_Store_In_Memory::find_cert(const X509_DN& subject_dn, - const std::vector<byte>& key_id) const +Certificate_Store_In_Memory::find_cert_by_pubkey_sha1(const std::vector<byte>& key_hash) const { - return cert_search(subject_dn, key_id, m_certs); + if(key_hash.size() != 20) + throw Invalid_Argument("Certificate_Store_In_Memory::find_cert_by_pubkey_sha1 invalid hash"); + + for(size_t i = 0; i != m_certs.size(); ++i) + { + const std::vector<byte> hash_i = m_certs[i]->subject_public_key_bitstring_sha1(); + if(key_hash == hash_i) + { + return m_certs[i]; + } + } + + return nullptr; } void Certificate_Store_In_Memory::add_crl(const X509_CRL& crl) { - X509_DN crl_issuer = crl.issuer_dn(); + std::shared_ptr<const X509_CRL> crl_s = std::make_shared<const X509_CRL>(crl); + return add_crl(crl_s); + } + +void Certificate_Store_In_Memory::add_crl(std::shared_ptr<const X509_CRL> crl) + { + X509_DN crl_issuer = crl->issuer_dn(); for(size_t i = 0; i != m_crls.size(); ++i) { // Found an update of a previously existing one; replace it if(m_crls[i]->issuer_dn() == crl_issuer) { - if(m_crls[i]->this_update() <= crl.this_update()) - m_crls[i] = std::make_shared<X509_CRL>(crl); + if(m_crls[i]->this_update() <= crl->this_update()) + m_crls[i] = crl; return; } } // Totally new CRL, add to the list - m_crls.push_back(std::make_shared<X509_CRL>(crl)); + m_crls.push_back(crl); } std::shared_ptr<const X509_CRL> Certificate_Store_In_Memory::find_crl_for(const X509_Certificate& subject) const @@ -134,19 +159,4 @@ Certificate_Store_In_Memory::Certificate_Store_In_Memory(const std::string& dir) } #endif -std::shared_ptr<const X509_Certificate> -Certificate_Store_Overlay::find_cert(const X509_DN& subject_dn, - const std::vector<byte>& key_id) const - { - return cert_search(subject_dn, key_id, m_certs); - } - -std::vector<X509_DN> Certificate_Store_Overlay::all_subjects() const - { - std::vector<X509_DN> subjects; - for(size_t i = 0; i != m_certs.size(); ++i) - subjects.push_back(m_certs[i]->subject_dn()); - return subjects; - } - } diff --git a/src/lib/x509/certstor.h b/src/lib/x509/certstor.h index 56176739b..ba71334c5 100644 --- a/src/lib/x509/certstor.h +++ b/src/lib/x509/certstor.h @@ -31,6 +31,15 @@ class BOTAN_DLL Certificate_Store find_cert(const X509_DN& subject_dn, const std::vector<byte>& key_id) const = 0; /** + * Find a certificate by searching for one with a matching SHA-1 hash of + * public key. Used for OCSP. + * @param key_hash SHA-1 hash of the subject's public key + * @return a matching certificate or nullptr otherwise + */ + virtual std::shared_ptr<const X509_Certificate> + find_cert_by_pubkey_sha1(const std::vector<byte>& key_hash) const = 0; + + /** * Finds a CRL for the given certificate * @param subject the subject certificate * @return the CRL for subject or nullptr otherwise @@ -79,12 +88,24 @@ class BOTAN_DLL Certificate_Store_In_Memory : public Certificate_Store void add_certificate(const X509_Certificate& cert); /** + * Add a certificate already in a shared_ptr to the store. + * @param cert certificate to be added + */ + void add_certificate(std::shared_ptr<const X509_Certificate> cert); + + /** * Add a certificate revocation list (CRL) to the store. * @param crl CRL to be added */ void add_crl(const X509_CRL& crl); /** + * Add a certificate revocation list (CRL) to the store as a shared_ptr + * @param crl CRL to be added + */ + void add_crl(std::shared_ptr<const X509_CRL> crl); + + /** * @return DNs for all certificates managed by the store */ std::vector<X509_DN> all_subjects() const override; @@ -96,39 +117,19 @@ class BOTAN_DLL Certificate_Store_In_Memory : public Certificate_Store const X509_DN& subject_dn, const std::vector<byte>& key_id) const override; + std::shared_ptr<const X509_Certificate> + find_cert_by_pubkey_sha1(const std::vector<byte>& key_hash) const override; + /** * Finds a CRL for the given certificate */ std::shared_ptr<const X509_CRL> find_crl_for(const X509_Certificate& subject) const override; private: // TODO: Add indexing on the DN and key id to avoid linear search - std::vector<std::shared_ptr<X509_Certificate>> m_certs; - std::vector<std::shared_ptr<X509_CRL>> m_crls; - }; - -/** -* FIXME add doc -*/ -class BOTAN_DLL Certificate_Store_Overlay : public Certificate_Store - { - public: - explicit Certificate_Store_Overlay(const std::vector<std::shared_ptr<const X509_Certificate>>& certs) : - m_certs(certs) {} - - /** - * @return DNs for all certificates managed by the store - */ - std::vector<X509_DN> all_subjects() const override; - - /** - * Find a certificate by Subject DN and (optionally) key identifier - */ - std::shared_ptr<const X509_Certificate> find_cert( - const X509_DN& subject_dn, - const std::vector<byte>& key_id) const override; - private: - const std::vector<std::shared_ptr<const X509_Certificate>>& m_certs; + std::vector<std::shared_ptr<const X509_Certificate>> m_certs; + std::vector<std::shared_ptr<const X509_CRL>> m_crls; }; } + #endif diff --git a/src/lib/x509/certstor_sql/certstor_sql.cpp b/src/lib/x509/certstor_sql/certstor_sql.cpp index dfb8c5d78..4dceae305 100644 --- a/src/lib/x509/certstor_sql/certstor_sql.cpp +++ b/src/lib/x509/certstor_sql/certstor_sql.cpp @@ -78,6 +78,13 @@ Certificate_Store_In_SQL::find_cert(const X509_DN& subject_dn, const std::vector return cert; } +std::shared_ptr<const X509_Certificate> +Certificate_Store_In_SQL::find_cert_by_pubkey_sha1(const std::vector<byte>& /*key_hash*/) const + { + // TODO! + return nullptr; + } + std::shared_ptr<const X509_CRL> Certificate_Store_In_SQL::find_crl_for(const X509_Certificate& subject) const { diff --git a/src/lib/x509/certstor_sql/certstor_sql.h b/src/lib/x509/certstor_sql/certstor_sql.h index 0025884f9..0f493c56b 100644 --- a/src/lib/x509/certstor_sql/certstor_sql.h +++ b/src/lib/x509/certstor_sql/certstor_sql.h @@ -41,6 +41,9 @@ class BOTAN_DLL Certificate_Store_In_SQL : public Certificate_Store virtual std::shared_ptr<const X509_Certificate> find_cert(const X509_DN& subject_dn, const std::vector<byte>& key_id) const override; + std::shared_ptr<const X509_Certificate> + find_cert_by_pubkey_sha1(const std::vector<byte>& key_hash) const override; + /** * Returns all subject DNs known to the store instance. */ diff --git a/src/lib/x509/info.txt b/src/lib/x509/info.txt index be1e879c3..7e6afc5ad 100644 --- a/src/lib/x509/info.txt +++ b/src/lib/x509/info.txt @@ -1,10 +1,9 @@ define X509_CERTIFICATES 20151023 -define OCSP 20131128 +define OCSP 20161118 <requires> asn1 datastor -http_util pubkey sha1 </requires> diff --git a/src/lib/x509/ocsp.cpp b/src/lib/x509/ocsp.cpp index 761c5b436..bd3f1855e 100644 --- a/src/lib/x509/ocsp.cpp +++ b/src/lib/x509/ocsp.cpp @@ -14,7 +14,10 @@ #include <botan/base64.h> #include <botan/pubkey.h> #include <botan/x509path.h> -#include <botan/http_util.h> + +#if defined(BOTAN_HAS_HTTP_UTIL) + #include <botan/http_util.h> +#endif namespace Botan { @@ -22,6 +25,7 @@ namespace OCSP { namespace { +// TODO: should this be in a header somewhere? void decode_optional_list(BER_Decoder& ber, ASN1_Tag tag, std::vector<X509_Certificate>& output) @@ -44,65 +48,20 @@ void decode_optional_list(BER_Decoder& ber, } } -void check_signature(const std::vector<byte>& tbs_response, - const AlgorithmIdentifier& sig_algo, - const std::vector<byte>& signature, - const X509_Certificate& cert) - { - std::unique_ptr<Public_Key> pub_key(cert.subject_public_key()); - - const std::vector<std::string> sig_info = - split_on(OIDS::lookup(sig_algo.oid), '/'); - - if(sig_info.size() != 2 || sig_info[0] != pub_key->algo_name()) - throw Exception("Information in OCSP response does not match cert"); - - std::string padding = sig_info[1]; - Signature_Format format = - (pub_key->message_parts() >= 2) ? DER_SEQUENCE : IEEE_1363; - - PK_Verifier verifier(*pub_key, padding, format); - - if(!verifier.verify_message(ASN1::put_in_sequence(tbs_response), signature)) - throw Exception("Signature on OCSP response does not verify"); - } +} -void check_signature(const std::vector<byte>& tbs_response, - const AlgorithmIdentifier& sig_algo, - const std::vector<byte>& signature, - const Certificate_Store& trusted_roots, - const std::vector<X509_Certificate>& certs) +Request::Request(const X509_Certificate& issuer_cert, + const X509_Certificate& subject_cert) : + m_issuer(issuer_cert), + m_subject(subject_cert), + m_certid(m_issuer, m_subject) { - if(certs.size() < 1) - throw Invalid_Argument("Short cert chain for check_signature"); - - if(trusted_roots.certificate_known(certs[0])) - return check_signature(tbs_response, sig_algo, signature, certs[0]); - - // Otherwise attempt to chain the signing cert to a trust root - - if(!certs[0].allowed_extended_usage("PKIX.OCSPSigning")) - throw Exception("OCSP response cert does not allow OCSP signing"); - - auto result = x509_path_validate(certs, Path_Validation_Restrictions(), trusted_roots); - - if(!result.successful_validation()) - throw Exception("Certificate validation failure: " + result.result_string()); - - if(!trusted_roots.certificate_known(result.trust_root())) // not needed anymore? - throw Exception("Certificate chain roots in unknown/untrusted CA"); - - const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path = result.cert_path(); - - check_signature(tbs_response, sig_algo, signature, *cert_path[0]); + if(subject_cert.issuer_dn() != issuer_cert.subject_dn()) + throw Invalid_Argument("Invalid cert pair to OCSP::Request (mismatched issuer,subject args?)"); } -} - std::vector<byte> Request::BER_encode() const { - CertID certid(m_issuer, m_subject); - return DER_Encoder().start_cons(SEQUENCE) .start_cons(SEQUENCE) .start_explicit(0) @@ -110,7 +69,7 @@ std::vector<byte> Request::BER_encode() const .end_explicit() .start_cons(SEQUENCE) .start_cons(SEQUENCE) - .encode(certid) + .encode(m_certid) .end_cons() .end_cons() .end_cons() @@ -122,10 +81,10 @@ std::string Request::base64_encode() const return Botan::base64_encode(BER_encode()); } -Response::Response(const Certificate_Store& trusted_roots, - const std::vector<byte>& response_bits) +Response::Response(const uint8_t response_bits[], size_t response_bits_len) : + m_response_bits(response_bits, response_bits + response_bits_len) { - BER_Decoder response_outer = BER_Decoder(response_bits).start_cons(SEQUENCE); + BER_Decoder response_outer = BER_Decoder(m_response_bits).start_cons(SEQUENCE); size_t resp_status = 0; @@ -145,71 +104,162 @@ Response::Response(const Certificate_Store& trusted_roots, BER_Decoder basicresponse = BER_Decoder(response_bytes.get_next_octet_string()).start_cons(SEQUENCE); - std::vector<byte> tbs_bits; - AlgorithmIdentifier sig_algo; - std::vector<byte> signature; - std::vector<X509_Certificate> certs; - basicresponse.start_cons(SEQUENCE) - .raw_bytes(tbs_bits) + .raw_bytes(m_tbs_bits) .end_cons() - .decode(sig_algo) - .decode(signature, BIT_STRING); - decode_optional_list(basicresponse, ASN1_Tag(0), certs); + .decode(m_sig_algo) + .decode(m_signature, BIT_STRING); + decode_optional_list(basicresponse, ASN1_Tag(0), m_certs); size_t responsedata_version = 0; - X509_DN name; - std::vector<byte> key_hash; - X509_Time produced_at; Extensions extensions; - BER_Decoder(tbs_bits) + BER_Decoder(m_tbs_bits) .decode_optional(responsedata_version, ASN1_Tag(0), ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) - .decode_optional(name, ASN1_Tag(1), + .decode_optional(m_signer_name, ASN1_Tag(1), ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) - .decode_optional_string(key_hash, OCTET_STRING, 2, + .decode_optional_string(m_key_hash, OCTET_STRING, 2, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) - .decode(produced_at) + .decode(m_produced_at) .decode_list(m_responses) .decode_optional(extensions, ASN1_Tag(1), ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)); + } + + response_outer.end_cons(); + } + +Certificate_Status_Code Response::verify_signature(const X509_Certificate& issuer) const + { + try + { + std::unique_ptr<Public_Key> pub_key(issuer.subject_public_key()); + + const std::vector<std::string> sig_info = + split_on(OIDS::lookup(m_sig_algo.oid), '/'); + + if(sig_info.size() != 2 || sig_info[0] != pub_key->algo_name()) + return Certificate_Status_Code::OCSP_RESPONSE_INVALID; + + std::string padding = sig_info[1]; + Signature_Format format = (pub_key->message_parts() >= 2) ? DER_SEQUENCE : IEEE_1363; + + PK_Verifier verifier(*pub_key, padding, format); - if(certs.empty()) + if(verifier.verify_message(ASN1::put_in_sequence(m_tbs_bits), m_signature)) + return Certificate_Status_Code::OCSP_SIGNATURE_OK; + else + return Certificate_Status_Code::OCSP_SIGNATURE_ERROR; + } + catch(Exception&) + { + return Certificate_Status_Code::OCSP_SIGNATURE_ERROR; + } + } + +Certificate_Status_Code Response::check_signature(const std::vector<Certificate_Store*>& trusted_roots, + const std::vector<std::shared_ptr<const X509_Certificate>>& ee_cert_path) const + { + std::shared_ptr<const X509_Certificate> signing_cert; + + for(size_t i = 0; i != trusted_roots.size(); ++i) + { + if(m_signer_name.empty() && m_key_hash.empty()) + return Certificate_Status_Code::OCSP_RESPONSE_INVALID; + + if(!m_signer_name.empty()) { - if(auto cert = trusted_roots.find_cert(name, std::vector<byte>())) - certs.push_back(*cert); - else - throw Exception("Could not find certificate that signed OCSP response"); + signing_cert = trusted_roots[i]->find_cert(m_signer_name, std::vector<byte>()); + if(signing_cert) + { + break; + } } - check_signature(tbs_bits, sig_algo, signature, trusted_roots, certs); + if(m_key_hash.size() > 0) + { + signing_cert = trusted_roots[i]->find_cert_by_pubkey_sha1(m_key_hash); + if(signing_cert) + { + break; + } + } } - response_outer.end_cons(); + if(!signing_cert && ee_cert_path.size() > 1) + { + // End entity cert is not allowed to sign their own OCSP request :) + for(size_t i = 1; i < ee_cert_path.size(); ++i) + { + // Check all CA certificates in the (assumed validated) EE cert path + if(!m_signer_name.empty() && ee_cert_path[i]->subject_dn() == m_signer_name) + { + signing_cert = ee_cert_path[i]; + break; + } + + if(m_key_hash.size() > 0 && ee_cert_path[i]->subject_public_key_bitstring_sha1() == m_key_hash) + { + signing_cert = ee_cert_path[i]; + break; + } + } + } + + if(!signing_cert && m_certs.size() > 0) + { + for(size_t i = 0; i < m_certs.size(); ++i) + { + // Check all CA certificates in the (assumed validated) EE cert path + if(!m_signer_name.empty() && m_certs[i].subject_dn() == m_signer_name) + { + signing_cert = std::make_shared<const X509_Certificate>(m_certs[i]); + break; + } + + if(m_key_hash.size() > 0 && m_certs[i].subject_public_key_bitstring_sha1() == m_key_hash) + { + signing_cert = std::make_shared<const X509_Certificate>(m_certs[i]); + break; + } + } + } + + if(!signing_cert) + return Certificate_Status_Code::OCSP_ISSUER_NOT_FOUND; + + if(!signing_cert->allowed_usage(CRL_SIGN) && + !signing_cert->allowed_extended_usage("PKIX.OCSPSigning")) + { + return Certificate_Status_Code::OCSP_RESPONSE_MISSING_KEYUSAGE; + } + + return this->verify_signature(*signing_cert); } Certificate_Status_Code Response::status_for(const X509_Certificate& issuer, - const X509_Certificate& subject) const + const X509_Certificate& subject, + std::chrono::system_clock::time_point ref_time) const { for(const auto& response : m_responses) { if(response.certid().is_id_for(issuer, subject)) { - X509_Time current_time(std::chrono::system_clock::now()); + X509_Time x509_ref_time(ref_time); if(response.cert_status() == 1) return Certificate_Status_Code::CERT_IS_REVOKED; - if(response.this_update() > current_time) + if(response.this_update() > x509_ref_time) return Certificate_Status_Code::OCSP_NOT_YET_VALID; - if(response.next_update().time_is_set() && current_time > response.next_update()) + if(response.next_update().time_is_set() && x509_ref_time > response.next_update()) return Certificate_Status_Code::OCSP_HAS_EXPIRED; if(response.cert_status() == 0) @@ -222,9 +272,11 @@ Certificate_Status_Code Response::status_for(const X509_Certificate& issuer, return Certificate_Status_Code::OCSP_CERT_NOT_LISTED; } +#if defined(BOTAN_HAS_HTTP_UTIL) + Response online_check(const X509_Certificate& issuer, const X509_Certificate& subject, - const Certificate_Store* trusted_roots) + Certificate_Store* trusted_roots) { const std::string responder_url = subject.ocsp_responder(); @@ -241,11 +293,19 @@ Response online_check(const X509_Certificate& issuer, // Check the MIME type? - OCSP::Response response(*trusted_roots, http.body()); + OCSP::Response response(http.body()); + + std::vector<Certificate_Store*> trusted_roots_vec; + trusted_roots_vec.push_back(trusted_roots); + + if(trusted_roots) + response.check_signature(trusted_roots_vec); return response; } +#endif + } } diff --git a/src/lib/x509/ocsp.h b/src/lib/x509/ocsp.h index fe1796984..05f194392 100644 --- a/src/lib/x509/ocsp.h +++ b/src/lib/x509/ocsp.h @@ -29,10 +29,7 @@ class BOTAN_DLL Request * @param subject_cert subject certificate */ Request(const X509_Certificate& issuer_cert, - const X509_Certificate& subject_cert) : - m_issuer(issuer_cert), - m_subject(subject_cert) - {} + const X509_Certificate& subject_cert); /** * @return BER-encoded OCSP request @@ -53,12 +50,18 @@ class BOTAN_DLL Request * @return subject certificate */ const X509_Certificate& subject() const { return m_subject; } + + const std::vector<byte>& issuer_key_hash() const + { return m_certid.issuer_key_hash(); } private: X509_Certificate m_issuer, m_subject; + CertID m_certid; }; /** -* An OCSP response. +* OCSP response. +* +* Note this class is only usable as an OCSP client */ class BOTAN_DLL Response { @@ -69,17 +72,62 @@ class BOTAN_DLL Response Response() {} /** - * Creates an OCSP response. - * @param trusted_roots trusted roots for the OCSP response + * Parses an OCSP response. + * @param response_bits response bits received + */ + Response(const std::vector<byte>& response_bits) : + Response(response_bits.data(), response_bits.size()) + {} + + /** + * Parses an OCSP response. * @param response_bits response bits received + * @param response_bits_len length of response in bytes + */ + Response(const uint8_t response_bits[], + size_t response_bits_len); + + /** + * Check signature and return status + * The optional cert_path is the (already validated!) certificate path of + * the end entity which is being inquired about + * @param trust_roots list of certstores containing trusted roots + * @param cert_path optionally, the (already verified!) certificate path for the certificate + * this is an OCSP response for. This is necessary to find the correct intermediate CA in + * some cases. + */ + Certificate_Status_Code check_signature(const std::vector<Certificate_Store*>& trust_roots, + const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path = {}) const; + + /** + * Verify that issuer's key signed this response + * @param issuer certificate of issuer + * @return if signature valid OCSP_SIGNATURE_OK else an error code */ - Response(const Certificate_Store& trusted_roots, - const std::vector<byte>& response_bits); + Certificate_Status_Code verify_signature(const X509_Certificate& issuer) const; + + /** + * @return the time this OCSP response was supposedly produced at + */ + const X509_Time& produced_at() const { return m_produced_at; } + + /** + * @return DN of signer, if provided in response (may be empty) + */ + const X509_DN& signer_name() const { return m_signer_name; } + + /** + * @return key hash, if provided in response (may be empty) + */ + const std::vector<byte>& signer_key_hash() const { return m_key_hash; } + + const std::vector<byte>& raw_bits() const { return m_response_bits; } /** * Searches the OCSP response for issuer and subject certificate. * @param issuer issuer certificate * @param subject subject certificate + * @param ref_time the reference time * @return OCSP status code, possible values: * CERT_IS_REVOKED, * OCSP_NOT_YET_VALID, @@ -89,12 +137,24 @@ class BOTAN_DLL Response * OCSP_CERT_NOT_LISTED */ Certificate_Status_Code status_for(const X509_Certificate& issuer, - const X509_Certificate& subject) const; + const X509_Certificate& subject, + std::chrono::system_clock::time_point ref_time = std::chrono::system_clock::now()) const; private: + std::vector<byte> m_response_bits; + X509_Time m_produced_at; + X509_DN m_signer_name; + std::vector<byte> m_key_hash; + std::vector<byte> m_tbs_bits; + AlgorithmIdentifier m_sig_algo; + std::vector<byte> m_signature; + std::vector<X509_Certificate> m_certs; + std::vector<SingleResponse> m_responses; }; +#if defined(BOTAN_HAS_HTTP_UTIL) + /** * Makes an online OCSP request via HTTP and returns the OCSP response. * @param issuer issuer certificate @@ -104,7 +164,9 @@ class BOTAN_DLL Response */ BOTAN_DLL Response online_check(const X509_Certificate& issuer, const X509_Certificate& subject, - const Certificate_Store* trusted_roots); + Certificate_Store* trusted_roots); + +#endif } diff --git a/src/lib/x509/ocsp_types.cpp b/src/lib/x509/ocsp_types.cpp index d470c2fa1..c9d349a4b 100644 --- a/src/lib/x509/ocsp_types.cpp +++ b/src/lib/x509/ocsp_types.cpp @@ -26,25 +26,11 @@ CertID::CertID(const X509_Certificate& issuer, std::unique_ptr<HashFunction> hash(HashFunction::create("SHA-160")); m_hash_id = AlgorithmIdentifier(hash->name(), AlgorithmIdentifier::USE_NULL_PARAM); - m_issuer_key_hash = unlock(hash->process(extract_key_bitstr(issuer))); + m_issuer_key_hash = unlock(hash->process(issuer.subject_public_key_bitstring())); m_issuer_dn_hash = unlock(hash->process(subject.raw_issuer_dn())); m_subject_serial = BigInt::decode(subject.serial_number()); } -std::vector<byte> CertID::extract_key_bitstr(const X509_Certificate& cert) const - { - const auto key_bits = cert.subject_public_key_bits(); - - AlgorithmIdentifier public_key_algid; - std::vector<byte> public_key_bitstr; - - BER_Decoder(key_bits) - .decode(public_key_algid) - .decode(public_key_bitstr, BIT_STRING); - - return public_key_bitstr; - } - bool CertID::is_id_for(const X509_Certificate& issuer, const X509_Certificate& subject) const { @@ -58,7 +44,7 @@ bool CertID::is_id_for(const X509_Certificate& issuer, if(m_issuer_dn_hash != unlock(hash->process(subject.raw_issuer_dn()))) return false; - if(m_issuer_key_hash != unlock(hash->process(extract_key_bitstr(issuer)))) + if(m_issuer_key_hash != unlock(hash->process(issuer.subject_public_key_bitstring()))) return false; } catch(...) diff --git a/src/lib/x509/ocsp_types.h b/src/lib/x509/ocsp_types.h index 6df8ac17f..40fbb85a8 100644 --- a/src/lib/x509/ocsp_types.h +++ b/src/lib/x509/ocsp_types.h @@ -30,9 +30,10 @@ class BOTAN_DLL CertID final : public ASN1_Object void encode_into(class DER_Encoder& to) const override; void decode_from(class BER_Decoder& from) override; - private: - std::vector<byte> extract_key_bitstr(const X509_Certificate& cert) const; + const std::vector<byte>& issuer_key_hash() const { return m_issuer_key_hash; } + + private: AlgorithmIdentifier m_hash_id; std::vector<byte> m_issuer_dn_hash; std::vector<byte> m_issuer_key_hash; diff --git a/src/lib/x509/pkcs10.cpp b/src/lib/x509/pkcs10.cpp index ccd22454b..22508f131 100644 --- a/src/lib/x509/pkcs10.cpp +++ b/src/lib/x509/pkcs10.cpp @@ -46,7 +46,7 @@ PKCS10_Request::PKCS10_Request(const std::vector<byte>& in) : } /* -* Deocde the CertificateRequestInfo +* Decode the CertificateRequestInfo */ void PKCS10_Request::force_decode() { @@ -120,11 +120,7 @@ void PKCS10_Request::handle_attribute(const Attribute& attr) } else if(attr.oid == OIDS::lookup("PKCS9.ExtensionRequest")) { - Extensions extensions; - value.decode(extensions).verify_end(); - - Data_Store issuer_info; - extensions.contents_to(m_info, issuer_info); + value.decode(m_extensions).verify_end(); } } @@ -175,7 +171,12 @@ AlternativeName PKCS10_Request::subject_alt_name() const */ Key_Constraints PKCS10_Request::constraints() const { - return Key_Constraints(m_info.get1_u32bit("X509v3.KeyUsage", NO_CONSTRAINTS)); + if(auto ext = m_extensions.get(OIDS::lookup("X509v3.KeyUsage"))) + { + return dynamic_cast<Cert_Extension::Key_Usage&>(*ext).get_constraints(); + } + + return NO_CONSTRAINTS; } /* @@ -183,12 +184,12 @@ Key_Constraints PKCS10_Request::constraints() const */ std::vector<OID> PKCS10_Request::ex_constraints() const { - std::vector<std::string> oids = m_info.get("X509v3.ExtendedKeyUsage"); + if(auto ext = m_extensions.get(OIDS::lookup("X509v3.ExtendedKeyUsage"))) + { + return dynamic_cast<Cert_Extension::Extended_Key_Usage&>(*ext).get_oids(); + } - std::vector<OID> result; - for(size_t i = 0; i != oids.size(); ++i) - result.push_back(OID(oids[i])); - return result; + return {}; } /* @@ -196,15 +197,37 @@ std::vector<OID> PKCS10_Request::ex_constraints() const */ bool PKCS10_Request::is_CA() const { - return (m_info.get1_u32bit("X509v3.BasicConstraints.is_ca") > 0); + if(auto ext = m_extensions.get(OIDS::lookup("X509v3.BasicConstraints"))) + { + return dynamic_cast<Cert_Extension::Basic_Constraints&>(*ext).get_is_ca(); + } + + return false; } /* * Return the desired path limit (if any) */ -u32bit PKCS10_Request::path_limit() const +size_t PKCS10_Request::path_limit() const + { + if(auto ext = m_extensions.get(OIDS::lookup("X509v3.BasicConstraints"))) + { + Cert_Extension::Basic_Constraints& basic_constraints = dynamic_cast<Cert_Extension::Basic_Constraints&>(*ext); + if(basic_constraints.get_is_ca()) + { + return basic_constraints.get_path_limit(); + } + } + + return 0; + } + +/* +* Return the X509v3 extensions +*/ +Extensions PKCS10_Request::extensions() const { - return m_info.get1_u32bit("X509v3.BasicConstraints.path_constraint", 0); + return m_extensions; } } diff --git a/src/lib/x509/pkcs10.h b/src/lib/x509/pkcs10.h index c7a9ec300..2202b92a4 100644 --- a/src/lib/x509/pkcs10.h +++ b/src/lib/x509/pkcs10.h @@ -1,6 +1,7 @@ /* * PKCS #10 * (C) 1999-2007 Jack Lloyd +* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -10,6 +11,7 @@ #include <botan/x509_obj.h> #include <botan/x509_dn.h> +#include <botan/x509_ext.h> #include <botan/datastor.h> #include <botan/key_constraint.h> #include <botan/asn1_attribute.h> @@ -72,7 +74,7 @@ class BOTAN_DLL PKCS10_Request final : public X509_Object * in the BasicConstraints extension. * @return path limit */ - u32bit path_limit() const; + size_t path_limit() const; /** * Get the challenge password for this request @@ -81,6 +83,12 @@ class BOTAN_DLL PKCS10_Request final : public X509_Object std::string challenge_password() const; /** + * Get the X509v3 extensions. + * @return X509v3 extensions + */ + Extensions extensions() const; + + /** * Create a PKCS#10 Request from a data source. * @param source the data source providing the DER encoded request */ @@ -105,6 +113,7 @@ class BOTAN_DLL PKCS10_Request final : public X509_Object void handle_attribute(const Attribute&); Data_Store m_info; + Extensions m_extensions; }; } diff --git a/src/lib/x509/x509_ca.cpp b/src/lib/x509/x509_ca.cpp index 6aba7311c..ec56abc92 100644 --- a/src/lib/x509/x509_ca.cpp +++ b/src/lib/x509/x509_ca.cpp @@ -63,24 +63,24 @@ X509_Certificate X509_CA::sign_request(const PKCS10_Request& req, constraints = req.constraints(); } - Extensions extensions; + Extensions extensions = req.extensions(); - extensions.add( + extensions.replace( new Cert_Extension::Basic_Constraints(req.is_CA(), req.path_limit()), true); if(constraints != NO_CONSTRAINTS) { - extensions.add(new Cert_Extension::Key_Usage(constraints), true); + extensions.replace(new Cert_Extension::Key_Usage(constraints), true); } - extensions.add(new Cert_Extension::Authority_Key_ID(m_cert.subject_key_id())); - extensions.add(new Cert_Extension::Subject_Key_ID(req.raw_public_key())); + extensions.replace(new Cert_Extension::Authority_Key_ID(m_cert.subject_key_id())); + extensions.replace(new Cert_Extension::Subject_Key_ID(req.raw_public_key())); - extensions.add( + extensions.replace( new Cert_Extension::Subject_Alternative_Name(req.subject_alt_name())); - extensions.add( + extensions.replace( new Cert_Extension::Extended_Key_Usage(req.ex_constraints())); return make_cert(m_signer, rng, m_ca_sig_algo, diff --git a/src/lib/x509/x509_ext.cpp b/src/lib/x509/x509_ext.cpp index c22e9ebcb..9ef14e88d 100644 --- a/src/lib/x509/x509_ext.cpp +++ b/src/lib/x509/x509_ext.cpp @@ -22,7 +22,7 @@ namespace Botan { /* * List of X.509 Certificate Extensions */ -Certificate_Extension* Extensions::get_extension(const OID& oid, bool critical) +Certificate_Extension* Extensions::create_extension(const OID& oid, bool critical) { #define X509_EXTENSION(NAME, TYPE) \ if(oid == OIDS::lookup(NAME)) { return new Cert_Extension::TYPE(); } @@ -90,10 +90,52 @@ void Certificate_Extension::validate(const X509_Certificate&, const X509_Certifi void Extensions::add(Certificate_Extension* extn, bool critical) { + // sanity check: we don't want to have the same extension more than once + for(const auto& ext : m_extensions) + { + if(ext.first->oid_of() == extn->oid_of()) + { + throw Invalid_Argument(extn->oid_name() + " extension already present"); + } + } + + if(m_extensions_raw.count(extn->oid_of()) > 0) + { + throw Invalid_Argument(extn->oid_name() + " extension already present"); + } + m_extensions.push_back(std::make_pair(std::unique_ptr<Certificate_Extension>(extn), critical)); m_extensions_raw.emplace(extn->oid_of(), std::make_pair(extn->encode_inner(), critical)); } +void Extensions::replace(Certificate_Extension* extn, bool critical) + { + for(auto it = m_extensions.begin(); it != m_extensions.end(); ++it) + { + if(it->first->oid_of() == extn->oid_of()) + { + m_extensions.erase(it); + break; + } + } + + m_extensions.push_back(std::make_pair(std::unique_ptr<Certificate_Extension>(extn), critical)); + m_extensions_raw[extn->oid_of()] = std::make_pair(extn->encode_inner(), critical); + } + +std::unique_ptr<Certificate_Extension> Extensions::get(const OID& oid) const + { + for(auto& ext : m_extensions) + { + if(ext.first->oid_of() == oid) + { + return std::unique_ptr<Certificate_Extension>(ext.first->copy()); + } + } + + return nullptr; + } + std::vector<std::pair<std::unique_ptr<Certificate_Extension>, bool>> Extensions::extensions() const { std::vector<std::pair<std::unique_ptr<Certificate_Extension>, bool>> exts; @@ -114,6 +156,7 @@ std::map<OID, std::pair<std::vector<byte>, bool>> Extensions::extensions_raw() c */ void Extensions::encode_into(DER_Encoder& to_object) const { + // encode any known extensions for(size_t i = 0; i != m_extensions.size(); ++i) { const Certificate_Extension* ext = m_extensions[i].first.get(); @@ -130,6 +173,30 @@ void Extensions::encode_into(DER_Encoder& to_object) const .end_cons(); } } + + // encode any unknown extensions + for(const auto& ext_raw : m_extensions_raw) + { + const bool is_critical = ext_raw.second.second; + const OID oid = ext_raw.first; + const std::vector<uint8_t> value = ext_raw.second.first; + + auto pos = std::find_if(std::begin(m_extensions), std::end(m_extensions), + [&oid](const std::pair<std::unique_ptr<Certificate_Extension>, bool>& ext) -> bool + { + return ext.first->oid_of() == oid; + }); + + if(pos == std::end(m_extensions)) + { + // not found in m_extensions, must be unknown + to_object.start_cons(SEQUENCE) + .encode(oid) + .encode_optional(is_critical, false) + .encode(value, OCTET_STRING) + .end_cons(); + } + } } /* @@ -157,7 +224,7 @@ void Extensions::decode_from(BER_Decoder& from_source) m_extensions_raw.emplace(oid, std::make_pair(value, critical)); - std::unique_ptr<Certificate_Extension> ext(get_extension(oid, critical)); + std::unique_ptr<Certificate_Extension> ext(create_extension(oid, critical)); if(!ext && critical && m_throw_on_unknown_critical) throw Decoding_Error("Encountered unknown X.509 extension marked " diff --git a/src/lib/x509/x509_ext.h b/src/lib/x509/x509_ext.h index b1984fa94..1657613e7 100644 --- a/src/lib/x509/x509_ext.h +++ b/src/lib/x509/x509_ext.h @@ -88,23 +88,84 @@ class BOTAN_DLL Extensions : public ASN1_Object public: void encode_into(class DER_Encoder&) const override; void decode_from(class BER_Decoder&) override; - void contents_to(Data_Store&, Data_Store&) const; + /** + * Adds a new extension to the list. + * @param extn the certificate extension + * @param critical whether this extension should be marked as critical + * @throw Invalid_Argument if the extension is already present in the list + */ void add(Certificate_Extension* extn, bool critical = false); + /** + * Adds an extension to the list or replaces it. + * @param extn the certificate extension + * @param critical whether this extension should be marked as critical + */ + void replace(Certificate_Extension* extn, bool critical = false); + + /** + * Searches for an extension by OID and returns the result. + * Only the known extensions types declared in this header + * are searched for by this function. + * @return Pointer to extension with oid, nullptr if not found. + */ + std::unique_ptr<Certificate_Extension> get(const OID& oid) const; + + /** + * Searches for an extension by OID and returns the result. + * Only the unknown extensions, that is, extensions + * types that are not declared in this header, are searched + * for by this function. + * @return Pointer to extension with oid, nullptr if not found. + */ + template<typename T> + std::unique_ptr<T> get_raw(const OID& oid) + { + try + { + if(m_extensions_raw.count(oid) > 0) + { + std::unique_ptr<T> ext(new T); + ext->decode_inner(m_extensions_raw[oid].first); + return std::move(ext); + } + } + catch(std::exception& e) + { + throw Decoding_Error("Exception while decoding extension " + + oid.as_string() + ": " + e.what()); + } + return nullptr; + } + + /** + * Returns the list of extensions together with the corresponding + * criticality flag. Only contains the known extensions + * types declared in this header. + */ std::vector<std::pair<std::unique_ptr<Certificate_Extension>, bool>> extensions() const; + /** + * Returns the list of extensions as raw, encoded bytes + * together with the corresponding criticality flag. + * Contains all extensions, known as well as unknown extensions. + */ std::map<OID, std::pair<std::vector<byte>, bool>> extensions_raw() const; Extensions& operator=(const Extensions&); Extensions(const Extensions&); + /** + * @param st whether to throw an exception when encountering an unknown + * extension type during decoding + */ explicit Extensions(bool st = true) : m_throw_on_unknown_critical(st) {} private: - static Certificate_Extension* get_extension(const OID&, bool); + static Certificate_Extension* create_extension(const OID&, bool); std::vector<std::pair<std::unique_ptr<Certificate_Extension>, bool>> m_extensions; bool m_throw_on_unknown_critical; diff --git a/src/lib/x509/x509cert.cpp b/src/lib/x509/x509cert.cpp index f56495a79..52802a8e4 100644 --- a/src/lib/x509/x509cert.cpp +++ b/src/lib/x509/x509cert.cpp @@ -143,11 +143,14 @@ void X509_Certificate::force_decode() m_issuer.add("X509.Certificate.v2.key_id", v2_issuer_key_id); m_subject.add("X509.Certificate.v2.key_id", v2_subject_key_id); - m_subject.add("X509.Certificate.public_key", - hex_encode(public_key.value)); + m_subject.add("X509.Certificate.public_key", hex_encode(public_key.value)); - std::unique_ptr<Public_Key> pub_key(subject_public_key()); - m_self_signed = (dn_subject == dn_issuer) && check_signature(*pub_key); + m_self_signed = false; + if(dn_subject == dn_issuer) + { + std::unique_ptr<Public_Key> pub_key(subject_public_key()); + m_self_signed = check_signature(*pub_key); + } if(m_self_signed && version == 0) { @@ -221,6 +224,29 @@ std::vector<byte> X509_Certificate::subject_public_key_bits() const return hex_decode(m_subject.get1("X509.Certificate.public_key")); } +std::vector<byte> X509_Certificate::subject_public_key_bitstring() const + { + // TODO: cache this + const std::vector<byte> key_bits = subject_public_key_bits(); + + AlgorithmIdentifier public_key_algid; + std::vector<byte> public_key_bitstr; + + BER_Decoder(key_bits) + .decode(public_key_algid) + .decode(public_key_bitstr, BIT_STRING); + + return public_key_bitstr; + } + +std::vector<byte> X509_Certificate::subject_public_key_bitstring_sha1() const + { + // TODO: cache this value + std::unique_ptr<HashFunction> hash(HashFunction::create("SHA-1")); + hash->update(this->subject_public_key_bitstring()); + return hash->final_stdvec(); + } + /* * Check if the certificate is for a CA */ diff --git a/src/lib/x509/x509cert.h b/src/lib/x509/x509cert.h index acdba7e02..5cf7c81fa 100644 --- a/src/lib/x509/x509cert.h +++ b/src/lib/x509/x509cert.h @@ -49,6 +49,19 @@ class BOTAN_DLL X509_Certificate : public X509_Object std::vector<byte> subject_public_key_bits() const; /** + * Get the bit string of the public key associated with this certificate + * @return subject public key of this certificate + */ + std::vector<byte> subject_public_key_bitstring() const; + + /** + * Get the SHA-1 bit string of the public key associated with this certificate. + * This is used for OCSP among other protocols + * @return hash of subject public key of this certificate + */ + std::vector<byte> subject_public_key_bitstring_sha1() const; + + /** * Get the certificate's issuer distinguished name (DN). * @return issuer DN of this certificate */ diff --git a/src/lib/x509/x509path.cpp b/src/lib/x509/x509path.cpp index f0b07e5fc..5c1e94ff8 100644 --- a/src/lib/x509/x509path.cpp +++ b/src/lib/x509/x509path.cpp @@ -1,13 +1,12 @@ /* * X.509 Certificate Path Validation -* (C) 2010,2011,2012,2014 Jack Lloyd +* (C) 2010,2011,2012,2014,2016 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #include <botan/x509path.h> #include <botan/ocsp.h> -#include <botan/http_util.h> #include <botan/parsing.h> #include <botan/pubkey.h> #include <botan/oids.h> @@ -15,98 +14,58 @@ #include <chrono> #include <vector> #include <set> -#include <future> -namespace Botan { - -namespace { - -std::shared_ptr<const X509_Certificate> -find_issuing_cert(const X509_Certificate& cert, - Certificate_Store& end_certs, - const std::vector<Certificate_Store*>& certstores) - { - const X509_DN issuer_dn = cert.issuer_dn(); - const std::vector<byte> auth_key_id = cert.authority_key_id(); - - if(std::shared_ptr<const X509_Certificate> c = end_certs.find_cert(issuer_dn, auth_key_id)) - { - if(*c != cert) - return c; - } - - for(size_t i = 0; i != certstores.size(); ++i) - { - if(std::shared_ptr<const X509_Certificate> c = certstores[i]->find_cert(issuer_dn, auth_key_id)) - return c; - } - - return nullptr; - } - -std::shared_ptr<const X509_CRL> find_crls_for(const X509_Certificate& cert, - const std::vector<Certificate_Store*>& certstores) - { - for(size_t i = 0; i != certstores.size(); ++i) - { - if(std::shared_ptr<const X509_CRL> crl = certstores[i]->find_crl_for(cert)) - return crl; - } - -#if 0 - const std::string crl_url = cert.crl_distribution_point(); - if(crl_url != "") - { - std::cout << "Downloading CRL " << crl_url << "\n"; - auto http = HTTP::GET_sync(crl_url); - - std::cout << http.status_message() << "\n"; - - http.throw_unless_ok(); - // check the mime type - - std::unique_ptr<X509_CRL> crl(new X509_CRL(http.body())); - - return crl.release(); - } +#if defined(BOTAN_HAS_ONLINE_REVOCATION_CHECKS) + #include <future> + #include <botan/http_util.h> #endif - return nullptr; - } +namespace Botan { +/* +* PKIX path validation +*/ std::vector<std::set<Certificate_Status_Code>> -check_chain(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, - const Path_Validation_Restrictions& restrictions, - const std::vector<Certificate_Store*>& certstores, - std::chrono::system_clock::time_point ref_time) +PKIX::check_chain(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + std::chrono::system_clock::time_point ref_time, + const std::string& hostname, + Usage_Type usage, + size_t min_signature_algo_strength, + const std::set<std::string>& trusted_hashes) { - const std::set<std::string>& trusted_hashes = restrictions.trusted_hashes(); + if(cert_path.empty()) + throw Invalid_Argument("PKIX::check_chain cert_path empty"); const bool self_signed_ee_cert = (cert_path.size() == 1); X509_Time validation_time(ref_time); - std::vector<std::future<OCSP::Response>> ocsp_responses; - std::vector<std::set<Certificate_Status_Code>> cert_status(cert_path.size()); + if(!hostname.empty() && !cert_path[0]->matches_dns_name(hostname)) + cert_status[0].insert(Certificate_Status_Code::CERT_NAME_NOMATCH); + + if(!cert_path[0]->allowed_usage(usage)) + cert_status[0].insert(Certificate_Status_Code::INVALID_USAGE); + for(size_t i = 0; i != cert_path.size(); ++i) { std::set<Certificate_Status_Code>& status = cert_status.at(i); const bool at_self_signed_root = (i == cert_path.size() - 1); - std::shared_ptr<const X509_Certificate> subject = cert_path[i]; + const std::shared_ptr<const X509_Certificate>& subject = cert_path[i]; + + const std::shared_ptr<const X509_Certificate>& issuer = cert_path[at_self_signed_root ? (i) : (i + 1)]; - std::shared_ptr<const X509_Certificate> issuer = cert_path[at_self_signed_root ? (i) : (i + 1)]; + if(at_self_signed_root && (issuer->is_self_signed() == false)) + { + status.insert(Certificate_Status_Code::CHAIN_LACKS_TRUST_ROOT); + } - if(i == 0 || restrictions.ocsp_all_intermediates()) + if(subject->issuer_dn() != issuer->subject_dn()) { - // certstore[0] is treated as trusted for OCSP (FIXME) - if(certstores.size() > 1) - ocsp_responses.push_back( - std::async(std::launch::async, - OCSP::online_check, *issuer, *subject, certstores[0])); + status.insert(Certificate_Status_Code::CHAIN_NAME_MISMATCH); } // Check all certs for valid time range @@ -128,21 +87,23 @@ check_chain(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_pat if(!issuer_key) { - status.insert(Certificate_Status_Code::SIGNATURE_ERROR); + status.insert(Certificate_Status_Code::CERT_PUBKEY_INVALID); } else { if(subject->check_signature(*issuer_key) == false) + { status.insert(Certificate_Status_Code::SIGNATURE_ERROR); + } - if(issuer_key->estimated_strength() < restrictions.minimum_key_strength()) + if(issuer_key->estimated_strength() < min_signature_algo_strength) status.insert(Certificate_Status_Code::SIGNATURE_METHOD_TOO_WEAK); } - // Allow untrusted hashes on self-signed roots - if(!trusted_hashes.empty() && !at_self_signed_root) + // Ignore untrusted hashes on self-signed roots + if(trusted_hashes.size() > 0 && !at_self_signed_root) { - if(!trusted_hashes.count(subject->hash_used_for_signature())) + if(trusted_hashes.count(subject->hash_used_for_signature()) == 0) status.insert(Certificate_Status_Code::UNTRUSTED_HASH); } @@ -154,6 +115,20 @@ check_chain(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_pat } } + return cert_status; + } + +std::vector<std::set<Certificate_Status_Code>> +PKIX::check_ocsp(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_responses, + const std::vector<Certificate_Store*>& trusted_certstores, + std::chrono::system_clock::time_point ref_time) + { + if(cert_path.empty()) + throw Invalid_Argument("PKIX::check_ocsp cert_path empty"); + + std::vector<std::set<Certificate_Status_Code>> cert_status(cert_path.size() - 1); + for(size_t i = 0; i != cert_path.size() - 1; ++i) { std::set<Certificate_Status_Code>& status = cert_status.at(i); @@ -161,129 +136,508 @@ check_chain(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_pat std::shared_ptr<const X509_Certificate> subject = cert_path.at(i); std::shared_ptr<const X509_Certificate> ca = cert_path.at(i+1); - if(i < ocsp_responses.size()) + if(i < ocsp_responses.size() && (ocsp_responses.at(i) != nullptr)) { try { - OCSP::Response ocsp = ocsp_responses[i].get(); + Certificate_Status_Code ocsp_signature_status = ocsp_responses.at(i)->check_signature(trusted_certstores, cert_path); + + if(ocsp_signature_status == Certificate_Status_Code::OCSP_SIGNATURE_OK) + { + // Signature ok, so check the claimed status + Certificate_Status_Code ocsp_status = ocsp_responses.at(i)->status_for(*ca, *subject, ref_time); + status.insert(ocsp_status); + } + else + { + // Some signature problem + status.insert(ocsp_signature_status); + } + } + catch(Exception& e) + { + status.insert(Certificate_Status_Code::OCSP_RESPONSE_INVALID); + } + } + } + + while(cert_status.size() > 0 && cert_status.back().empty()) + cert_status.pop_back(); + + return cert_status; + } - auto ocsp_status = ocsp.status_for(*ca, *subject); +std::vector<std::set<Certificate_Status_Code>> +PKIX::check_crl(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + const std::vector<std::shared_ptr<const X509_CRL>>& crls, + std::chrono::system_clock::time_point ref_time) + { + if(cert_path.empty()) + throw Invalid_Argument("PKIX::check_crl cert_path empty"); - status.insert(ocsp_status); + std::vector<std::set<Certificate_Status_Code>> cert_status(cert_path.size()); + const X509_Time validation_time(ref_time); + + for(size_t i = 0; i != cert_path.size() - 1; ++i) + { + std::set<Certificate_Status_Code>& status = cert_status.at(i); + + if(i < crls.size() && crls.at(i)) + { + std::shared_ptr<const X509_Certificate> subject = cert_path.at(i); + std::shared_ptr<const X509_Certificate> ca = cert_path.at(i+1); - //std::cout << "OCSP status: " << Path_Validation_Result::status_string(ocsp_status) << "\n"; + if(!ca->allowed_usage(CRL_SIGN)) + status.insert(Certificate_Status_Code::CA_CERT_NOT_FOR_CRL_ISSUER); - // Either way we have a definitive answer, no need to check CRLs - if(ocsp_status == Certificate_Status_Code::CERT_IS_REVOKED) - return cert_status; - else if(ocsp_status == Certificate_Status_Code::OCSP_RESPONSE_GOOD) - continue; + if(validation_time < X509_Time(crls[i]->this_update())) + status.insert(Certificate_Status_Code::CRL_NOT_YET_VALID); + + if(validation_time > X509_Time(crls[i]->next_update())) + status.insert(Certificate_Status_Code::CRL_HAS_EXPIRED); + + if(crls[i]->check_signature(ca->subject_public_key()) == false) + status.insert(Certificate_Status_Code::CRL_BAD_SIGNATURE); + + status.insert(Certificate_Status_Code::VALID_CRL_CHECKED); + + if(crls[i]->is_revoked(*subject)) + status.insert(Certificate_Status_Code::CERT_IS_REVOKED); + } + } + + while(cert_status.size() > 0 && cert_status.back().empty()) + cert_status.pop_back(); + + return cert_status; + } + +std::vector<std::set<Certificate_Status_Code>> +PKIX::check_crl(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + const std::vector<Certificate_Store*>& certstores, + std::chrono::system_clock::time_point ref_time) + { + if(cert_path.empty()) + throw Invalid_Argument("PKIX::check_crl cert_path empty"); + + if(certstores.empty()) + throw Invalid_Argument("PKIX::check_crl certstores empty"); + + std::vector<std::shared_ptr<const X509_CRL>> crls(cert_path.size()); + + for(size_t i = 0; i != cert_path.size(); ++i) + { + BOTAN_ASSERT_NONNULL(cert_path[i]); + for(size_t c = 0; c != certstores.size(); ++c) + { + crls[i] = certstores[c]->find_crl_for(*cert_path[i]); + if(crls[i]) + break; + } + } + + return PKIX::check_crl(cert_path, crls, ref_time); + } + +#if defined(BOTAN_HAS_ONLINE_REVOCATION_CHECKS) + +std::vector<std::set<Certificate_Status_Code>> +PKIX::check_ocsp_online(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + const std::vector<Certificate_Store*>& trusted_certstores, + std::chrono::system_clock::time_point ref_time, + std::chrono::milliseconds timeout, + bool ocsp_check_intermediate_CAs) + { + if(cert_path.empty()) + throw Invalid_Argument("PKIX::check_ocsp_online cert_path empty"); + + std::vector<std::future<std::shared_ptr<const OCSP::Response>>> ocsp_response_futures; + + size_t to_ocsp = 1; + + if(ocsp_check_intermediate_CAs) + to_ocsp = cert_path.size() - 1; + if(cert_path.size() == 1) + to_ocsp = 0; + + for(size_t i = 0; i < to_ocsp; ++i) + { + const std::shared_ptr<const X509_Certificate>& subject = cert_path.at(i); + const std::shared_ptr<const X509_Certificate>& issuer = cert_path.at(i+1); + + if(subject->ocsp_responder() == "") + { + ocsp_response_futures.emplace_back(std::async(std::launch::deferred, [&]{ + throw Exception("No OCSP responder URL set for this certificate"); + return std::shared_ptr<const OCSP::Response>(); + })); } - catch(std::exception&) + else { - //std::cout << "OCSP error: " << e.what() << "\n"; + ocsp_response_futures.emplace_back(std::async(std::launch::async, [&]{ + OCSP::Request req(*issuer, *subject); + + auto http = HTTP::POST_sync(subject->ocsp_responder(), + "application/ocsp-request", + req.BER_encode()); + + http.throw_unless_ok(); + // Check the MIME type? + + return std::make_shared<const OCSP::Response>(http.body()); + })); } - } + } - std::shared_ptr<const X509_CRL> crl_p = find_crls_for(*subject, certstores); + std::vector<std::shared_ptr<const OCSP::Response>> ocsp_responses(ocsp_response_futures.size()); - if(!crl_p) + for(size_t pass = 1; pass < 3; ++pass) + { + for(size_t i = 0; i < ocsp_response_futures.size(); ++i) { - if(restrictions.require_revocation_information()) - status.insert(Certificate_Status_Code::NO_REVOCATION_DATA); - continue; + try + { + if(ocsp_responses[i] == nullptr && ocsp_response_futures[i].valid()) + { + std::future_status status = ocsp_response_futures[i].wait_for(timeout); + + if(status == std::future_status::ready || + status == std::future_status::deferred) + { + ocsp_responses[i] = ocsp_response_futures[i].get(); + } + } + } + catch(std::exception&) + { + // value is default initialized to null, no need to do anything + } } + } - const X509_CRL& crl = *crl_p; + return PKIX::check_ocsp(cert_path, ocsp_responses, trusted_certstores, ref_time); + } - if(!ca->allowed_usage(CRL_SIGN)) - status.insert(Certificate_Status_Code::CA_CERT_NOT_FOR_CRL_ISSUER); +std::vector<std::set<Certificate_Status_Code>> +PKIX::check_crl_online(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + const std::vector<Certificate_Store*>& certstores, + Certificate_Store_In_Memory* crl_store, + std::chrono::system_clock::time_point ref_time, + std::chrono::milliseconds timeout) + { + if(cert_path.empty()) + throw Invalid_Argument("PKIX::check_crl_online cert_path empty"); + if(certstores.empty()) + throw Invalid_Argument("PKIX::check_crl_online certstores empty"); - if(validation_time < X509_Time(crl.this_update())) - status.insert(Certificate_Status_Code::CRL_NOT_YET_VALID); + std::vector<std::future<std::shared_ptr<const X509_CRL>>> future_crls; + std::vector<std::shared_ptr<const X509_CRL>> crls(cert_path.size()); - if(validation_time > X509_Time(crl.next_update())) - status.insert(Certificate_Status_Code::CRL_HAS_EXPIRED); + for(size_t i = 0; i != cert_path.size(); ++i) + { + for(size_t c = 0; c != certstores.size(); ++i) + { + crls[i] = certstores[i]->find_crl_for(*cert_path[i]); + if(crls[i]) + break; + } - if(crl.check_signature(ca->subject_public_key()) == false) - status.insert(Certificate_Status_Code::CRL_BAD_SIGNATURE); + // TODO: check if CRL is expired and re-request? - if(crl.is_revoked(*subject)) - status.insert(Certificate_Status_Code::CERT_IS_REVOKED); + // Only request if we don't already have a CRL + if(crls[i]) + { + /* + We already have a CRL, so just insert this empty one to hold a place in the vector + so that indexes match up + */ + future_crls.emplace_back(std::future<std::shared_ptr<const X509_CRL>>()); + } + else if(cert_path[i]->crl_distribution_point() == "") + { + // Avoid creating a thread for this case + future_crls.emplace_back(std::async(std::launch::deferred, [&]{ + throw Exception("No CRL distribution point for this certificate"); + return std::shared_ptr<const X509_CRL>(); + })); + } + else + { + future_crls.emplace_back(std::async(std::launch::async, [&]() { + auto http = HTTP::GET_sync(cert_path[i]->crl_distribution_point()); + http.throw_unless_ok(); + // check the mime type? + return std::make_shared<const X509_CRL>(http.body()); + })); + } } - if(self_signed_ee_cert) - cert_status.back().insert(Certificate_Status_Code::CANNOT_ESTABLISH_TRUST); + for(size_t i = 0; i != future_crls.size(); ++i) + { + if(future_crls[i].valid()) + { + try + { + std::future_status status = future_crls[i].wait_for(timeout); - return cert_status; - } + if(status == std::future_status::ready) + { + crls[i] = future_crls[i].get(); + } + } + catch(std::exception& e) + { + // crls[i] left null + } + } + } -} + const std::vector<std::set<Certificate_Status_Code>> crl_status = PKIX::check_crl(cert_path, crls, ref_time); -Path_Validation_Result x509_path_validate( - const std::vector<X509_Certificate>& end_certs, - const Path_Validation_Restrictions& restrictions, - const std::vector<Certificate_Store*>& certstores, - const std::string& hostname, - Usage_Type usage, - std::chrono::system_clock::time_point validation_time) - { - if(end_certs.empty()) - throw Invalid_Argument("x509_path_validate called with no subjects"); + if(crl_store) + { + for(size_t i = 0; i != crl_status.size(); ++i) + { + if(crl_status[i].count(Certificate_Status_Code::VALID_CRL_CHECKED)) + { + // better be non-null, we supposedly validated it + BOTAN_ASSERT_NONNULL(crls[i]); + crl_store->add_crl(crls[i]); + } + } + } - std::vector<std::shared_ptr<const X509_Certificate>> cert_path; - std::vector<std::shared_ptr<const X509_Certificate>> end_certs_sharedptr; - cert_path.push_back(std::make_shared<X509_Certificate>(end_certs[0])); + return crl_status; + } - for(auto c: end_certs) - end_certs_sharedptr.push_back(std::make_shared<const X509_Certificate>(c)); +#endif + +Certificate_Status_Code +PKIX::build_certificate_path(std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + const std::vector<Certificate_Store*>& trusted_certstores, + const std::shared_ptr<const X509_Certificate>& end_entity, + const std::vector<std::shared_ptr<const X509_Certificate>>& end_entity_extra) + { + if(end_entity->is_self_signed()) + { + return Certificate_Status_Code::CANNOT_ESTABLISH_TRUST; + } /* * This is an inelegant but functional way of preventing path loops * (where C1 -> C2 -> C3 -> C1). We store a set of all the certificate * fingerprints in the path. If there is a duplicate, we error out. + * TODO: save fingerprints in result struct? Maybe useful for blacklists, etc. */ std::set<std::string> certs_seen; - Certificate_Store_Overlay extra(end_certs_sharedptr); + cert_path.push_back(end_entity); + certs_seen.insert(end_entity->fingerprint("SHA-256")); + + Certificate_Store_In_Memory ee_extras; + for(size_t i = 0; i != end_entity_extra.size(); ++i) + ee_extras.add_certificate(end_entity_extra[i]); // iterate until we reach a root or cannot find the issuer - while(!cert_path.back()->is_self_signed()) + for(;;) { - std::shared_ptr<const X509_Certificate> cert = find_issuing_cert(*cert_path.back(), extra, certstores); - if(!cert) - return Path_Validation_Result(Certificate_Status_Code::CERT_ISSUER_NOT_FOUND); + const X509_Certificate& last = *cert_path.back(); + const X509_DN issuer_dn = last.issuer_dn(); + const std::vector<byte> auth_key_id = last.authority_key_id(); + + std::shared_ptr<const X509_Certificate> issuer; + bool trusted_issuer = false; + + for(Certificate_Store* store : trusted_certstores) + { + issuer = store->find_cert(issuer_dn, auth_key_id); + if(issuer) + { + trusted_issuer = true; + break; + } + } + + if(!issuer) + { + // fall back to searching supplemental certs + issuer = ee_extras.find_cert(issuer_dn, auth_key_id); + } + + if(!issuer) + return Certificate_Status_Code::CERT_ISSUER_NOT_FOUND; + + const std::string fprint = issuer->fingerprint("SHA-256"); + + if(certs_seen.count(fprint) > 0) // already seen? + return Certificate_Status_Code::CERT_CHAIN_LOOP; - const std::string fprint = cert->fingerprint("SHA-256"); - if(certs_seen.count(fprint) > 0) - return Path_Validation_Result(Certificate_Status_Code::CERT_CHAIN_LOOP); certs_seen.insert(fprint); - cert_path.push_back(cert); + cert_path.push_back(issuer); + + if(issuer->is_self_signed()) + { + if(trusted_issuer) + { + return Certificate_Status_Code::OK; + } + else + { + return Certificate_Status_Code::CANNOT_ESTABLISH_TRUST; + } + } } + } - std::vector<std::set<Certificate_Status_Code>> res = - check_chain(cert_path, restrictions, certstores, validation_time); +void PKIX::merge_revocation_status(std::vector<std::set<Certificate_Status_Code>>& chain_status, + const std::vector<std::set<Certificate_Status_Code>>& crl, + const std::vector<std::set<Certificate_Status_Code>>& ocsp, + bool require_rev_on_end_entity, + bool require_rev_on_intermediates) + { + if(chain_status.empty()) + throw Invalid_Argument("PKIX::merge_revocation_status chain_status was empty"); - if(!hostname.empty() && !cert_path[0]->matches_dns_name(hostname)) - res[0].insert(Certificate_Status_Code::CERT_NAME_NOMATCH); + for(size_t i = 0; i != chain_status.size() - 1; ++i) + { + bool had_crl = false, had_ocsp = false; - if(!cert_path[0]->allowed_usage(usage)) - res[0].insert(Certificate_Status_Code::INVALID_USAGE); + if(i < crl.size() && crl[i].size() > 0) + { + for(auto&& code : crl[i]) + { + if(code == Certificate_Status_Code::VALID_CRL_CHECKED) + { + had_crl = true; + } + chain_status[i].insert(code); + } + } + + if(i < ocsp.size() && ocsp[i].size() > 0) + { + for(auto&& code : ocsp[i]) + { + if(code == Certificate_Status_Code::OCSP_RESPONSE_GOOD) + { + had_ocsp = true; + } + + chain_status[i].insert(code); + } + } - return Path_Validation_Result(res, std::move(cert_path)); + if(had_crl == false && had_ocsp == false) + { + if((require_rev_on_end_entity && i == 0) || + (require_rev_on_intermediates && i > 0)) + { + chain_status[i].insert(Certificate_Status_Code::NO_REVOCATION_DATA); + } + } + } + } + +Certificate_Status_Code PKIX::overall_status(const std::vector<std::set<Certificate_Status_Code>>& cert_status) + { + if(cert_status.empty()) + throw Invalid_Argument("PKIX::overall_status empty cert status"); + + Certificate_Status_Code overall_status = Certificate_Status_Code::OK; + + // take the "worst" error as overall + for(const std::set<Certificate_Status_Code>& s : cert_status) + { + if(!s.empty()) + { + auto worst = *s.rbegin(); + // Leave informative OCSP/CRL confirmations on cert-level status only + if(worst >= Certificate_Status_Code::FIRST_ERROR_STATUS && worst > overall_status) + { + overall_status = worst; + } + } + } + return overall_status; + } + +Path_Validation_Result BOTAN_DLL x509_path_validate( + const std::vector<X509_Certificate>& end_certs, + const Path_Validation_Restrictions& restrictions, + const std::vector<Certificate_Store*>& trusted_roots, + const std::string& hostname, + Usage_Type usage, + std::chrono::system_clock::time_point ref_time, + std::chrono::milliseconds ocsp_timeout, + const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp) + { + if(end_certs.empty()) + throw Invalid_Argument("x509_path_validate called with no subjects"); + + std::shared_ptr<const X509_Certificate> end_entity(std::make_shared<const X509_Certificate>(end_certs[0])); + std::vector<std::shared_ptr<const X509_Certificate>> end_entity_extra; + for(size_t i = 1; i < end_certs.size(); ++i) + { + end_entity_extra.push_back(std::make_shared<const X509_Certificate>(end_certs[i])); + } + + std::vector<std::shared_ptr<const X509_Certificate>> cert_path; + Certificate_Status_Code path_building_result = + PKIX::build_certificate_path(cert_path, trusted_roots, end_entity, end_entity_extra); + + // If we cannot successfully build a chain to a trusted self-signed root, stop now + if(path_building_result != Certificate_Status_Code::OK) + { + return Path_Validation_Result(path_building_result); + } + + std::vector<std::set<Certificate_Status_Code>> status = + PKIX::check_chain(cert_path, ref_time, + hostname, usage, + restrictions.minimum_key_strength(), + restrictions.trusted_hashes()); + + std::vector<std::set<Certificate_Status_Code>> crl_status = + PKIX::check_crl(cert_path, trusted_roots, ref_time); + + std::vector<std::set<Certificate_Status_Code>> ocsp_status; + + if(ocsp_resp.size() > 0) + { + ocsp_status = PKIX::check_ocsp(cert_path, ocsp_resp, trusted_roots, ref_time); + } + + if(ocsp_status.empty() && ocsp_timeout != std::chrono::milliseconds(0)) + { +#if defined(BOTAN_TARGET_OS_HAS_THREADS) && defined(BOTAN_HAS_HTTP_UTIL) + ocsp_status = PKIX::check_ocsp_online(cert_path, trusted_roots, ref_time, + ocsp_timeout, restrictions.ocsp_all_intermediates()); +#else + ocsp_status.resize(1); + ocsp_status[0].insert(Certificate_Status_Code::OCSP_NO_HTTP); +#endif + } + + PKIX::merge_revocation_status(status, crl_status, ocsp_status, + restrictions.require_revocation_information(), + restrictions.ocsp_all_intermediates()); + + return Path_Validation_Result(status, std::move(cert_path)); } Path_Validation_Result x509_path_validate( const X509_Certificate& end_cert, const Path_Validation_Restrictions& restrictions, - const std::vector<Certificate_Store*>& certstores, + const std::vector<Certificate_Store*>& trusted_roots, const std::string& hostname, Usage_Type usage, - std::chrono::system_clock::time_point when) + std::chrono::system_clock::time_point when, + std::chrono::milliseconds ocsp_timeout, + const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp) { std::vector<X509_Certificate> certs; certs.push_back(end_cert); - return x509_path_validate(certs, restrictions, certstores, hostname, usage, when); + return x509_path_validate(certs, restrictions, trusted_roots, hostname, usage, when, ocsp_timeout, ocsp_resp); } Path_Validation_Result x509_path_validate( @@ -292,12 +646,14 @@ Path_Validation_Result x509_path_validate( const Certificate_Store& store, const std::string& hostname, Usage_Type usage, - std::chrono::system_clock::time_point when) + std::chrono::system_clock::time_point when, + std::chrono::milliseconds ocsp_timeout, + const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp) { - std::vector<Certificate_Store*> certstores; - certstores.push_back(const_cast<Certificate_Store*>(&store)); + std::vector<Certificate_Store*> trusted_roots; + trusted_roots.push_back(const_cast<Certificate_Store*>(&store)); - return x509_path_validate(end_certs, restrictions, certstores, hostname, usage, when); + return x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, when, ocsp_timeout, ocsp_resp); } Path_Validation_Result x509_path_validate( @@ -306,22 +662,24 @@ Path_Validation_Result x509_path_validate( const Certificate_Store& store, const std::string& hostname, Usage_Type usage, - std::chrono::system_clock::time_point when) + std::chrono::system_clock::time_point when, + std::chrono::milliseconds ocsp_timeout, + const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp) { std::vector<X509_Certificate> certs; certs.push_back(end_cert); - std::vector<Certificate_Store*> certstores; - certstores.push_back(const_cast<Certificate_Store*>(&store)); + std::vector<Certificate_Store*> trusted_roots; + trusted_roots.push_back(const_cast<Certificate_Store*>(&store)); - return x509_path_validate(certs, restrictions, certstores, hostname, usage, when); + return x509_path_validate(certs, restrictions, trusted_roots, hostname, usage, when, ocsp_timeout, ocsp_resp); } Path_Validation_Restrictions::Path_Validation_Restrictions(bool require_rev, size_t key_strength, - bool ocsp_all) : + bool ocsp_intermediates) : m_require_revocation_information(require_rev), - m_ocsp_all_intermediates(ocsp_all), + m_ocsp_all_intermediates(ocsp_intermediates), m_minimum_key_strength(key_strength) { if(key_strength <= 80) @@ -335,21 +693,10 @@ Path_Validation_Restrictions::Path_Validation_Restrictions(bool require_rev, Path_Validation_Result::Path_Validation_Result(std::vector<std::set<Certificate_Status_Code>> status, std::vector<std::shared_ptr<const X509_Certificate>>&& cert_chain) : - m_overall(Certificate_Status_Code::VERIFIED), m_all_status(status), - m_cert_path(cert_chain) + m_cert_path(cert_chain), + m_overall(PKIX::overall_status(m_all_status)) { - // take the "worst" error as overall - for(const auto& s : m_all_status) - { - if(!s.empty()) - { - auto worst = *s.rbegin(); - // Leave OCSP confirmations on cert-level status only - if(worst != Certificate_Status_Code::OCSP_RESPONSE_GOOD) - m_overall = worst; - } - } } const X509_Certificate& Path_Validation_Result::trust_root() const @@ -372,10 +719,9 @@ std::set<std::string> Path_Validation_Result::trusted_hashes() const bool Path_Validation_Result::successful_validation() const { - if(result() == Certificate_Status_Code::VERIFIED || - result() == Certificate_Status_Code::OCSP_RESPONSE_GOOD) - return true; - return false; + return (result() == Certificate_Status_Code::VERIFIED || + result() == Certificate_Status_Code::OCSP_RESPONSE_GOOD || + result() == Certificate_Status_Code::VALID_CRL_CHECKED); } std::string Path_Validation_Result::result_string() const @@ -385,68 +731,8 @@ std::string Path_Validation_Result::result_string() const const char* Path_Validation_Result::status_string(Certificate_Status_Code code) { - switch(code) - { - case Certificate_Status_Code::VERIFIED: - return "Verified"; - case Certificate_Status_Code::OCSP_RESPONSE_GOOD: - return "OCSP response good"; - case Certificate_Status_Code::NO_REVOCATION_DATA: - return "No revocation data"; - case Certificate_Status_Code::SIGNATURE_METHOD_TOO_WEAK: - return "Signature method too weak"; - case Certificate_Status_Code::UNTRUSTED_HASH: - return "Untrusted hash"; - - case Certificate_Status_Code::CERT_NOT_YET_VALID: - return "Certificate is not yet valid"; - case Certificate_Status_Code::CERT_HAS_EXPIRED: - return "Certificate has expired"; - case Certificate_Status_Code::OCSP_NOT_YET_VALID: - return "OCSP is not yet valid"; - case Certificate_Status_Code::OCSP_HAS_EXPIRED: - return "OCSP has expired"; - case Certificate_Status_Code::CRL_NOT_YET_VALID: - return "CRL is not yet valid"; - case Certificate_Status_Code::CRL_HAS_EXPIRED: - return "CRL has expired"; - - case Certificate_Status_Code::CERT_ISSUER_NOT_FOUND: - return "Certificate issuer not found"; - case Certificate_Status_Code::CANNOT_ESTABLISH_TRUST: - return "Cannot establish trust"; - case Certificate_Status_Code::CERT_CHAIN_LOOP: - return "Loop in certificate chain"; - - case Certificate_Status_Code::POLICY_ERROR: - return "Policy error"; - case Certificate_Status_Code::INVALID_USAGE: - return "Invalid usage"; - case Certificate_Status_Code::CERT_CHAIN_TOO_LONG: - return "Certificate chain too long"; - case Certificate_Status_Code::CA_CERT_NOT_FOR_CERT_ISSUER: - return "CA certificate not allowed to issue certs"; - case Certificate_Status_Code::CA_CERT_NOT_FOR_CRL_ISSUER: - return "CA certificate not allowed to issue CRLs"; - case Certificate_Status_Code::OCSP_CERT_NOT_LISTED: - return "OCSP cert not listed"; - case Certificate_Status_Code::OCSP_BAD_STATUS: - return "OCSP bad status"; - case Certificate_Status_Code::CERT_NAME_NOMATCH: - return "Certificate does not match provided name"; - case Certificate_Status_Code::NAME_CONSTRAINT_ERROR: - return "Certificate does not pass name constraint"; - case Certificate_Status_Code::UNKNOWN_CRITICAL_EXTENSION: - return "Unknown critical extension encountered"; - - case Certificate_Status_Code::CERT_IS_REVOKED: - return "Certificate is revoked"; - case Certificate_Status_Code::CRL_BAD_SIGNATURE: - return "CRL bad signature"; - case Certificate_Status_Code::SIGNATURE_ERROR: - return "Signature error"; - // intentionally no default so we are warned - } + if(const char* s = to_string(code)) + return s; return "Unknown error"; } diff --git a/src/lib/x509/x509path.h b/src/lib/x509/x509path.h index f65652e59..79daca672 100644 --- a/src/lib/x509/x509path.h +++ b/src/lib/x509/x509path.h @@ -11,9 +11,15 @@ #include <botan/cert_status.h> #include <botan/x509cert.h> #include <botan/certstor.h> +#include <botan/ocsp.h> +#include <functional> #include <set> #include <chrono> +#if defined(BOTAN_TARGET_OS_HAS_THREADS) && defined(BOTAN_HAS_HTTP_UTIL) + #define BOTAN_HAS_ONLINE_REVOCATION_CHECKS +#endif + namespace Botan { /** @@ -28,7 +34,11 @@ class BOTAN_DLL Path_Validation_Restrictions * operations, eg 80 means 2^80) of a signature. Signatures * weaker than this are rejected. If more than 80, SHA-1 * signatures are also rejected. - * @param ocsp_all_intermediates + * 80 bit strength requires 1024 bit RSA + * 110 bit strength requires 2048 bit RSA + * Using 128 requires ECC (P-256) or ~3000 bit RSA keys. + * @param ocsp_all_intermediates Make OCSP requests for all CAs as + * well as end entity (if OCSP enabled in path validation request) */ Path_Validation_Restrictions(bool require_rev = false, size_t minimum_key_strength = 80, @@ -39,7 +49,8 @@ class BOTAN_DLL Path_Validation_Restrictions * @param minimum_key_strength is the minimum strength (in terms of * operations, eg 80 means 2^80) of a signature. Signatures * weaker than this are rejected. - * @param ocsp_all_intermediates + * @param ocsp_all_intermediates Make OCSP requests for all CAs as + * well as end entity (if OCSP enabled in path validation request) * @param trusted_hashes a set of trusted hashes. Any signatures * created using a hash other than one of these will be * rejected. @@ -60,7 +71,8 @@ class BOTAN_DLL Path_Validation_Restrictions { return m_require_revocation_information; } /** - * FIXME add doc + * @return whether all intermediate CAs should also be OCSPed. If false + * then only end entity OCSP is required/requested. */ bool ocsp_all_intermediates() const { return m_ocsp_all_intermediates; } @@ -106,6 +118,7 @@ class BOTAN_DLL Path_Validation_Result /** * @return the full path from subject to trust root + * This path may be empty */ const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path() const { return m_cert_path; } @@ -151,52 +164,54 @@ class BOTAN_DLL Path_Validation_Result explicit Path_Validation_Result(Certificate_Status_Code status) : m_overall(status) {} private: - friend Path_Validation_Result BOTAN_DLL x509_path_validate( - const std::vector<X509_Certificate>& end_certs, - const Path_Validation_Restrictions& restrictions, - const std::vector<Certificate_Store*>& certstores); - - Certificate_Status_Code m_overall; std::vector<std::set<Certificate_Status_Code>> m_all_status; std::vector<std::shared_ptr<const X509_Certificate>> m_cert_path; + Certificate_Status_Code m_overall; }; - /** * PKIX Path Validation * @param end_certs certificate chain to validate * @param restrictions path validation restrictions -* @param certstores list of certificate stores that contain trusted certificates +* @param trusted_roots list of certificate stores that contain trusted certificates * @param hostname if not empty, compared against the DNS name in end_certs[0] * @param usage if not set to UNSPECIFIED, compared against the key usage in end_certs[0] * @param validation_time what reference time to use for validation +* @param ocsp_timeout timeout for OCSP operations, 0 disables OCSP check +* @param ocsp_resp additional OCSP responses to consider (eg from peer) * @return result of the path validation */ Path_Validation_Result BOTAN_DLL x509_path_validate( const std::vector<X509_Certificate>& end_certs, const Path_Validation_Restrictions& restrictions, - const std::vector<Certificate_Store*>& certstores, + const std::vector<Certificate_Store*>& trusted_roots, const std::string& hostname = "", Usage_Type usage = Usage_Type::UNSPECIFIED, - std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now()); + std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now(), + std::chrono::milliseconds ocsp_timeout = std::chrono::milliseconds(0), + const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp = {}); /** * PKIX Path Validation * @param end_cert certificate to validate * @param restrictions path validation restrictions -* @param certstores list of stores that contain trusted certificates +* @param trusted_roots list of stores that contain trusted certificates * @param hostname if not empty, compared against the DNS name in end_cert * @param usage if not set to UNSPECIFIED, compared against the key usage in end_cert * @param validation_time what reference time to use for validation +* @param ocsp_timeout timeoutput for OCSP operations, 0 disables OCSP check +* @param ocsp_resp additional OCSP responses to consider (eg from peer) * @return result of the path validation */ Path_Validation_Result BOTAN_DLL x509_path_validate( const X509_Certificate& end_cert, const Path_Validation_Restrictions& restrictions, - const std::vector<Certificate_Store*>& certstores, + const std::vector<Certificate_Store*>& trusted_roots, const std::string& hostname = "", Usage_Type usage = Usage_Type::UNSPECIFIED, - std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now()); + std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now(), + std::chrono::milliseconds ocsp_timeout = std::chrono::milliseconds(0), + const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp = {}); /** * PKIX Path Validation @@ -206,6 +221,8 @@ Path_Validation_Result BOTAN_DLL x509_path_validate( * @param hostname if not empty, compared against the DNS name in end_cert * @param usage if not set to UNSPECIFIED, compared against the key usage in end_cert * @param validation_time what reference time to use for validation +* @param ocsp_timeout timeoutput for OCSP operations, 0 disables OCSP check +* @param ocsp_resp additional OCSP responses to consider (eg from peer) * @return result of the path validation */ Path_Validation_Result BOTAN_DLL x509_path_validate( @@ -214,7 +231,9 @@ Path_Validation_Result BOTAN_DLL x509_path_validate( const Certificate_Store& store, const std::string& hostname = "", Usage_Type usage = Usage_Type::UNSPECIFIED, - std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now()); + std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now(), + std::chrono::milliseconds ocsp_timeout = std::chrono::milliseconds(0), + const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp = {}); /** * PKIX Path Validation @@ -224,6 +243,8 @@ Path_Validation_Result BOTAN_DLL x509_path_validate( * @param hostname if not empty, compared against the DNS name in end_certs[0] * @param usage if not set to UNSPECIFIED, compared against the key usage in end_certs[0] * @param validation_time what reference time to use for validation +* @param ocsp_timeout timeoutput for OCSP operations, 0 disables OCSP check +* @param ocsp_resp additional OCSP responses to consider (eg from peer) * @return result of the path validation */ Path_Validation_Result BOTAN_DLL x509_path_validate( @@ -232,7 +253,167 @@ Path_Validation_Result BOTAN_DLL x509_path_validate( const Certificate_Store& store, const std::string& hostname = "", Usage_Type usage = Usage_Type::UNSPECIFIED, - std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now()); + std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now(), + std::chrono::milliseconds ocsp_timeout = std::chrono::milliseconds(0), + const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp = {}); + + +/** +* namespace PKIX holds the building blocks that are called by x509_path_validate. +* This allows custom validation logic to be written by applications and makes +* for easier testing, but unless you're positive you know what you're doing you +* probably want to just call x509_path_validate instead. +*/ +namespace PKIX { + +/** +* Build certificate path +* @param cert_path_out output parameter, cert_path will be appended to this vector +* @param trusted_certstores list of certificate stores that contain trusted certificates +* @param end_entity the cert to be validated +* @param end_entity_extra optional list of additional untrusted certs for path building +* @return result of the path building operation (OK or error) +*/ +Certificate_Status_Code +BOTAN_DLL build_certificate_path(std::vector<std::shared_ptr<const X509_Certificate>>& cert_path_out, + const std::vector<Certificate_Store*>& trusted_certstores, + const std::shared_ptr<const X509_Certificate>& end_entity, + const std::vector<std::shared_ptr<const X509_Certificate>>& end_entity_extra); + +/** +* Check the certificate chain, but not any revocation data +* +* @param cert_path path built by build_certificate_path with OK result +* @param ref_time whatever time you want to perform the validation +* against (normally current system clock) +* @param hostname the hostname +* @param usage end entity usage checks +* @param min_signature_algo_strength 80 or 110 typically +* Note 80 allows 1024 bit RSA and SHA-1. 110 allows 2048 bit RSA and SHA-2. +* Using 128 requires ECC (P-256) or ~3000 bit RSA keys. +* @param trusted_hashes set of trusted hash functions, empty means accept any +* hash we have an OID for +* @return vector of results on per certificate in the path, each containing a set of +* results. If all codes in the set are < Certificate_Status_Code::FIRST_ERROR_STATUS, +* then the result for that certificate is successful. If all results are +*/ +std::vector<std::set<Certificate_Status_Code>> +BOTAN_DLL check_chain(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + std::chrono::system_clock::time_point ref_time, + const std::string& hostname, + Usage_Type usage, + size_t min_signature_algo_strength, + const std::set<std::string>& trusted_hashes); + +/** +* Check OCSP responses for revocation information +* @param cert_path path already validated by check_chain +* @param ocsp_responses the OCSP responses to consider +* @param certstores trusted roots +* @param ref_time whatever time you want to perform the validation against +* (normally current system clock) +* @return revocation status +*/ +std::vector<std::set<Certificate_Status_Code>> +BOTAN_DLL check_ocsp(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_responses, + const std::vector<Certificate_Store*>& certstores, + std::chrono::system_clock::time_point ref_time); + +/** +* Check CRLs for revocation infomration +* @param cert_path path already validated by check_chain +* @param crls the list of CRLs to check, it is assumed that crls[i] (if not null) +* is the associated CRL for the subject in cert_path[i]. +* @param ref_time whatever time you want to perform the validation against +* (normally current system clock) +* @return revocation status +*/ +std::vector<std::set<Certificate_Status_Code>> +BOTAN_DLL check_crl(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + const std::vector<std::shared_ptr<const X509_CRL>>& crls, + std::chrono::system_clock::time_point ref_time); + +/** +* Check CRLs for revocation infomration +* @param cert_path path already validated by check_chain +* @param certstores a list of certificate stores to query for the CRL +* @param ref_time whatever time you want to perform the validation against +* (normally current system clock) +* @return revocation status +*/ +std::vector<std::set<Certificate_Status_Code>> +BOTAN_DLL check_crl(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + const std::vector<Certificate_Store*>& certstores, + std::chrono::system_clock::time_point ref_time); + +#if defined(BOTAN_HAS_ONLINE_REVOCATION_CHECKS) + +/** +* Check OCSP using online (HTTP) access. Current version creates a thread and +* network connection per OCSP request made. +* +* @param cert_path path already validated by check_chain +* @param trusted_certstores a list of certstores with trusted certs +* @param ref_time whatever time you want to perform the validation against +* (normally current system clock) +* @param timeout for timing out the responses, though actually this function +* may block for up to timeout*cert_path.size()*C for some small C. +* @param ocsp_check_intermediate_CAs if true also performs OCSP on any intermediate +* CA certificates. If false, only does OCSP on the end entity cert. +* @return revocation status +*/ +std::vector<std::set<Certificate_Status_Code>> +BOTAN_DLL check_ocsp_online(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + const std::vector<Certificate_Store*>& trusted_certstores, + std::chrono::system_clock::time_point ref_time, + std::chrono::milliseconds timeout, + bool ocsp_check_intermediate_CAs); + +/** +* Check CRL using online (HTTP) access. Current version creates a thread and +* network connection per CRL access. + +* @param cert_path path already validated by check_chain +* @param trusted_certstores a list of certstores with trusted certs +* @param certstore_to_recv_crls optional (nullptr to disable), all CRLs +* retreived will be saved to this cert store. +* @param ref_time whatever time you want to perform the validation against +* (normally current system clock) +* @param timeout for timing out the responses, though actually this function +* may block for up to timeout*cert_path.size()*C for some small C. +* @return revocation status +*/ +std::vector<std::set<Certificate_Status_Code>> +BOTAN_DLL check_crl_online(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + const std::vector<Certificate_Store*>& trusted_certstores, + Certificate_Store_In_Memory* certstore_to_recv_crls, + std::chrono::system_clock::time_point ref_time, + std::chrono::milliseconds timeout); + +#endif + +/** +* Find overall status (OK, error) of a validation +* @param cert_status result of merge_revocation_status or check_chain +*/ +Certificate_Status_Code BOTAN_DLL overall_status(const std::vector<std::set<Certificate_Status_Code>>& cert_status); + +/** +* Merge the results from CRL and/or OCSP checks into chain_status +* @param chain_status the certificate status +* @param crl_status results from check_crl +* @param ocsp_status results from check_ocsp +* @param require_rev_on_end_entity require valid CRL or OCSP on end-entity cert +* @param require_rev_on_intermediates require valid CRL or OCSP on all intermediate certificates +*/ +void BOTAN_DLL merge_revocation_status(std::vector<std::set<Certificate_Status_Code>>& chain_status, + const std::vector<std::set<Certificate_Status_Code>>& crl_status, + const std::vector<std::set<Certificate_Status_Code>>& ocsp_status, + bool require_rev_on_end_entity, + bool require_rev_on_intermediates); + +} } diff --git a/src/lib/x509/x509self.cpp b/src/lib/x509/x509self.cpp index b59b45f6a..fe0336014 100644 --- a/src/lib/x509/x509self.cpp +++ b/src/lib/x509/x509self.cpp @@ -65,7 +65,7 @@ X509_Certificate create_self_signed_cert(const X509_Cert_Options& opts, constraints = opts.constraints; } - Extensions extensions; + Extensions extensions = opts.extensions; extensions.add( new Cert_Extension::Basic_Constraints(opts.is_CA, opts.path_limit), @@ -119,7 +119,7 @@ PKCS10_Request create_cert_req(const X509_Cert_Options& opts, constraints = opts.constraints; } - Extensions extensions; + Extensions extensions = opts.extensions; extensions.add( new Cert_Extension::Basic_Constraints(opts.is_CA, opts.path_limit)); diff --git a/src/lib/x509/x509self.h b/src/lib/x509/x509self.h index 401b2eb2f..008eece51 100644 --- a/src/lib/x509/x509self.h +++ b/src/lib/x509/x509self.h @@ -9,6 +9,7 @@ #define BOTAN_X509_SELF_H__ #include <botan/x509cert.h> +#include <botan/x509_ext.h> #include <botan/pkcs10.h> #include <botan/asn1_time.h> @@ -115,6 +116,11 @@ class BOTAN_DLL X509_Cert_Options std::vector<OID> ex_constraints; /** + * Additional X.509 extensions + */ + Extensions extensions; + + /** * Mark the certificate as a CA certificate and set the path limit. * @param limit the path limit to be set in the BasicConstraints extension. */ diff --git a/src/scripts/ci/circle/gcc-static-debug.sh b/src/scripts/ci/circle/gcc-static-debug.sh index 3a8900fb4..d6908fa4e 100755 --- a/src/scripts/ci/circle/gcc-static-debug.sh +++ b/src/scripts/ci/circle/gcc-static-debug.sh @@ -5,6 +5,6 @@ which shellcheck > /dev/null && shellcheck "$0" # Run shellcheck on this if avai BUILD_NICKNAME=$(basename "$0" .sh) BUILD_DIR="./build-$BUILD_NICKNAME" -./configure.py --with-build-dir="$BUILD_DIR" --with-debug-info --disable-shared --via-amalgamation --with-pkcs11 +./configure.py --with-build-dir="$BUILD_DIR" --with-debug-info --disable-shared --amalgamation --with-pkcs11 make -j 2 -f "$BUILD_DIR"/Makefile "$BUILD_DIR"/botan-test diff --git a/src/scripts/ci/travis/build.sh b/src/scripts/ci/travis/build.sh index 0344fd892..0accbc3db 100755 --- a/src/scripts/ci/travis/build.sh +++ b/src/scripts/ci/travis/build.sh @@ -2,10 +2,10 @@ set -ev which shellcheck > /dev/null && shellcheck "$0" # Run shellcheck on this if available -MAKE_PREFIX="" -TEST_PREFIX="" +MAKE_PREFIX=() +TEST_PREFIX=() TEST_EXE=./botan-test -TEST_FLAGS="" +TEST_FLAGS=() CFG_FLAGS=(--prefix=/tmp/botan-installation --cc=$CC --os=$TRAVIS_OS_NAME) # PKCS11 is optional but doesn't pull in new dependencies @@ -14,7 +14,7 @@ CFG_FLAGS+=(--with-pkcs11) CC_BIN=$CXX if [ "$BUILD_MODE" = "static" ] || [ "$BUILD_MODE" = "mini-static" ]; then - CFG_FLAGS+=(--disable-shared --via-amalgamation) + CFG_FLAGS+=(--disable-shared --amalgamation) elif [ "$BUILD_MODE" = "shared" ] || [ "$BUILD_MODE" = "mini-shared" ]; then # No special flags required for shared lib build CFG_FLAGS+=() @@ -32,13 +32,13 @@ elif [ "$BUILD_MODE" = "parallel" ]; then fi elif [ "$BUILD_MODE" = "coverage" ]; then - CFG_FLAGS+=(--with-coverage) + CFG_FLAGS+=(--with-coverage --no-optimizations) elif [ "$BUILD_MODE" = "sanitizer" ]; then export ASAN_OPTIONS=detect_leaks=0 CFG_FLAGS+=(--with-sanitizers --disable-modules=locking_allocator) elif [ "$BUILD_MODE" = "valgrind" ]; then CFG_FLAGS+=(--with-valgrind --with-debug-info --disable-modules=locking_allocator) - TEST_PREFIX="valgrind --error-exitcode=9 -v" + TEST_PREFIX=(valgrind --error-exitcode=9 -v) fi if [ "$BUILD_MODE" = "mini-static" ] || [ "$BUILD_MODE" = "mini-shared" ]; then @@ -54,11 +54,12 @@ elif [ "${BUILD_MODE:0:5}" != "cross" ]; then if [ "$BUILD_MODE" = "coverage" ]; then CFG_FLAGS+=(--with-tpm) - TEST_FLAGS="--pkcs11-lib=/tmp/softhsm/lib/softhsm/libsofthsm2.so" + TEST_FLAGS=(--run-online-tests --pkcs11-lib=/tmp/softhsm/lib/softhsm/libsofthsm2.so) fi - # Avoid OpenSSL when using dynamic checkers... - if [ "$BUILD_MODE" != "sanitizer" ] && [ "$BUILD_MODE" != "valgrind" ]; then + # Avoid OpenSSL when using dynamic checkers, or on OS X where it sporadically + # is not installed on the CI image + if [ "$TRAVIS_OS_NAME" != "osx" ] && [ "$BUILD_MODE" != "sanitizer" ] && [ "$BUILD_MODE" != "valgrind" ]; then CFG_FLAGS+=(--with-openssl) fi fi @@ -72,7 +73,7 @@ if [ "${BUILD_MODE:0:6}" = "cross-" ]; then if [ "$TRAVIS_OS_NAME" = "osx" ]; then CFG_FLAGS+=(--disable-shared) - MAKE_PREFIX="xcrun --sdk iphoneos" + MAKE_PREFIX=(xcrun --sdk iphoneos) if [ "$BUILD_MODE" = "cross-arm32" ]; then CFG_FLAGS+=(--cpu=armv7 --cc-abi-flags="-arch armv7 -arch armv7s -stdlib=libc++") elif [ "$BUILD_MODE" = "cross-arm64" ]; then @@ -83,22 +84,22 @@ if [ "${BUILD_MODE:0:6}" = "cross-" ]; then if [ "$BUILD_MODE" = "cross-arm32" ]; then CC_BIN=arm-linux-gnueabihf-g++-4.8 - TEST_PREFIX="qemu-arm -L /usr/arm-linux-gnueabihf/" + TEST_PREFIX=(qemu-arm -L /usr/arm-linux-gnueabihf/) CFG_FLAGS+=(--cpu=armv7) CFG_FLAGS+=(--module-policy=modern --enable-modules=tls) elif [ "$BUILD_MODE" = "cross-arm64" ]; then CC_BIN=aarch64-linux-gnu-g++-4.8 - TEST_PREFIX="qemu-aarch64 -L /usr/aarch64-linux-gnu/" + TEST_PREFIX=(qemu-aarch64 -L /usr/aarch64-linux-gnu/) CFG_FLAGS+=(--cpu=armv8-a) CFG_FLAGS+=(--module-policy=modern --enable-modules=tls) elif [ "$BUILD_MODE" = "cross-ppc32" ]; then CC_BIN=powerpc-linux-gnu-g++-4.8 - TEST_PREFIX="qemu-ppc -L /usr/powerpc-linux-gnu/" + TEST_PREFIX=(qemu-ppc -L /usr/powerpc-linux-gnu/) CFG_FLAGS+=(--cpu=ppc32) CFG_FLAGS+=(--module-policy=modern --enable-modules=tls) elif [ "$BUILD_MODE" = "cross-ppc64" ]; then CC_BIN=powerpc64le-linux-gnu-g++-4.8 - TEST_PREFIX="qemu-ppc64le -L /usr/powerpc64le-linux-gnu/" + TEST_PREFIX=(qemu-ppc64le -L /usr/powerpc64le-linux-gnu/) CFG_FLAGS+=(--cpu=ppc64 --with-endian=little) CFG_FLAGS+=(--module-policy=modern --enable-modules=tls) elif [ "$BUILD_MODE" = "cross-win32" ]; then @@ -113,7 +114,7 @@ fi CFG_FLAGS+=(--cc-bin="ccache $CC_BIN") if [ "$BUILD_MODE" = "sonarqube" ]; then - MAKE_PREFIX="./build-wrapper-linux-x86/build-wrapper-linux-x86-64 --out-dir bw-outputs" + MAKE_PREFIX=(./build-wrapper-linux-x86/build-wrapper-linux-x86-64 --out-dir bw-outputs) fi # configure @@ -128,8 +129,9 @@ if [ "$BUILD_MODE" = "docs" ]; then doxygen build/botan.doxy sphinx-build -a -W -c src/build-data/sphinx doc/manual manual-out else - echo $MAKE_PREFIX make -j $BUILD_JOBS - time $MAKE_PREFIX make -j $BUILD_JOBS + MAKE_CMD=("${MAKE_PREFIX[@]}" make -j "$BUILD_JOBS") + echo "Running" "${MAKE_CMD[@]}" + time "${MAKE_CMD[@]}" fi # post-build ccache stats @@ -139,6 +141,8 @@ ccache --show-stats if [ "$BUILD_MODE" = "sonarqube" ]; then + cp src/build-data/sonar-project.properties . + if [ "$TRAVIS_BRANCH" = "master" ] && [ "$TRAVIS_PULL_REQUEST" = "false" ]; then # => This will run a full analysis of the project and push results to the SonarQube server. # @@ -155,11 +159,11 @@ if [ "$BUILD_MODE" = "sonarqube" ]; then # http://docs.travis-ci.com/user/pull-requests/#Security-Restrictions-when-testing-Pull-Requests # That's why the analysis does not need to be executed if the variable GITHUB_TOKEN is not defined. echo "Starting Pull Request analysis by SonarQube..." - sonar-scanner -Dsonar.login=$SONAR_TOKEN \ + sonar-scanner -Dsonar.login="$SONAR_TOKEN" \ -Dsonar.analysis.mode=preview \ - -Dsonar.github.oauth=$GITHUB_TOKEN \ - -Dsonar.github.repository=$TRAVIS_REPO_SLUG \ - -Dsonar.github.pullRequest=$TRAVIS_PULL_REQUEST + -Dsonar.github.oauth="$GITHUB_TOKEN" \ + -Dsonar.github.repository="$TRAVIS_REPO_SLUG" \ + -Dsonar.github.pullRequest="$TRAVIS_PULL_REQUEST" fi # When neither on master branch nor on a non-external pull request => nothing to do fi @@ -168,8 +172,9 @@ if [ "$BUILD_MODE" = "sonarqube" ] || [ "$BUILD_MODE" = "docs" ] || \ ( [ "${BUILD_MODE:0:5}" = "cross" ] && [ "$TRAVIS_OS_NAME" = "osx" ] ); then echo "Running tests disabled on this build type" else - echo Running $TEST_PREFIX $TEST_EXE $TEST_FLAGS - time $TEST_PREFIX $TEST_EXE $TEST_FLAGS + TEST_CMD=("${TEST_PREFIX[@]}" $TEST_EXE "${TEST_FLAGS[@]}") + echo "Running" "${TEST_CMD[@]}" + time "${TEST_CMD[@]}" fi # Run Python tests (need shared libs) diff --git a/src/scripts/ci/travis/install.sh b/src/scripts/ci/travis/install.sh index c3e4ee834..9f24457ab 100755 --- a/src/scripts/ci/travis/install.sh +++ b/src/scripts/ci/travis/install.sh @@ -23,9 +23,13 @@ if [ "$TRAVIS_OS_NAME" = "linux" ]; then if [ "$BUILD_MODE" = "docs" ]; then sudo apt-get install doxygen - # The version of Sphinx in 14.04 is too old (1.2.2) - # and does not support all C++ features used in the manual - sudo pip install sphinx + + # The version of Sphinx in 14.04 is too old (1.2.2) and does not support + # all C++ features used in the manual. Install python-requests to avoid + # problem in Ubuntu packaged version, see + # http://stackoverflow.com/questions/32779919/no-module-named-for-requests + sudo apt-get remove python-requests python-openssl + sudo pip install requests sphinx pyopenssl fi if [ "$BUILD_MODE" = "coverage" ]; then @@ -76,7 +80,7 @@ if [ "$TRAVIS_OS_NAME" = "osx" ]; then if [ "$BUILD_MODE" != "cross-arm32" ] && [ "$BUILD_MODE" != "cross-arm64" ]; then brew install xz - brew install python # python2 + # Python2 is already installed brew install python3 # Boost 1.58 is installed on Travis OS X images diff --git a/src/scripts/lcov.sh b/src/scripts/lcov.sh new file mode 100755 index 000000000..1068b21aa --- /dev/null +++ b/src/scripts/lcov.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +./configure.py --with-debug-info --with-coverage-info --with-bzip2 --with-lzma --with-sqlite --with-zlib --with-pkcs11 --with-openssl --with-sqlite3 + +make -l4 -j$(nproc) -k +./botan-test --pkcs11-lib=/usr/lib/libsofthsm2.so --run-online-tests + +#LCOV_OPTIONS="--rc lcov_branch_coverage=1" +LCOV_OPTIONS="" + +rm -f coverage.info coverage.info.raw +lcov $LCOV_OPTIONS --capture --directory . --output-file coverage.info.raw +lcov $LCOV_OPTIONS --remove coverage.info.raw '/usr/*' --output-file coverage.info +genhtml $LCOV_OPTIONS coverage.info --output-directory lcov-out diff --git a/src/scripts/oids.py b/src/scripts/oids.py index 8d5cd6d8f..5e53decf7 100755 --- a/src/scripts/oids.py +++ b/src/scripts/oids.py @@ -34,6 +34,9 @@ def format_as_map(oid2str, str2oid): * * This file was automatically generated by %s on %s * +* All manual edits to this file will be lost. Edit the script +* then regenerate this source file. +* * Botan is released under the Simplified BSD License (see license.txt) */ @@ -81,6 +84,9 @@ def format_as_ifs(oid2str, str2oid): * * This file was automatically generated by %s on %s * +* All manual edits to this file will be lost. Edit the script +* then regenerate this source file. +* * Botan is released under the Simplified BSD License (see license.txt) */ diff --git a/src/tests/data/block/aes.vec b/src/tests/data/block/aes.vec index 4f428f252..43fff6739 100644 --- a/src/tests/data/block/aes.vec +++ b/src/tests/data/block/aes.vec @@ -1,3 +1,5 @@ +# Test vectors from NIST CAVP AESAVS +# http://csrc.nist.gov/groups/STM/cavp/documents/aes/AESAVS.pdf #test cpuid aesni ssse3 diff --git a/src/tests/data/block/idea.vec b/src/tests/data/block/idea.vec index eee5ef5e9..3f9c2f4cf 100644 --- a/src/tests/data/block/idea.vec +++ b/src/tests/data/block/idea.vec @@ -94,6 +94,10 @@ Key = F2022315280960F16FD09741D13F693A In = C309000000000000A02A000000000000B03D000000000000C9420000000000002B4C000000000000A04E0000000000009857000000000000C8600000000000000063000000000000F2660000000000008698000000000000729D00000000000034A000000000000023A500000000000010AE00000000000025AE00000000000030D600000000000064DB000000000000BCE1000000000000F6E70000000000004AEC00000000000080F9000000000000E0FE00000000000061FF000000000000 Out = 9C3C4F44BB50DF7367DAD70E6FED04E0AEB0344116C6E41F66A1A304E822132D8AFCC1727259D93DD6E742EAEF2FD8C03EAD7890DC4EFACBB8776F3439A3DB1B55D47DC6BC4A43349BA9E85FE178CD1ADBDD4E9D19CA1E7659341251586E13864A8C4E93A2616A0C18890A622452AD9FD09CB1A9CDC83ABF2FCFA325FA0117319C924852D426132D05DA82EEBC3C261A6036C6477FBE3F65C40B8B02C2F9D8C8B3084034AB3873CF22F20759C145ECCE92CE6B557D6DB959DA0B8AD4E0DFBCEA +Key = 00010002000300040005000600070008 +In = 000000010002000301020304050607080019324B647D96AFF5202D5B9C671B08FAE6D2BEAA96826E0A141E28323C4650050A0F14191E2328050A0F14191E2328000000010002000301020304050607080019324B647D96AFF5202D5B9C671B08FAE6D2BEAA96826E0A141E28323C4650050A0F14191E2328050A0F14191E2328 +Out = 11FBED2B01986DE5540E5FEA18C2F8B19F0A0AB6E10CED78CF18FD7355E2C5C585DF52005608193D2F7DE750212FB7347B7314925DE59C097B7314925DE59C0911FBED2B01986DE5540E5FEA18C2F8B19F0A0AB6E10CED78CF18FD7355E2C5C585DF52005608193D2F7DE750212FB7347B7314925DE59C097B7314925DE59C09 + Key = 67C6697351FF4AEC29CDBAABF2FBE346 In = 7CC254F81BE8E78D765A2E63339FC99A66320DB73158A35A255D051758E95ED4ABB2CDC69BB454110E827441213DDC8770E93EA141E1FC673E017E97EADC6B968F385C2AECB03BFB32AF3C54EC18DB5C021AFE43FBFAAA3AFB29D1E6053C7C9475D8BE6189F95CBBA8990F95B1EBF1B305EFF700E9A13AE5CA0BCBD0484764BD1F231EA81C7B64C514735AC55E4B79633B706424119E09DCAAD4ACF21B10AF3B33CDE3504847155CBB6F2219BA9B7DF50BE11A1C7F23F829F8A41B13B5CA4EE8983238E0794D3D34BC5F4E77FACB6C05AC86212BAA1A55A2BE70B5733B045CD33694B3AFE2F0E49E4F321549FD824EA90870D4B28A2954489A0ABCD50E18A844AC5BF38E4CD72D9B0942E506C433AFCDA3847F2DADD47647DE321CEC4AC430F62023856CFBB20704F4EC0BB920BA86C33E05F1ECD96733B79950A3E314D3D934F75EA0F210A8F6059401BEB4BC4478FA4969E623D01ADA696A7E4C7E5125B34884533A94FB319990325744EE9BBCE9E525CF08F5E9E25E5360AAD2B2D085FA54D835E8D466826498D9A8877565705A8A3F62802944DE7CA5894E5759D351ADAC869580EC17E485F18C0C66F17CC07CBB22FCE466DA610B63AF62BC83B4692F3AFFAF271693AC071FB86D11342D8DEF4F89D4B66335C1C7E4248367D8ED9612EC453902D8E50AF89D7709D1A596C1F41F95AA82CA6C49AE90CD1668BAAC7AA6F2B4A8CA99B2C2372ACB08CF61C9C3805E6E0328DA4CD76A19EDD2D3994C798B0022569AD418D1FEE4D9CD45A391C601FFC92AD91501432FEE150287617C13629E69FC7281CD7165A63EAB49CF714BCE3A75A74F76EA7E64FF81EB61FDFEC39B67BF0DE98C7E4E32BDF97C8C6AC75BA43C02F4B2ED7216ECF3014DF000108B67CF99505B179F8ED4980A6103D1BCA70DBE9BBFAB0ED59801D6E5F2D6F67D3EC5168E212E2DAF02C6B963C98A1F7097DE0C56891A2B211B01070DD8FD8B16C2A1A4E3CFD292D2984B3561D555D16C33DDC2BCF7EDDE13EFE520C7E2ABDDA44D81881C531AEEEB66244C3B791EA8ACFB6A68F3584606472B260E0DD2EBB21F6C3A3BC0542AABBA4EF8F6C7169E731108DB0460220AA74D31B55B03A00D220D475DCD9B877856D5704C9C86EA0F98F2EB9C530DA7FA5AD8B0B5DB50C2FD5D095A2AA5E2A3FBB71347549A316332234ECE765B7571B64D216B28712E25CF3780F9DC629CD719B01E6D4A4FD17C731F4AE97BC05A310D7B9C36EDCA5BBC02DBB5DE3D52B65702D4C44C2495C897B5128030D2DB61E056FD1643C871FFCA4DB5A88A075EE10933A655573B1DEEF02F6E20024981E2A07FF8E34769E311B698B9419F1822A84BC8FDA2041A90F449FE154B48962DE81525CB5C8FAE6D45462786E53FA98D8A718A2C75A4BC6AEEBA7F39021567EA2B8CB6871B64F561AB1CE7905B901EE5 Out = 9C142A22EDF81444F47272B80A037C169E304393537CECE8003BD80F7B0544063B4A141F9A99D3C6820BAD98BECD914804F389EB2A50E1E2CF22161FC78B93660E07E2686E70AC0715299C4796F3559FDA802E61CB4ABBF42BAE516BD09FA410085A0A92C6F32A3797D19808D3B3D049B605852E970E5A1B8031D3DC34B5A273F54ED35E21D780204F4B3C512596237153BE9FAF74A44E9A9DCBE96D628AA58B1E3363A94DF540230B38A1ACA440432640E5387D92F1CC1A16F8628A4CB6229F513AB926300668CF97B27643C9C9D0C3030D0CDFBBCB69C3DB199E5D392A97A51DE6C9881AE5612A69FA0EA026F2F254B929201AFB3AFC8D977C3ED6E12F011892037D0F49B0144E07A0F0556F0BAC9B3F829C233265439AF711E0B5DD6EC813FD51281E8AA6F031B096C64EE8F03E041FE4DC6B5441141F2D4A308CE8EA77C6483E3CF565EC49CF27A0B13F28D3C63AD7FB6B3A96579D30C9D65F7BA86E56DA6D14AF3C7D170CB5BF5F21C70C1771354DA2850CFF8D9250273828C1FE60C4AC086049404E3D63E04935F03B057B4783B13CF49757A8B5ABB3D2E37E54B881D236F7DF7FE80E4AE33E9125F54AA96D96BFB15607F0800B215CBF9BB0F7E29080D8504E9BC1F78256593B9565E5AA5FA22032A47041B453D1B154A8D24CD59CF9AA6A8E55363F3DF2B6307ABA5134D67B0DF0AE4FE77F23BF7DF8504FE9DC7F32A8562E2DF585E639847DD624E55B0D0DCCDA72D0F1E072D82D4BC135DC5F7F9130956D401FAB1456527FE087A436C1511CDFEA58202D200E1817E360E8400AAE83B073A63596B033D7E83C6CAB7FDD7069C3B1718EAF60B937CD2458255E68FCD9514FD14AA6E27EC76E75F95F0A678A0F64D49C1B9B8F8DA56DDB8CE640FF6E7195F4A679165F9996F3DDF992E3CB4ED9E9084AFC0038E4BEFB467CC8170AF8F004082BBCB137BBD45C124BE8CEDC89DD565A24830889CE4B9781FC18803BDA1A0A4EB70DA35887B02F18CFF9329E2B7C31B0F5F0648E0508379B52C8FF91CEF939A040A8C20F2F27ED65553680729A2181B3B3C4AA02BFF8DF0A9228A87BBF52B48F473D0F9070C76E4DB6F09FFDFEB629BD0E1944B7016AF34187E2985AEAE30D6480A58F649A0C858E1F1458388A9E822A306AC1AA7465882DE78F242EF7B0CB45D68A057F00D8609587922C8FAD6F1A7FFA34BF2175FC516730A61CF82C6F866C978CC292BCC1F91E6AF1785FCDAA9A43A01E6AEE91E222F8AF8C989F2A4C50B7A1D45BC15E11E5E6E6EF720506B8DF564648BEBFE272C0A77D41295865108150CDB3620970A37DB94F1CC35E434DC33434D99871F6141EB57C9E648AD1BF70E2B7FCEB81EA871DD92F19C366EA532CA4A7BEF9242128B7ADDD308B58FFF5594CB4156A03C6A6ED3F27E8DB20FB2F4208422B7E9E0A4E63A0122560CFBC diff --git a/src/tests/data/block/serpent.vec b/src/tests/data/block/serpent.vec index 8a40c54b7..9e6b9eb07 100644 --- a/src/tests/data/block/serpent.vec +++ b/src/tests/data/block/serpent.vec @@ -10,6 +10,10 @@ Key = 0000000000000000000000000000000000000000000000000000000000000000 In = D095576FCEA3E3A7ED98D9F29073D78E2F6AA890CEA3E3A7ED98D9F29073D78ED095576F315C1C58ED98D9F29073D78E2F6AA890315C1C58ED98D9F29073D78ED095576FCEA3E3A71267260D9073D78E2F6AA890CEA3E3A71267260D9073D78ED095576F315C1C581267260D9073D78E2F6AA890315C1C581267260D9073D78E5718F3B4ED59D02DE5C40E9A826FFF30AC56479B43617B1C7C804629E36E93F520027AB27AB4CCF48F9973CC052E0A35C8DD678E5D5E8F67FAA0CB599C7886BD Out = B90EE5862DE69168F2BDD5125B45472BA3E17E2DF4EA6F41B2017E37023F202AFD2951E466110BC6F4816EBF968CDD01C36EE750C51192B0C85D5BB2584AE06286069E27F65F454C6E3F7E9097DCEFAA00FA885A8854844C970338841CA2E24DA18A399A0AA2FD20EAA740A0CB6145B53D79E39A79CC14D97147F3D172F66BB19263BE9CA3CB9661695C1CCD1041F2E8C35E27B56BAA1AF03542B3DA703BFEF722AAA7F89676ADAA2923903B2A3DB526734448F52EDB9316CAFA7F095C24B0E7 +Key = 00000000000000000000000000000000 +In = D29D576FCEA3A3A7ED9099F29273D78E2D62A890CEA3A3A7ED9099F29273D78ED29D576F315C5C58ED9099F29273D78E2D62A890315C5C58ED9099F29273D78ED29D576FCEA3A3A7126F660D9273D78E2D62A890CEA3A3A7126F660D9273D78ED29D576F315C5C58126F660D9273D78E2D62A890315C5C58126F660D9273D78ED29D576FCEA3A3A7ED9099F26D8C28712D62A890CEA3A3A7ED9099F26D8C2871D29D576F315C5C58ED9099F26D8C28712D62A890315C5C58ED9099F26D8C2871D29D576FCEA3A3A7126F660D6D8C28712D62A890CEA3A3A7126F660D6D8C2871D29D576F315C5C58126F660D6D8C28712D62A890315C5C58126F660D6D8C2871AA26D561F567520E8AE47528C24C18D731A2193D9A97FED6922B17AAA6372B74BE5DEBD559E303C9C92B174A5107BBFEB626D8F65EDCCDF3AEE475C8A183772241DDE7C1F1631F5FDED4F42746471BD651D238BA86176EFE39E4695AAEB73B52EA5926CADAD8018962E469BA920CB8BF1EA9062E4D9CEDD5FAD4F4C7990367A4B966E5C5D2277288C61B96A559CC84AFB6A6583C5AACFCD6212B0BD8AEF3C6A9A11DDBD175639341052B0B384678D8D9352299B71DD880E29D1B96452DB86540B2288B968AE8B08648D1CE9606FD992D717EB02EB81A2E939D54ACA91087112D0D809C5EE82F477EBA7B956DBB23463B0F0190D616F5294112FFB7884E8B37F941BA1B505386B7428B88338188F7E718A3348230BF5CFA552F88D22463D9703A115351622E016BCA26918D17E13225F67EE4E3F2C46FE52ECBDA044C585717DC563A8403FF5309D62370B1DCF5A11EDD2F7D73602B70CD2553E44C1D3F170126155BBD9BE3A965B345E834718F651CEF6CC65E8C5C566E894817350F497816F1EEFA51FC91FEBB6E9F8CB141CC0EB6AF3C6F8380CBD3C996167F2F0E90E71B756C87EB62A4975356B28DCBF6A64A0BD107206D48FE6DBE19D50314B90AC87B8335706F9B26007071AD8105CFAA1C1E2FF7FEAE5CEC4D11477F24E6B2009068703C0E29E2950F2AC2DACD63DEEB5C7EFA9FDB9F3B740563D5518287DC981FC9CB46D4B5A5A86FEC08FE70D18297DCF51072DDBE038DA040EBB12C509F5940A212DDEB59F02132BE4581FC23EABAA960D6341D9352E36DFD6E4EAF0F6F439BC8CE73A9AB3164FF30350F2DC08E939A104D6DF0C2C28F8E2D44468A61278BB6B4294DAE45AE0CAA032FC97CD4D8C57FB83BBA8AFCAE22070BC882D3A42B38A09E65 +Out = B2288B968AE8B08648D1CE9606FD992D717EB02EB81A2E939D54ACA91087112D0D809C5EE82F477EBA7B956DBB23463B0F0190D616F5294112FFB7884E8B37F941BA1B505386B7428B88338188F7E718A3348230BF5CFA552F88D22463D9703A115351622E016BCA26918D17E13225F67EE4E3F2C46FE52ECBDA044C585717DC563A8403FF5309D62370B1DCF5A11EDD2F7D73602B70CD2553E44C1D3F170126155BBD9BE3A965B345E834718F651CEF6CC65E8C5C566E894817350F497816F1EEFA51FC91FEBB6E9F8CB141CC0EB6AF3C6F8380CBD3C996167F2F0E90E71B756C87EB62A4975356B28DCBF6A64A0BD107206D48FE6DBE19D50314B90AC87B8335706F9B26007071AD8105CFAA1C1E2FF7FEAE5CEC4D11477F24E6B2009068703C0E29E2950F2AC2DACD63DEEB5C7EFA9FDB9F3B740563D5518287DC981FC9CB46D4B5A5A86FEC08FE70D18297DCF51072DDBE038DA040EBB12C509F5940A212DDEB59F02132BE4581FC23EABAA960D6341D9352E36DFD6E4EAF0F6F439BC8CE73A9AB3164FF30350F2DC08E939A104D6DF0C2C28F8E2D44468A61278BB6B4294DAE45AE0CAA032FC97CD4D8C57FB83BBA8AFCAE22070BC882D3A42B38A09E6558A51ED82169DE7027CBE72452626CA3FF6BBF2FB2C574EC9D5656505B51688047AEA89DBBB5C4EBE819C5BDFDAB16033D2FE7D01071373624D99845D90E32C1708C609C4E75BE40D8DE77F8EA78C2CC98852792C22E971F29C2E125247FB43CAD1FD857DE9B8016C5971FFF86AD399ED669FEF7481FD73B9A45B1CFFE9C556DAE9A816916FB1F5822B2CEC8986F6E5B156775D0F6F432D57D351C62A24AFE63AE812270F7416D05E153E5AB703DCD3FF320F6AD3D00647C23F08699E0EE9F5EDDB3C717C2A6D3E58D38269DBA0243926D64CCD92B1101086DD3F0DDB73312A31D5F5EA0FD18AB84E242C96FFCC222F9FE12D5B15F5A3C365E9FF3248FB43B385A0F73507F49A08E68952BEE09DC7D35E7B29A44C8970624CB3A93DA4AE7E49835AE41A5BE2EE591750FF9A7D431B1EE8A69099E689A06324AA0AE431ACAE762FD3B90A8B269090A4CEEA076CF1EB7A580DEDE896BED63917384B1C5E18B7B57A7EB6B127A7A32898989E32CFF9A46BF6A62268500E53AD8A5FBC95226266BD9AAE1BA501274C49A7A7EC67D7577114B7707DAB9D066AF086C09E7DD4116CEA6EE25DA9A65EF05A31ED0BDF56D525EC8968D1D01AF7165C5AEAC76BD367A575A + Key = 000000000000000000000000000000000000000000000000 In = D29D576FCEABA3A7ED9899F2927BD78E Out = 130E353E1037C22405E8FAEFB2C3C3E9 diff --git a/src/tests/data/block/xtea.vec b/src/tests/data/block/xtea.vec index e2377c887..27b88ae99 100644 --- a/src/tests/data/block/xtea.vec +++ b/src/tests/data/block/xtea.vec @@ -147,3 +147,126 @@ Key = A6BFB85FA91B8CA4197C8B502A62F972 In = 3DAADD7A9633E19B Out = 4DE5C07EA1564A64 +Key = DD0C8719A8DA117DD9D1DAA189E65654 +In = E197D59E064818B7C8AD72C29E227E09 +Out = 04CD161E422154E5BCA5249582B9D4C0 + +Key = D8C8ACF6B4B68A837639320798994979 +In = AE53AA320088B4042EAAEE3649FE6E36445696F01CA40D3C +Out = A3B303C42178F97F719449529D51511491B41EB70E6101C6 + +Key = 24059EA6D8A9F0CA678ED6680362596F +In = 655A6B1D6970ABA078819E5AE1D08471A0E01E0A5C64E612504F4BD9BE4A8AE8 +Out = 7DB966E1A2B7C0E8EAA9D308EF89652A5857461D100DD0CEF9C6FE7BB4DFE33A + +Key = 2434D48F17E0A7D91F255FCE60F3D6EA +In = F3B1BB81C053DB02A8515885CA6DF124AB04927D2AAF6F0032BF17B4B437E1F2C7D82F89BAD898DF +Out = 215D5ABF53C4AA0D7571A0D9D05C3B6D33D65BF35EFFA4778FF59DEE90900ACDD4FC6645368A294F + +Key = 18C1E1EB3925EEC61559DB74EC99491B +In = 06F0A1AD9F9EAA665044D0A2EFA10ABC30F7FBA3FC47C6AE1947B7E9B47733547E5C843DAC59D09393835061D834971E +Out = 066309B116A6692F279F2526FD284E75479BF7FB5F63096AD7108CFB0DB39062A2627594F098F0BF5A3B4C67CF29E993 + +Key = 5258617DB39A2968B1EB02565A2BDD1D +In = 2FA1106E95056E070352666F059A72DF6CC949BB3161D5FFD8FE46451444D096BBD606B0BD443189AF001E5BBBA134DB1FEA7AE9B4587438 +Out = 1DF05B34A733F83B7DA1F194507904CDA99C374174AAB472CC598E06960263BD9DD0EFA2F4C14CC8AF4039A55EC00125766D25FBB7139081 + +Key = C4A02982C1291093144C64DA1E7E3D67 +In = E6ABE28FD1E9392CFC65978D586D31D344140673E345D6AA06C75E1C03E4E314831EB94ABCAF6B23F2C34670A79500C6142EE722FD7E408D751DCB30E5C63F5D +Out = 3EC6FE802F4EAA740DDF34EB79798F458049FE09190D12455EDD6129BAE85D22FF4E96AEB59DB9413DC24D41730454F65C443C819265B4CDBFB87F5ADDE7F4EA + +Key = 58B61987700468A366178595E20A365A +In = 213595590E62A55F241E3D4CFCA65C1BA23BF801ED05D25A8FD0A06A9846BE3C28B9BA45A2B32BE80ED468E007EB6EFF0EECDA4460A700977B84464631B642135BAB8519248CA0E0 +Out = 5A6D52C19193A6C002D58C15BD2490CAA36550B684A726C33F1A12DFA2D4764FB75EA336823833637765F37547103691B852FAB81BBD74EF6C20BB885AC42946998E74D2B8C2BB75 + +Key = 75E691CF7E511D4B1A114C0E80BC7C7E +In = 7DE080A1683521CEAF78AB4C3160D326A07FF4C6F446A94FEADFC0BC8464EB781D743694734C5938F7D2DE4822EFFF34A82EF0C2E11F92CF1E0B2989786FA990DA3AAEC7FC647675024BDB47F20C67A7 +Out = 1A5002651E1686F56A6BFDD8DC40DA9DCAE7E4773237720BAC8962DC2FEBCAAD885C4A62F13476B303B2700150F5CBA1CA976A753E6971095F175E8BA2D97E1F1C18FEBB0F8658DCE957E65DA18D38D8 + +Key = 5161285DC54A3D9ECB691C0CDF987D33 +In = 739D59F39F57C04D1450926AD161AE7CF1522C4929CB299C2EE03842E3DA7AFD54AF4DEF19867E278678222C85D8901526E62A008D449478FE4249173B6E80980B9F91D09F7F5CA8A174EC73A57AA878E74F0315B6F3E15C +Out = 59E210F2DF601ECB05F4FBAED1077A9AE1B783526DABCB881881BCD103658E03FD6C1D122508DD039470226BA0AA50AA087D40732D77D137DD2CC96824E24C44BA8955D250297C02E3D444F4F1E78F5A02C50C7314CE356C + +Key = 19B8DF4B8C9BEBE46AE4F71FDB4EF5D4 +In = 3A483364A30C28F9B932A11152D741304802030C60453D1E9433823A21F033DF5A6FB43FE9CCB423946DD363F9EEA9F0E60898652E8E4C4B6AB6410B468861CDCE22B3043BBF72520232EB34D1685274A3FDCBFD9753DAD0AE467CF7EE661145 +Out = 11AB2B4CC8CC30311EE2B979C6AF90C5EDF073CA2E483C2F0207E8E95AACC55F0120C9B0DC689A2B645EA1560FEBF3D027F0F24E551205091D04A72657209E814A9DAF3457ED96539FC1CC8937D76E2EB4854313E2C067F86EF889757E014B35 + +Key = 3D29E84526A1D60D177C03632DBF1E96 +In = A9E72827F67035507B5F0747149A73AC2763000470087FD6F8F165FCB872AE7BA58CF568E1D70D28891881F0464207E5FF67CD2A707B71286DA7635085B3B68F9228A646A186C8D09D3E31B56562ACABD0D5AA32F608C54086642AEBB72767643C90B7DC02FF772F +Out = 5AC440B8C9AF2D5843B125711F519D34DACF4D86CDBC856933C96D5B3CEA980E9DEC2F0E2BF6E8EEF38214D59B5562324C009953DCCC4ED2D6C6B55211AC5E0EDC7C8AD3F8760823D55365D84525E09DD3145DB6D700D9BAA4A92F38EAAD8CE33000A0ED72A1FEAF + +Key = 10E1FEA37BE818FD0CC1421E16A3151F +In = D24A21AB1ECBCF2EF83A1FCBC1032EED930FE269AFF8EDCFEE26FB1A2DA9D063EAE522E841024B7FDEDCDD6BAA1126834C996B9FD09654901FA8830C64AB1F5CA3BE896D5E60BE29D08C9E0A4F07956551E618F1FBF46DC8255A4E2F4DC8DE5729CCBB39FAECEA0A4C45F53FCF5C3973 +Out = 2A2A34F1EB3F99FAFADAE4A68CC85799D9EB7B1F0277E71D56FBC395E3A93980B670D36B87153B90B8154EA962C39A049088665EBFE6D43A5E9A04A93F4D683DD509E27BD3AC659E5AEEE8B62EC3037C425EFEC0E726E8E572017940725A794E58817914308832AB59644B03D1155D33 + +Key = 80477A99D76ADDF3DEBEF9E8FF185DFD +In = 9CF0C3E72880B2C3FEB787D84866DB80D4B4EFA60E3708CE6FAF0ECC29EDED0C8D9EB26957F1DF63FD39EB11158DD089B9622D161AA83E0BB921067F77D6F4479B17FB9C9F30C4F56A86EEF38733C8D557053BD4978E41B965CF1F2025402836AC90935E9564BF23F5FC76F29DDBA491446695A82D54514C +Out = 3A8E38AC17AD900742F711491153A7FB93C04F981CF75FB34FC9B28A2C24A81C60AC4585DFE04FC026B6731A8C2404E65DE9FDAFDD32685A3863EC4CC77490F8E0D3ED234152FAEF3C8E1BCE7E4BAFD1171141D5ACE23BB3E5EAB0F20D000371DEF9E831BF716B6AC5EC2313F013766071F3AAD4492FD780 + +Key = 978393BF38701AE612953AE4C060B632 +In = C1BB0B801F25223FCDF8CF13251877AA8472CA6924C0F51F1C968E981CFEF665F99EC57E4C33C3B083D7DC62DC0096B062CBB6DDF4D39DC28843A74E81A5F9558FD9F5F74D3857BF01A341BA443A2440C85CF069A757AA0E1ADD2B67860F3BEA805EAE1316BFD5638C312E96614607B5BD816B55FA16C301B71212B5B1203F2B +Out = D481D95387B075DDB6771A669D3E11AC591A629B53405802F016E710D5E919E195A4553CF83337ABBBD506131F363D2BB5A8D3B542AE8A99B4D4641C373BABFE737C14AC6612FE466D2A83C867F42D4004685B230D3FC1C23D3410D767353A5C523B0B36E0D35D9B3D9605AE9C8402D0F7679A3573F3354E6BE0F2D173355B6B + +Key = 9A4972A00B5C1B22AA07DA8C1C8B8FF9 +In = 0C0627A330788002C9DCDFBBF23F46ECFF4CF793D93D934CC553A64ABAD1DEA3710F775C71D54412BB3B6361B54C5E2DE7244CED9B546D146F20D8730FDD8AA155EAFFBEF34C70BE1F6199F67D88186ED039E00BB88B7DD13F071AA4C309CF92C10DE3882674B5C5C5EDB457F826C2D62724E1AD328CC09FB4113E083E4C4D31717FFA66914890CC +Out = 5AAE35C53504B9DB9CBD7C00B01AF71772BE3E911DC6EBE45C1EBD331DD81CAAE710F9637B2B22C12BD16B0D84F0B41A59BF169938475F56B57347362C7E6EF4F9ABAEC9F44C3BF11BC2D02DD0DB00A8DB780A1D1B399C11485EAAE96E1AF12EDF48B4CF6FCCD343F16CD0565E843EB4FE1DFFC1EE2FA8E0F73839D6F6E131442154A4972F552DC4 + +Key = 8EBCF7F6F9025BD94D2985A4D3982A84 +In = F2DF92A7AF36169DF9F2CE6DAAB0788284FEFC9D1C43619FAE6CB75576EE173DA697A01D96835B357C89B737794D0E5B2C7F02F8E5DB968E2D000AFCFDF9B17BFC8383832A2CA177CBE99385C9314F94977350C2D4B4AC6D37E0EC8F36E666C54011B2ABAD25CA922946A7B0C9FB5AAF54D618BBFE59C1751404200BA90051B5E54F64C7045B72B01681FCC6E7763F8B +Out = F090795579AE3AFE49B96ECD3A8C01D449DA8AD81AEABAC135EB9CBB904647D5B1522B208F325C0597A2294CC1A10164551549B69E96F5AE72DDE9A4656AA533FBD7E98A6E66BE29663176D5621CD21F29494D1CF6D784432B1524BA56BC3E67E9FB4378190268B4DE6BA74B8B2B0E1EA52B75C45FCEA715B8A00B7D2456BCE2B45B192EDC10FE777FE53260F8E25397 + +Key = C2A7EAFAE3BAD26025FBC1EC1F3B1342 +In = EE4C225C44528549B4F609723FB33467DBF135FAAB3F6C82DD9E3383714F39EBB31FA595850389D1BB1C1E9DDC3D1E0439F21B819B3D294B15EF81EA1E95C36E75D20B4C0D7C3765E97E9A2B9E03B5F5D5705DBB35C241779E232B0781EF9A3F371D89E451DC68F6F7E0AC8AEB7F8E41DEE6A0A86ED9195CCF12BDBD820243865FDD31B8D0F33418023E2089BF65A5C9D20E03DD7D4C8287 +Out = 355BDD01480727A7496347973315434AFD0D75AC1AAF3869A461F78EF5E5923A7C4F749F7929C497CDCA398F4CA868A860E0296A952BC115C07B38D5460753D134E8111C0C108136154EBC7A386921F754D1F116F474C4B7DC8B5515ECA301E30D1D4661FF2814621C0CE1CE812B317C94EE900FD23FC2D941504B345B5BCB4DF7CC3A01BD3D759E4A7C4C4FA893B6B230D21FEFFB69C0E4 + +Key = 86014B66CAE76E61371F64A580B3A3F7 +In = FC2B09E77FD6C0DFAFA0EBA6AA058D2357A620E4EFE70E52E8136B5294EBCF97E3DB642E3062EDA1DD93DAF24E97FB14F41C53D38729105BB46DB59507B6152CBF7747537F9FC8A8CDAB5028AEBB26FA8B5E020D7E1D110C159425ADA07B6E2526106DB5C1B4E2F62B5FFDD398EF3581EEA831FC686389C19E679B394A79D24AA34403BAB37A8B313F82878605E027EED34926D390BCFBB1E786153B0379C382 +Out = F330598D81495B8AEFCBEF71B791A872B394E7A472E4E9E4D4C4DAABF7C2EDA0AF52CC162FF5001DF22EB012792A509C25566AD0BEBA50529F015CF3C4E6139C80373604EABA6F7593AF87B31E300A3A2C5B9DC10EB36DE921BDF7E5569BFE8A4155F6F5F272846194E0178B228E15DF6787AD158F0907205FA941D76BA4A4F2C121652806B463CC1DB8BDDE50776BBF19577A25A66B4DC3230870963E53A137 + +Key = 372ADAC63D66E934514CB2E26B388F25 +In = 2642676CAE2461ADAADCE76CB12F9BE1A85DA497B5B6FA3FFFDA136E5ED6E53ABE52AA961D3D12EDA92644D9CCF6EE1C0023744BE75786CE57FCA3102D0E4AEFB3F6CF7E0FC1C74D37DDC4CBF3CD59560DE06209006A55E8C463156B8F1D81C7C9FDC270A39FDBD67F53A19673514569BD75BD747076C2CDBCF51C98995EDFE830CA8372279EA41819DC68ECA82B247653BA8EB10A8F909A762B74D9D46D7BB3E29C725C74504D0D +Out = 20401A5F52C04821DB0609B9113ECE78977DB9A614CAEF283062D84985985C50090D64F5BE66BB90E68D75801900FEBFFEA8BD5790337BB0ED215011E541AE1285FB3B305E05F4A24E2CD6D3A62EE76CA4DDDD2E371A67E36DEA94EA5C26CA1D1B322F249DAD9C5DE435D7704B4F29A7D960EB9582316EC193C97BB5B64BBB2ADE27F250C2BFBDD48D660825EBE99E75C0E4354E0E5B84338E6361A5C9C368F095D3630C3E9878AD + +Key = B4BB2D7C1DCCF12BF555DFBFF33BFA09 +In = 26BA6EF5054908E2CE4618CFABAF79F8D87DA4605B7F33EFA1C6AA0F039E138CCA821C75F0B2D17E52932B25CDCDE78DA2BC77432786E865CB153E0A0C637E9691D08679075095EA47DC18F40435B2DDD071D066F3B2B792FA528C0A64725F2B07981A2FD91F658C49B75317FB963B2BB68430EC9FAAE98963A8EA85F62AD4F77E115D3FD979DB421A773F2454E6AF49BD950550B126921E2FA581EEDB2387EA285D652DA362BBABE6F7D8454074B6C9 +Out = 9CD37096F29ED2C56C7D2842883A79D712F6AB9F5F08AED655CFECAA2F482FF470D74597188C280E8FAA0B19B51B56A4A8B2B8E3ACE48927A61787341F5DC153621C14110710895E4AD3886ACE7599919C985C70A8B9A7891FA43D1CDDB30726A2D5027D77386E5E8B80BD7CBCBAA250269C250A8F2276E052A88997182528B947751DECC3E8555A8D4C6D6C223F7B6D431AE2C7931DB88200DA4D987FA0ADDF0C0C8997B7224E06F9701BFAAB2E99CB + +Key = FB8C5F864EAD033E0F3D427E76B5C9F5 +In = C1EFE0B080811DBEAB17EB4C00E62F695BA71BB8E27006187F6F224F29D83820BEF01EF26D3CD5FF85CD5B005FF0DE9A8795B20F31E4D98A3BAE15B7BFB60FB8642D77C12E488652A26B5E32116AA0F7177D1E3F46C31DFDF212683B08E84C0EE72A15466974FC5024F3A0FA2061F53AAA86B3A29114D165C150D6FBBF0F07645C91CB5C9EFBCB292ACCF7159203BF83A28FD040E92711854CDB4679A6D885FBADD29438BA11E9ECBA68F8BCD4433F7DCC6C263E41C3E64D +Out = 781D45863F3047C63BDB423712F166E4E5D018A6CD05B70E1131622E93BD6E0CB56735B5335001B9B971A671475DF0EDBEC0FAB32DDFD422504A941860C223D86B77EE2A4F7CBC4434738CF7F59059EFC0CFE4693FA9BD553B5EF3C1F311FDB66C8B4117620126768A74227874D9BC89FECA06CEBCEE39528378B1B5915543453E667860D94C0406543B341175650D865D245225B0964BE723516490D8F908DA7B73A72C790A5B6CD6B980D0FF8DEFE9BE0859163D3527D5 + +Key = 4ABBB43F2BF9C69B02AED5D4D82310F2 +In = B863168DAF023E33D00F90F5BD076FA62F3BFADC93F0A1EE0E1466DC87507BE3E0420F884D40511F5C1A6DC912E70F33EC90D52E2F98FBE89EF076E3A95CF011F6ABA8A946B409C196ED86094597D35C548EF84ACAD0CB3E292CFC4D43183F4D97C43BFC5445A5DDF396159F9662D0D844391075E5A209A00CFD49AA86519F7C3DE285D9DD02F3924D0836C725AA0669F3B98C4B42AC893B90F55D4F07B83CAD7F693BF49D72423A369E7FC563D44229CBFB5F7A25EEBB50DBDCA0852851D417 +Out = 3F22A08DF104CB891887000C0B975296A0A736B7D074739DBB7B16100EC96EA30F84438E3C9B6F38063C2C4FD8B39262D828F000B8176D6793F8537598DA976A29228966AF45F698BE394FD0FBFED864BB1B81BCEF8D9FED2BC7FBECEFC31D319D6C54648C9C0ADBB83B18A56E8C1D72DB37FD24EABA87F6C9767E3B3FA4566DA71D03539EB8E558390EFB8B1839AFEBE11FCD2F81774674228FB965D4A78164E57F5348DB47E06C0D2507B9738F3750D1780D49E485B9CF89A7C716F9A628AF + +Key = 8C366409428A56AD49CF09F5C790325F +In = FB669C4A5B01B8808E3A7A08E47D2ECE63202C4F896402163D88BDE3FA02A0C7EA924B808AC430A3A157B09FDA1991A18DE25F842E2DD3A221AD2804660791AE592E60D9991C59D6D0E50CA49F1F4FF5AABA0C81DA2C36EC169B420745357B82201009C2E2EF15853C65647FC93B587E25415AAABB8AAA7B441F8E1616A1DDBA24C83935C5A4755C19719837AC1EFC7275B37E264B1AF004513D53BC94BFF7D6763AB8AEA592FFCE8725BF2CC06C711AA2691475CDCDB82A28ABFBB1D166A20D3563B66060699F16 +Out = EF73A9BB5596BC30BAF024316E5085A71F83CA9C8BBEBA4C0F5EACE57BD0F19A9688590B4F255E048E90EE2F8316885ABBC82BD6F15FD6AD56C3C58D5FE6BF3BBBC6795E4E9D424EB570CA5775B39EF117F4D0337F88E6B3096F0206F89D01F1EEB39A388F42C44CB03AD06A6A4E914D545499852E2EC5F1F35556515FC7D04E884D48D92BB1ED179C485EE5E5B136F81BEDF14ABB843AC9292B80440FDB5CDD50EB573C744AF2444BDFFFD785FE3535F698F446B533FECEFC1ADF7752916B2B77C68F1AD08A77B5 + +Key = 0D852CA9C6CB0FA6A95F2B0D414A6F19 +In = 379AC957E6721F2C33CFA9C8E8FAA85B3AE28E346E99FAFE06C5F2497724D800C332A3DE25424523CBDEBB0EA95AA31C88B8A00ED3CF0E90B42BC1CF690618CC15796E1966AA57067D5B7E172A1F818C1C7EAF58C27E6EB3F647879E9785FC8362210C8E8C458A60AF1CFDBEF698869E3347645C6D9AE7407F8DC7A1F84B20C1CEB17E33320F9BECC4B3E8E450BE9F5956F74CF33F764526F097DFCB63C57C9798F791B471C494062BB6675C374EA7273E69C12B5349172AEED9C66AF0380490B74F2293AA22DA87976580994A5109B5 +Out = 7AE8556DD6A8EE6E86499658479AE39CC400452F06071044CD165FF5C2B85FD59DE4BFEC7FBFE20F578C1E21A53BC896D3FE5D77C7F908FA96A68FADA439645F621ACDDD9E2F351F1E4D87BE5BCA2D6C93584DC331DD623925B630EC01C296F64F71DF0DD92232C7B0A0DB821B1761A442CA73EC3FCBAB386B0FFA35754ED91B113D51CD9239DF73ED46BBE1485075BAAAFAC363F541870AA96EE7F21C4ECDBC0DA9F309B2CAB1C77D6220B2BC9EF5F2319607D7C3D32C9F007C21CCA676872818085C971FFB778138C5398EE372DEC9 + +Key = C071C64B7DBA548A42CF9656521425FB +In = 84B35BBFE1FFE781B931EEA1556DBA23D38673BB229EDBAAEA95A93736104DF3805D496895F105FC5433F698CAC70526A74EB67935788C35D87E6ACB63A285999CB981173BA6EB6F8402F89D4D2DBF0A5DE904D5BDFC4864C6E48B906090DC418E9A91BDA8BE63E3CB341B570EBA6C5095A478C0FF43C062E12FB180D0B74DA39F7B562FFE9F652B3FF4356BA024777AC34D7F84C45FEA5EC21BBAB205C6FF43EC92782BEEFD471DD8703FBD5DE167A829443F5F1EE398475A40049C2AB577B5A6BF2581420F38D22F46142B59C92ED80F44A22A49644843 +Out = 17B0379B31BE60CD613289C2176135F971DDAAC953B76C8B48BA9FFCA0A040EF00E97A320FD19C9D4CB269AC205DCEDA98DB7390992FA4FC567DE5A39ACF08DACE83858E03E3BDE07B75AB74CF4D90DA3FF2B95476F9A81853BFFEBD91450E71E4D5BB5291BEA641F877361112D65E7578390A71CA8778CFACD4D25F71C90D289AD29045358D1DC8E14983E75CCA03F12521969916432CB967202086B62B33AFE1FA5B5A68BD4BF19888922F814577ED0E4F09C50D884A7DAE5B08B2AABFA8FA159BEA131841CB0F3B63F826E36682208F78839D9E84D917 + +Key = BC12C0EA9A1D8C2F0CA4F4683EFB8E38 +In = AC1211AABCB5E081D8C95FDD138A42FD6F1D808E37077D65D8FEAC80791E5D169A32B2F333CED7B84CFA383B430BD7611726230664C2471C0413CE30006872B0707DBDA38F9640D5E376D050DDD5526A3313AD1247B6CE98F1484D9FF0169B7190F8D4CBE10BC03234E3CA2581EEB98DC5969E2EB57A4C5A10DD5B5619D80D5A9B9C3595EAD7E0B5B622A5A2F685D70CD687BEA1876C74A29DE026C1F8F673D66F1171B1633A05393A9896705A8E504BC474083DB285BF8DD893D3D699505345EB97985948DA52A17AEABF279CC28E9793D360E8D707D5C36C0047BDC6ABE83E +Out = 40BF0E1D3B5D92417849BBAE059D7EA6F22D409F5563957BAD0A4398F963AC823AE33A6F6E908AC004E94A5AB9E3E7C4184C94FC90EBFAC6CC70C60FE939453507BB65913FC9A97721A730880EFE22439DF0C516009A06FAE30F6CED63D9CEB707C331D0EDC2945EE3561EDAE176E525E66EEF01E4FE4880F8F7D79A32E45CF71300A262A5F78079C20D7A9EB543D2269579EC077A33EBCFB9289EB85C979951923ED96ADAA2984D6DEB1F5B3FA9CDD859EF877B7594E84B99E3A9D2C8B8F984428D18A1B59EBFB851CB8EF0B4719725CF07D73E580C18B537BE3AFB34186668 + +Key = A114856E299B436E09F437C57B15109B +In = 2D2E50EFC0C6378E1D6BF584C498600F883CB10A49E27325E20A018B0BB3F192C7462F1CF76636CB86F3CE38DBE3A70502A7A6F72EEFB76990773407DA628C11FBEC2E8478EF2F98F0BEDB6733F695CF0158B8CF5AF6097F84116CDF8B973F3B0A6BC863B12EFCEDF0AD18F4755974E9A05E554654115EA2B309DC37D41B7C1C6686C6470A7A528BFD2E8ECA7E28657ABB5BC34532C38365FA1BA9DAA3CEBC85A9F30195E6D4EB52EF8CD243AE7DB1D082501FCA2A93A4A81C4E1DEF5F4E0625BB088D0B2F4C31DC26561179DC3B46DFCACE0E82CA9A05058E2118194F6021CFDBE0D8C1D7B6D41B +Out = A6A0348A6F587D6664381AE45F8A0BC69C51F7BF6C26755452CDDB4F1F101EA2224F61BCDBA8E97067DA55F4BF59A5D7CF12ABCF4DF18B92E4B6921569051F5E70F25698FE0D6C19B891B48A3E03EBD7FE4A79A250A8B5FE6662D4430725AC447B55BBDAFB259B323872B4EFBB452FB968E979006EA49A789F4C3743DBC1306AFBF5A4B1F421C99A3AA07A2E98A47B4DAF2204CECB2AA86FB9AB60125AD0CD94C799CF3EBEC65C6F4F2B864C11F513CEA9D6280CDF16B1F0E1F943A444786E1DCB1851681572ACA9571699B82CE9E5275E6999A1EEB599CC8A0583D11D47938324E95B67407A0D68 + +Key = C722C9F2A15369264DB7F54FEB0207B8 +In = AFC793265B90D53B647275124998999B3D8C91440541DB7E8CB0E8837AEB4653FC35361B55D659148D9F25E3C109B1BB92C037397DA8F91CD5AF0B6EDE7667BFCF1DDCEE76AE83F167D937EB67005D48A9503315476A43A45001F621444C562563DE6901E969F6662249A6BDAB7A638405EA3AC01304FD2DB772CC7AC122CD3D65B749A3F31704910950B642C8E5654DC10B07C614C65A07BDE2AB52196999066284CF0F6EB66CD1A62C29B683A436C5BBC15704688BAB92972421903D53F2072F7B8D53B02B70F63E7A7503207360A4872E04CBADBFEB321BCDDEA5E89419FEDED04000065DF73BE58A79AB5BDF885E +Out = 6CAE06C13E54BB2375E3D3C741E9C61D3813AB63CB157E54FAFD28E9A4D935E57D74032E5E669844D277F211B480F0E54E4F0B09C2242FE1D5EEFF32E1313759A47E7450B55E09C437D1EF3F60A0572134C2D9B5258414BA5D84774D65FE545F1B80E7FC06BD7669D05AFAA2271AEE74F8E0C247070CBA2FFCA62B6CE5BFB0B6E75055F099939AC44FEC6E9A3615FD57B3723119FF14C927BA06DFFA36E91744E035AE7A9F21625D74BB62C41802782201D1043E5B9AE266997FABBB42ED800EA1E2F2A4E78C265E3CBAA9979ED89A8FC6C9F16BC6802A5E7D2D819A7D8357B9C40B5BCC50726EBA3DD0791E11489771 + +Key = BEF7E425E917D067300D40D19AE12ADE +In = 936C9695CF82D4241CAEDA1E8C80DA52CA4837BBDD2158E2CCDAA99EFEC6F1FA29D6ADDD6FE3A660F50FC6C2AE456BF742081FB471A317707C523638AA27DD85621CDED72631C4690A857512265A11C283193BE33BBA6E77EACD56E9DF9541BDC3567814E98F0E6D57D9B25440FB7AB62AD9375B2A96F60C4E4B57AD02F62EAA06793D0C5761369447B9A0621EC2F9AFBE8F52E8720CCF67E4A1BC7285463E8DEAADC248CD8207739F04FD13F72E0A7A0CDDD5EA0B7111582A389C21F499BB4349E8BDFAB0925E4C299773A9A546913D37B7951C9052EE9455391880A77CC66F133FB8AF5CBDDB2433F3F9D52F94A15D8A9143D0729F6D60 +Out = 8144D92331D338C920C0BA0C6B32C6EE28BBCE148F6B56B5D2A12D029734A41B8B4071E4A7601A88E8CEB031DDD38E4588CCAA900E8E23AA1C3D4AAD39FB75B90A8C47ABE3641FC6B04EA1E74FD4B4B9E72310F79D25509B3DCA63BEB093A08F7149A23E0D548DD5C20449C90FB41C88CBB6D1D51D35DE46D4112090926A7948563487E34E7507CCBA9825BB48EA8709239CB49CBC0FC09447570E1FDE99E1316BC24A5CD38E53F613152BA9BAFEB065AE30CD73DADEF90E4E907C0E55EA0488B9CDD20926B3893D8429E4C9FCEA17087B6933064976F2503ACD2D8D0DF4CF6F10BFEC0C914B0C46E6FF575464FCEB1EDC01AFBE446F77AC + +Key = 19796BDCABF22920277106075D0E0EB0 +In = 23D35E037CBBA0A76A46DD433B547E17B54A81782A51D13829BA301250ECBEB0EB598F76BE470D8411E7E58516873B4C9BB87E4B41C4DA3BB941C3F8A9EEFAA507D30948692ADD5E53AF8EF3CE42D6944D8E2994F45F4090B8934BCB09B94B3BF04726F42B00ECF9D9893BAAABFAF712E022F82317CFEC8AAEB7242BAADEF7526833C2EA481816856BD423CC652CC04301C7212BBE69F251BEBFCACAF0F12A19F99EC4A88E4381403B24322133373ABE881C0F97D706EE4CBF3F5F7E69B8624F50270E508ED0487B0B8116BE1AF904C23B4F704BCB8AF92B118A912B5CD0D759C3F73A6331E1337B693B7EA65A017CB62C51A4E4AC7C6AB9530DE747FFCEF27C +Out = D968A79959F5DCB6486FE846504AC0E8753E56410795AB9637BA84EDD9AFD692DA253ACFDE1FCEF40280D30BAD93AF2386B755835AD1CB18D472DAF37D7C69109DE9898E09C69DD8D5DAD6D6640246B28F905FC0B1329D44E9AD2DD4D5D467862AE364CE7A81D5433B00CAF11B9A1D7D54910CB2B01888348ED423A2BB40CE0CC23210CE10CB9B123AAA8F41A3B25114398160C0E9241CEF67F52CC419AD31E5E04C4CE91716ED99702AE69E7A1D501C47A53F81E611827C7694E9B4B9446F263FF1170F4CD70B432EFEF97F0916CC6BA81A8E11EC996526E9202F6910FE8A427CD0BC8C7BFA23D0DCE30FDD6C2F36B582A3C9B698BC5CC6CEB3F951B26D586B diff --git a/src/tests/data/kdf/sp800_108_ctr.vec b/src/tests/data/kdf/sp800_108_ctr.vec index 001acf689..7d8087fd1 100644 --- a/src/tests/data/kdf/sp800_108_ctr.vec +++ b/src/tests/data/kdf/sp800_108_ctr.vec @@ -1,3 +1,5 @@ +# Test vectors generated with BouncyCastle + [SP800-108-Counter(HMAC(SHA-160))] OutputLen = 2 Salt = 876F7274958C9F920019 diff --git a/src/tests/data/kdf/sp800_108_fb.vec b/src/tests/data/kdf/sp800_108_fb.vec index e10d3e1c8..5928bfcaa 100644 --- a/src/tests/data/kdf/sp800_108_fb.vec +++ b/src/tests/data/kdf/sp800_108_fb.vec @@ -1,3 +1,5 @@ +# Test vectors generated with BouncyCastle + [SP800-108-Feedback(HMAC(SHA-160))] OutputLen = 2 Salt = 0976FDEC7817D94D60C4E0C9091D82E38BCFC58D7FFF0829A13D1B4455B8 diff --git a/src/tests/data/kdf/sp800_108_pipe.vec b/src/tests/data/kdf/sp800_108_pipe.vec index 6889a19cc..7b00337d4 100644 --- a/src/tests/data/kdf/sp800_108_pipe.vec +++ b/src/tests/data/kdf/sp800_108_pipe.vec @@ -1,3 +1,5 @@ +# Test vectors generated with BouncyCastle + [SP800-108-Pipeline(HMAC(SHA-160))] OutputLen = 2 Salt = B65A30885B0849C7099B diff --git a/src/tests/data/kdf/sp800_56c.vec b/src/tests/data/kdf/sp800_56c.vec index b1f96bd6d..a441fd5bd 100644 --- a/src/tests/data/kdf/sp800_56c.vec +++ b/src/tests/data/kdf/sp800_56c.vec @@ -1,3 +1,7 @@ +# Generated using PyCryptodome +# it implements the very similar HKDF from RFC 5869, +# which was slightly modified to be equivalent to SP800-56C + [SP800-56C(HMAC(SHA-160))] OutputLen = 2 Salt = 97ca00eac481e8b3556a diff --git a/src/tests/data/modes/ecb.vec b/src/tests/data/modes/ecb.vec deleted file mode 100644 index f8a02ae64..000000000 --- a/src/tests/data/modes/ecb.vec +++ /dev/null @@ -1,418 +0,0 @@ - -[AES-128/ECB/NoPadding] -Key = 00010203050607080A0B0C0D0F101112 -Nonce = -In = D8F532538289EF7D06B506A4FD5BE9C9FD7A929E0FD917686D9520ED236A276D69E63C821F9DE0BF23CF1D19C7374FD1C3139DE2E1BA4693C3E9D29D774C2FF469E63C821F9DE0BF23CF1D19C7374FD1C3139DE2E1BA4693C3E9D29D774C2FF4D8F532538289EF7D06B506A4FD5BE9C9FD7A929E0FD917686D9520ED236A276DD8F532538289EF7D06B506A4FD5BE9C9C3139DE2E1BA4693C3E9D29D774C2FF4 -Out = FD7A929E0FD917686D9520ED236A276D69E63C821F9DE0BF23CF1D19C7374FD1C3139DE2E1BA4693C3E9D29D774C2FF46BA2DCF84C0E7E4D75CB53AD11BA76D6C3139DE2E1BA4693C3E9D29D774C2FF46BA2DCF84C0E7E4D75CB53AD11BA76D6FD7A929E0FD917686D9520ED236A276D69E63C821F9DE0BF23CF1D19C7374FD1FD7A929E0FD917686D9520ED236A276D6BA2DCF84C0E7E4D75CB53AD11BA76D6 - -[Serpent/ECB/NoPadding] -Key = 00000000000000000000000000000000 -Nonce = -In = D29D576FCEA3A3A7ED9099F29273D78E2D62A890CEA3A3A7ED9099F29273D78ED29D576F315C5C58ED9099F29273D78E2D62A890315C5C58ED9099F29273D78ED29D576FCEA3A3A7126F660D9273D78E2D62A890CEA3A3A7126F660D9273D78ED29D576F315C5C58126F660D9273D78E2D62A890315C5C58126F660D9273D78ED29D576FCEA3A3A7ED9099F26D8C28712D62A890CEA3A3A7ED9099F26D8C2871D29D576F315C5C58ED9099F26D8C28712D62A890315C5C58ED9099F26D8C2871D29D576FCEA3A3A7126F660D6D8C28712D62A890CEA3A3A7126F660D6D8C2871D29D576F315C5C58126F660D6D8C28712D62A890315C5C58126F660D6D8C2871AA26D561F567520E8AE47528C24C18D731A2193D9A97FED6922B17AAA6372B74BE5DEBD559E303C9C92B174A5107BBFEB626D8F65EDCCDF3AEE475C8A183772241DDE7C1F1631F5FDED4F42746471BD651D238BA86176EFE39E4695AAEB73B52EA5926CADAD8018962E469BA920CB8BF1EA9062E4D9CEDD5FAD4F4C7990367A4B966E5C5D2277288C61B96A559CC84AFB6A6583C5AACFCD6212B0BD8AEF3C6A9A11DDBD175639341052B0B384678D8D9352299B71DD880E29D1B96452DB86540B2288B968AE8B08648D1CE9606FD992D717EB02EB81A2E939D54ACA91087112D0D809C5EE82F477EBA7B956DBB23463B0F0190D616F5294112FFB7884E8B37F941BA1B505386B7428B88338188F7E718A3348230BF5CFA552F88D22463D9703A115351622E016BCA26918D17E13225F67EE4E3F2C46FE52ECBDA044C585717DC563A8403FF5309D62370B1DCF5A11EDD2F7D73602B70CD2553E44C1D3F170126155BBD9BE3A965B345E834718F651CEF6CC65E8C5C566E894817350F497816F1EEFA51FC91FEBB6E9F8CB141CC0EB6AF3C6F8380CBD3C996167F2F0E90E71B756C87EB62A4975356B28DCBF6A64A0BD107206D48FE6DBE19D50314B90AC87B8335706F9B26007071AD8105CFAA1C1E2FF7FEAE5CEC4D11477F24E6B2009068703C0E29E2950F2AC2DACD63DEEB5C7EFA9FDB9F3B740563D5518287DC981FC9CB46D4B5A5A86FEC08FE70D18297DCF51072DDBE038DA040EBB12C509F5940A212DDEB59F02132BE4581FC23EABAA960D6341D9352E36DFD6E4EAF0F6F439BC8CE73A9AB3164FF30350F2DC08E939A104D6DF0C2C28F8E2D44468A61278BB6B4294DAE45AE0CAA032FC97CD4D8C57FB83BBA8AFCAE22070BC882D3A42B38A09E65 -Out = B2288B968AE8B08648D1CE9606FD992D717EB02EB81A2E939D54ACA91087112D0D809C5EE82F477EBA7B956DBB23463B0F0190D616F5294112FFB7884E8B37F941BA1B505386B7428B88338188F7E718A3348230BF5CFA552F88D22463D9703A115351622E016BCA26918D17E13225F67EE4E3F2C46FE52ECBDA044C585717DC563A8403FF5309D62370B1DCF5A11EDD2F7D73602B70CD2553E44C1D3F170126155BBD9BE3A965B345E834718F651CEF6CC65E8C5C566E894817350F497816F1EEFA51FC91FEBB6E9F8CB141CC0EB6AF3C6F8380CBD3C996167F2F0E90E71B756C87EB62A4975356B28DCBF6A64A0BD107206D48FE6DBE19D50314B90AC87B8335706F9B26007071AD8105CFAA1C1E2FF7FEAE5CEC4D11477F24E6B2009068703C0E29E2950F2AC2DACD63DEEB5C7EFA9FDB9F3B740563D5518287DC981FC9CB46D4B5A5A86FEC08FE70D18297DCF51072DDBE038DA040EBB12C509F5940A212DDEB59F02132BE4581FC23EABAA960D6341D9352E36DFD6E4EAF0F6F439BC8CE73A9AB3164FF30350F2DC08E939A104D6DF0C2C28F8E2D44468A61278BB6B4294DAE45AE0CAA032FC97CD4D8C57FB83BBA8AFCAE22070BC882D3A42B38A09E6558A51ED82169DE7027CBE72452626CA3FF6BBF2FB2C574EC9D5656505B51688047AEA89DBBB5C4EBE819C5BDFDAB16033D2FE7D01071373624D99845D90E32C1708C609C4E75BE40D8DE77F8EA78C2CC98852792C22E971F29C2E125247FB43CAD1FD857DE9B8016C5971FFF86AD399ED669FEF7481FD73B9A45B1CFFE9C556DAE9A816916FB1F5822B2CEC8986F6E5B156775D0F6F432D57D351C62A24AFE63AE812270F7416D05E153E5AB703DCD3FF320F6AD3D00647C23F08699E0EE9F5EDDB3C717C2A6D3E58D38269DBA0243926D64CCD92B1101086DD3F0DDB73312A31D5F5EA0FD18AB84E242C96FFCC222F9FE12D5B15F5A3C365E9FF3248FB43B385A0F73507F49A08E68952BEE09DC7D35E7B29A44C8970624CB3A93DA4AE7E49835AE41A5BE2EE591750FF9A7D431B1EE8A69099E689A06324AA0AE431ACAE762FD3B90A8B269090A4CEEA076CF1EB7A580DEDE896BED63917384B1C5E18B7B57A7EB6B127A7A32898989E32CFF9A46BF6A62268500E53AD8A5FBC95226266BD9AAE1BA501274C49A7A7EC67D7577114B7707DAB9D066AF086C09E7DD4116CEA6EE25DA9A65EF05A31ED0BDF56D525EC8968D1D01AF7165C5AEAC76BD367A575A - -[IDEA/ECB/NoPadding] -Key = 00010002000300040005000600070008 -Nonce = -In = 000000010002000301020304050607080019324B647D96AFF5202D5B9C671B08FAE6D2BEAA96826E0A141E28323C4650050A0F14191E2328050A0F14191E2328000000010002000301020304050607080019324B647D96AFF5202D5B9C671B08FAE6D2BEAA96826E0A141E28323C4650050A0F14191E2328050A0F14191E2328 -Out = 11FBED2B01986DE5540E5FEA18C2F8B19F0A0AB6E10CED78CF18FD7355E2C5C585DF52005608193D2F7DE750212FB7347B7314925DE59C097B7314925DE59C0911FBED2B01986DE5540E5FEA18C2F8B19F0A0AB6E10CED78CF18FD7355E2C5C585DF52005608193D2F7DE750212FB7347B7314925DE59C097B7314925DE59C09 - -[DES/ECB/NoPadding] -Key = 0113B970FD34F2CE -Nonce = -In = 059B5E0851CF143A -Out = 86A560F10EC6D85B - -Key = 0123456789ABCDEF -Nonce = -In = 4E6F772069732074 -Out = 3FA40E8A984D4815 - -[DES/ECB/PKCS7] -Key = 02D863A4885D417A -Nonce = -In = -Out = 705FDF4DC7ABFBFC - -Key = 05ADD235B01BBDA7 -Nonce = -In = FA -Out = 2281AC7CFA703BA9 - -Key = 93F04843AFC3A191 -Nonce = -In = B895 -Out = 8C3BF9AB9D16C8CF - -Key = 1F4E2C013314B55A -Nonce = -In = 8E97DE -Out = BE38BD2AFE108D2A - -Key = 0F59C05186431E13 -Nonce = -In = C1DAE88E -Out = 998341E8B0CCE82E - -Key = E68BF7B98D61FED0 -Nonce = -In = A6E0360E88 -Out = F5E88FCC387B8883 - -Key = AE3AB00A0BA38BE0 -Nonce = -In = 55E67A79F043 -Out = A868B107BD96F35C - -Key = 9B661C7A536AFC6D -Nonce = -In = D77C93B63D6D5B -Out = 19DA07A34FA683C4 - -Key = 8E1C689280575F05 -Nonce = -In = 328D09508E747AE1 -Out = 9C75845C6BFF94438EB7E7E4C77342F0 - -Key = EB4A6B437572E1E7 -Nonce = -In = 421D4BDC3869E59F07 -Out = 8DF60DC27A2E2EE23360BE31343FCBDB - -Key = FFE58726B90C9F97 -Nonce = -In = 160E525583C3E4FBC4FE -Out = 9B649660DFE5B875CD81180AD627943F - -Key = 560EE1ED2CC2BFFB -Nonce = -In = E873B3C2B31130719E6469 -Out = 6E33AE2AF48CC39697800A3AA357CC5E - -Key = 012A7DE9CBFBD230 -Nonce = -In = 405915ADC0111EB8AF225612 -Out = 569BE1F2AE91785B0634F8DD4EC1DFF2 - -Key = 3D5D56CA2E8E359C -Nonce = -In = E923C535186730F309CDEA6DEA -Out = 846D7314F76E00902054BD2B2AE1F580 - -Key = 2AD63A5312BF4259 -Nonce = -In = 116053A5820F9D36650EEF49A05B -Out = 9BD56C43036485B648EFE6D31E69F0C6 - -Key = 7FF12D4D8A9EF138 -Nonce = -In = B6DCD40077FE89138B5A2ED35E1B3D -Out = 2FBE419BADA6D4BF3F6C7BB2A1AAC329 - -Key = F71A3B1AABD660BD -Nonce = -In = 08F0AA208F8A06C6292838A8CEE9104E -Out = 44BFCA2722D274504AF482E9261CDB7B16918BE77A461B3B - -Key = 1ED8B08898872631 -Nonce = -In = 878412F6255FF4360A22772711289FD351 -Out = 9C92FDDE178D3B6C895AAD1B8DC886176910B021D5B3AA77 - -Key = 0DCB3527035253A5 -Nonce = -In = 1399A0CD9F2778BCFBA9C0F7E7C89CA069E3 -Out = 5972F89D8C161DD30A409BCDBF43B20BB104E8A293C48FDD - -Key = BF4B260909243B2F -Nonce = -In = EA1CC272D3725E4C5DC56079FA3C9F26A1373A -Out = D1B2FCC83CBF11E022C058FCB988CBBBC3843517F5E9D900 - -Key = 5D869F3486DFE1A1 -Nonce = -In = 098DD47EA5784D307C115824CFC3443983FDF58B -Out = 77DFAE7F46AF6DB0D0E5775859943E2875854A680B54B59B - -[DES/ECB/OneAndZeros] -Key = E7BADA575103632A -Nonce = -In = -Out = 09B0A56E79B07C38 - -Key = 06779EACFBA84CFC -Nonce = -In = 96 -Out = C602F30C18C2B878 - -Key = 09EEAA55C12DBFED -Nonce = -In = 6EE7 -Out = 5E9FCE6A89418AEA - -Key = 79C5B2870123FA92 -Nonce = -In = 665672 -Out = 85589647B376B1D1 - -Key = 37EC3B88DF82E1F3 -Nonce = -In = 7F862990 -Out = ABCEF68C99607B22 - -Key = 0BD2E04EC57814A1 -Nonce = -In = 39E551A9F1 -Out = 04F6D20B0A25B97C - -Key = 8900F77C54E909C3 -Nonce = -In = 52BD5DAD29B0 -Out = 0828E5AF2A1E1157 - -Key = D5E02CC281CD647B -Nonce = -In = 49EF95ABD932F8 -Out = A3325FBF67FE8F22 - -Key = C4E91F2F3EEC7639 -Nonce = -In = B0F0218A6C30542F -Out = E8045C90741ECCE8F90B5469B2E3B359 - -Key = AF593C04EDE5F7E2 -Nonce = -In = 80EE077361737B995C -Out = F2E9AD2163C0665263CD11C7D976260F - -Key = 77B77F440177BF65 -Nonce = -In = 3BE81FFC61B21BFC81D6 -Out = 59EBA86DB5734577B9E665C3D8BF65AF - -Key = B1E69181A32E7CB1 -Nonce = -In = 3EC3AF047C2817138C818A -Out = B8C17B79CB5160EE4612CB5639D72AC8 - -Key = D6492B1E5A936965 -Nonce = -In = 0133FFE3ECDE48F98D3BDBD4 -Out = 8CBFF36A7B691F168AA2D93A9360DFA5 - -Key = 404B2DC43EBF706D -Nonce = -In = 638A220840B1ACBC24CE4F8B5A -Out = F7A3E8DF04252727E4056A5AF9392DEB - -Key = 8188847D3F21BB71 -Nonce = -In = 70197E5EE1D774B11005E8700740 -Out = 8A8A81862C313C7F904D86B953A6E5FB - -Key = EE97A705E4E375C8 -Nonce = -In = 9EB11AB4E97D026703BFD0645108E9 -Out = D7D02FEC752ACD59B235441A4D6682E7 - -Key = A1B692CE93547EC4 -Nonce = -In = 87F1A7ED6D8C4AD56AB716BC8E02D8DB -Out = A6BEBCDEB9285A54EBCEF6F94142A60C0E5D90CCA6D256E3 - -Key = 824BE4D31F8FF51A -Nonce = -In = 5448723839EA0910C29931F5AE6BA9423B -Out = AA328F5083DBED23B18CD35C4B4B185714DDDB02E81214AE - -Key = 91B2A69AE61A53A7 -Nonce = -In = F454E24EFF899FA825534965855D2B1D03E5 -Out = 27D077F2B382CD8C6520346DB77D83D91BD5B08882203858 - -Key = E43579BA4E10BD39 -Nonce = -In = 8C4BCB186170411186D2A0496051E0988FC83B -Out = E1C1D7EF18964E2EAFF84169252F94EE315209D5BC151241 - -Key = 346ADDF6AE9E62D5 -Nonce = -In = 90CBEFA6E4F3D57BE288197E3E1C2055CE07979B -Out = 37860F65AED6EE5312E3FEC4F2CF948A3CFCB27092A7B3C8 - -Key = 3C6A1A7DEE4FF813 -Nonce = -In = 9A5476706A45500C9AD6AFBA73E68E0355C11DFABD -Out = ADC2FACDD08D2AF9CB00E22209C109D0D39BDF9EBC1200E3 - -Key = D584B755C7F2E8F3 -Nonce = -In = 9EFBCC5E45E15F83D4A62995F4F8CAB036A63F1B18CD -Out = 2D9C371F7CD55E7A95B2042A91C9B10025078FF0070EBC62 - -Key = 35732A4D581F153B -Nonce = -In = 3758CF70B2A1A36BEB273545809B35C92202124A30A113 -Out = C728B4B0F49233489B0453CD81FE8C07C68BD17661F75523 - -Key = 58780533BD9EEDBD -Nonce = -In = 00E0D8C19605363653DFA5F778DAF9E959CBF9BB7E4D3245 -Out = BB44D4E603A6CD1EBB27E47FF7AD9F163420E58B97F1C7FF975B521917E7879B - -[XTEA/ECB/NoPadding] -Key = DD0C8719A8DA117DD9D1DAA189E65654 -Nonce = -In = E197D59E064818B7C8AD72C29E227E09 -Out = 04CD161E422154E5BCA5249582B9D4C0 - -Key = D8C8ACF6B4B68A837639320798994979 -Nonce = -In = AE53AA320088B4042EAAEE3649FE6E36445696F01CA40D3C -Out = A3B303C42178F97F719449529D51511491B41EB70E6101C6 - -Key = 24059EA6D8A9F0CA678ED6680362596F -Nonce = -In = 655A6B1D6970ABA078819E5AE1D08471A0E01E0A5C64E612504F4BD9BE4A8AE8 -Out = 7DB966E1A2B7C0E8EAA9D308EF89652A5857461D100DD0CEF9C6FE7BB4DFE33A - -Key = 2434D48F17E0A7D91F255FCE60F3D6EA -Nonce = -In = F3B1BB81C053DB02A8515885CA6DF124AB04927D2AAF6F0032BF17B4B437E1F2C7D82F89BAD898DF -Out = 215D5ABF53C4AA0D7571A0D9D05C3B6D33D65BF35EFFA4778FF59DEE90900ACDD4FC6645368A294F - -Key = 18C1E1EB3925EEC61559DB74EC99491B -Nonce = -In = 06F0A1AD9F9EAA665044D0A2EFA10ABC30F7FBA3FC47C6AE1947B7E9B47733547E5C843DAC59D09393835061D834971E -Out = 066309B116A6692F279F2526FD284E75479BF7FB5F63096AD7108CFB0DB39062A2627594F098F0BF5A3B4C67CF29E993 - -Key = 5258617DB39A2968B1EB02565A2BDD1D -Nonce = -In = 2FA1106E95056E070352666F059A72DF6CC949BB3161D5FFD8FE46451444D096BBD606B0BD443189AF001E5BBBA134DB1FEA7AE9B4587438 -Out = 1DF05B34A733F83B7DA1F194507904CDA99C374174AAB472CC598E06960263BD9DD0EFA2F4C14CC8AF4039A55EC00125766D25FBB7139081 - -Key = C4A02982C1291093144C64DA1E7E3D67 -Nonce = -In = E6ABE28FD1E9392CFC65978D586D31D344140673E345D6AA06C75E1C03E4E314831EB94ABCAF6B23F2C34670A79500C6142EE722FD7E408D751DCB30E5C63F5D -Out = 3EC6FE802F4EAA740DDF34EB79798F458049FE09190D12455EDD6129BAE85D22FF4E96AEB59DB9413DC24D41730454F65C443C819265B4CDBFB87F5ADDE7F4EA - -Key = 58B61987700468A366178595E20A365A -Nonce = -In = 213595590E62A55F241E3D4CFCA65C1BA23BF801ED05D25A8FD0A06A9846BE3C28B9BA45A2B32BE80ED468E007EB6EFF0EECDA4460A700977B84464631B642135BAB8519248CA0E0 -Out = 5A6D52C19193A6C002D58C15BD2490CAA36550B684A726C33F1A12DFA2D4764FB75EA336823833637765F37547103691B852FAB81BBD74EF6C20BB885AC42946998E74D2B8C2BB75 - -Key = 75E691CF7E511D4B1A114C0E80BC7C7E -Nonce = -In = 7DE080A1683521CEAF78AB4C3160D326A07FF4C6F446A94FEADFC0BC8464EB781D743694734C5938F7D2DE4822EFFF34A82EF0C2E11F92CF1E0B2989786FA990DA3AAEC7FC647675024BDB47F20C67A7 -Out = 1A5002651E1686F56A6BFDD8DC40DA9DCAE7E4773237720BAC8962DC2FEBCAAD885C4A62F13476B303B2700150F5CBA1CA976A753E6971095F175E8BA2D97E1F1C18FEBB0F8658DCE957E65DA18D38D8 - -Key = 5161285DC54A3D9ECB691C0CDF987D33 -Nonce = -In = 739D59F39F57C04D1450926AD161AE7CF1522C4929CB299C2EE03842E3DA7AFD54AF4DEF19867E278678222C85D8901526E62A008D449478FE4249173B6E80980B9F91D09F7F5CA8A174EC73A57AA878E74F0315B6F3E15C -Out = 59E210F2DF601ECB05F4FBAED1077A9AE1B783526DABCB881881BCD103658E03FD6C1D122508DD039470226BA0AA50AA087D40732D77D137DD2CC96824E24C44BA8955D250297C02E3D444F4F1E78F5A02C50C7314CE356C - -Key = 19B8DF4B8C9BEBE46AE4F71FDB4EF5D4 -Nonce = -In = 3A483364A30C28F9B932A11152D741304802030C60453D1E9433823A21F033DF5A6FB43FE9CCB423946DD363F9EEA9F0E60898652E8E4C4B6AB6410B468861CDCE22B3043BBF72520232EB34D1685274A3FDCBFD9753DAD0AE467CF7EE661145 -Out = 11AB2B4CC8CC30311EE2B979C6AF90C5EDF073CA2E483C2F0207E8E95AACC55F0120C9B0DC689A2B645EA1560FEBF3D027F0F24E551205091D04A72657209E814A9DAF3457ED96539FC1CC8937D76E2EB4854313E2C067F86EF889757E014B35 - -Key = 3D29E84526A1D60D177C03632DBF1E96 -Nonce = -In = A9E72827F67035507B5F0747149A73AC2763000470087FD6F8F165FCB872AE7BA58CF568E1D70D28891881F0464207E5FF67CD2A707B71286DA7635085B3B68F9228A646A186C8D09D3E31B56562ACABD0D5AA32F608C54086642AEBB72767643C90B7DC02FF772F -Out = 5AC440B8C9AF2D5843B125711F519D34DACF4D86CDBC856933C96D5B3CEA980E9DEC2F0E2BF6E8EEF38214D59B5562324C009953DCCC4ED2D6C6B55211AC5E0EDC7C8AD3F8760823D55365D84525E09DD3145DB6D700D9BAA4A92F38EAAD8CE33000A0ED72A1FEAF - -Key = 10E1FEA37BE818FD0CC1421E16A3151F -Nonce = -In = D24A21AB1ECBCF2EF83A1FCBC1032EED930FE269AFF8EDCFEE26FB1A2DA9D063EAE522E841024B7FDEDCDD6BAA1126834C996B9FD09654901FA8830C64AB1F5CA3BE896D5E60BE29D08C9E0A4F07956551E618F1FBF46DC8255A4E2F4DC8DE5729CCBB39FAECEA0A4C45F53FCF5C3973 -Out = 2A2A34F1EB3F99FAFADAE4A68CC85799D9EB7B1F0277E71D56FBC395E3A93980B670D36B87153B90B8154EA962C39A049088665EBFE6D43A5E9A04A93F4D683DD509E27BD3AC659E5AEEE8B62EC3037C425EFEC0E726E8E572017940725A794E58817914308832AB59644B03D1155D33 - -Key = 80477A99D76ADDF3DEBEF9E8FF185DFD -Nonce = -In = 9CF0C3E72880B2C3FEB787D84866DB80D4B4EFA60E3708CE6FAF0ECC29EDED0C8D9EB26957F1DF63FD39EB11158DD089B9622D161AA83E0BB921067F77D6F4479B17FB9C9F30C4F56A86EEF38733C8D557053BD4978E41B965CF1F2025402836AC90935E9564BF23F5FC76F29DDBA491446695A82D54514C -Out = 3A8E38AC17AD900742F711491153A7FB93C04F981CF75FB34FC9B28A2C24A81C60AC4585DFE04FC026B6731A8C2404E65DE9FDAFDD32685A3863EC4CC77490F8E0D3ED234152FAEF3C8E1BCE7E4BAFD1171141D5ACE23BB3E5EAB0F20D000371DEF9E831BF716B6AC5EC2313F013766071F3AAD4492FD780 - -Key = 978393BF38701AE612953AE4C060B632 -Nonce = -In = C1BB0B801F25223FCDF8CF13251877AA8472CA6924C0F51F1C968E981CFEF665F99EC57E4C33C3B083D7DC62DC0096B062CBB6DDF4D39DC28843A74E81A5F9558FD9F5F74D3857BF01A341BA443A2440C85CF069A757AA0E1ADD2B67860F3BEA805EAE1316BFD5638C312E96614607B5BD816B55FA16C301B71212B5B1203F2B -Out = D481D95387B075DDB6771A669D3E11AC591A629B53405802F016E710D5E919E195A4553CF83337ABBBD506131F363D2BB5A8D3B542AE8A99B4D4641C373BABFE737C14AC6612FE466D2A83C867F42D4004685B230D3FC1C23D3410D767353A5C523B0B36E0D35D9B3D9605AE9C8402D0F7679A3573F3354E6BE0F2D173355B6B - -Key = 9A4972A00B5C1B22AA07DA8C1C8B8FF9 -Nonce = -In = 0C0627A330788002C9DCDFBBF23F46ECFF4CF793D93D934CC553A64ABAD1DEA3710F775C71D54412BB3B6361B54C5E2DE7244CED9B546D146F20D8730FDD8AA155EAFFBEF34C70BE1F6199F67D88186ED039E00BB88B7DD13F071AA4C309CF92C10DE3882674B5C5C5EDB457F826C2D62724E1AD328CC09FB4113E083E4C4D31717FFA66914890CC -Out = 5AAE35C53504B9DB9CBD7C00B01AF71772BE3E911DC6EBE45C1EBD331DD81CAAE710F9637B2B22C12BD16B0D84F0B41A59BF169938475F56B57347362C7E6EF4F9ABAEC9F44C3BF11BC2D02DD0DB00A8DB780A1D1B399C11485EAAE96E1AF12EDF48B4CF6FCCD343F16CD0565E843EB4FE1DFFC1EE2FA8E0F73839D6F6E131442154A4972F552DC4 - -Key = 8EBCF7F6F9025BD94D2985A4D3982A84 -Nonce = -In = F2DF92A7AF36169DF9F2CE6DAAB0788284FEFC9D1C43619FAE6CB75576EE173DA697A01D96835B357C89B737794D0E5B2C7F02F8E5DB968E2D000AFCFDF9B17BFC8383832A2CA177CBE99385C9314F94977350C2D4B4AC6D37E0EC8F36E666C54011B2ABAD25CA922946A7B0C9FB5AAF54D618BBFE59C1751404200BA90051B5E54F64C7045B72B01681FCC6E7763F8B -Out = F090795579AE3AFE49B96ECD3A8C01D449DA8AD81AEABAC135EB9CBB904647D5B1522B208F325C0597A2294CC1A10164551549B69E96F5AE72DDE9A4656AA533FBD7E98A6E66BE29663176D5621CD21F29494D1CF6D784432B1524BA56BC3E67E9FB4378190268B4DE6BA74B8B2B0E1EA52B75C45FCEA715B8A00B7D2456BCE2B45B192EDC10FE777FE53260F8E25397 - -Key = C2A7EAFAE3BAD26025FBC1EC1F3B1342 -Nonce = -In = EE4C225C44528549B4F609723FB33467DBF135FAAB3F6C82DD9E3383714F39EBB31FA595850389D1BB1C1E9DDC3D1E0439F21B819B3D294B15EF81EA1E95C36E75D20B4C0D7C3765E97E9A2B9E03B5F5D5705DBB35C241779E232B0781EF9A3F371D89E451DC68F6F7E0AC8AEB7F8E41DEE6A0A86ED9195CCF12BDBD820243865FDD31B8D0F33418023E2089BF65A5C9D20E03DD7D4C8287 -Out = 355BDD01480727A7496347973315434AFD0D75AC1AAF3869A461F78EF5E5923A7C4F749F7929C497CDCA398F4CA868A860E0296A952BC115C07B38D5460753D134E8111C0C108136154EBC7A386921F754D1F116F474C4B7DC8B5515ECA301E30D1D4661FF2814621C0CE1CE812B317C94EE900FD23FC2D941504B345B5BCB4DF7CC3A01BD3D759E4A7C4C4FA893B6B230D21FEFFB69C0E4 - -Key = 86014B66CAE76E61371F64A580B3A3F7 -Nonce = -In = FC2B09E77FD6C0DFAFA0EBA6AA058D2357A620E4EFE70E52E8136B5294EBCF97E3DB642E3062EDA1DD93DAF24E97FB14F41C53D38729105BB46DB59507B6152CBF7747537F9FC8A8CDAB5028AEBB26FA8B5E020D7E1D110C159425ADA07B6E2526106DB5C1B4E2F62B5FFDD398EF3581EEA831FC686389C19E679B394A79D24AA34403BAB37A8B313F82878605E027EED34926D390BCFBB1E786153B0379C382 -Out = F330598D81495B8AEFCBEF71B791A872B394E7A472E4E9E4D4C4DAABF7C2EDA0AF52CC162FF5001DF22EB012792A509C25566AD0BEBA50529F015CF3C4E6139C80373604EABA6F7593AF87B31E300A3A2C5B9DC10EB36DE921BDF7E5569BFE8A4155F6F5F272846194E0178B228E15DF6787AD158F0907205FA941D76BA4A4F2C121652806B463CC1DB8BDDE50776BBF19577A25A66B4DC3230870963E53A137 - -Key = 372ADAC63D66E934514CB2E26B388F25 -Nonce = -In = 2642676CAE2461ADAADCE76CB12F9BE1A85DA497B5B6FA3FFFDA136E5ED6E53ABE52AA961D3D12EDA92644D9CCF6EE1C0023744BE75786CE57FCA3102D0E4AEFB3F6CF7E0FC1C74D37DDC4CBF3CD59560DE06209006A55E8C463156B8F1D81C7C9FDC270A39FDBD67F53A19673514569BD75BD747076C2CDBCF51C98995EDFE830CA8372279EA41819DC68ECA82B247653BA8EB10A8F909A762B74D9D46D7BB3E29C725C74504D0D -Out = 20401A5F52C04821DB0609B9113ECE78977DB9A614CAEF283062D84985985C50090D64F5BE66BB90E68D75801900FEBFFEA8BD5790337BB0ED215011E541AE1285FB3B305E05F4A24E2CD6D3A62EE76CA4DDDD2E371A67E36DEA94EA5C26CA1D1B322F249DAD9C5DE435D7704B4F29A7D960EB9582316EC193C97BB5B64BBB2ADE27F250C2BFBDD48D660825EBE99E75C0E4354E0E5B84338E6361A5C9C368F095D3630C3E9878AD - -Key = B4BB2D7C1DCCF12BF555DFBFF33BFA09 -Nonce = -In = 26BA6EF5054908E2CE4618CFABAF79F8D87DA4605B7F33EFA1C6AA0F039E138CCA821C75F0B2D17E52932B25CDCDE78DA2BC77432786E865CB153E0A0C637E9691D08679075095EA47DC18F40435B2DDD071D066F3B2B792FA528C0A64725F2B07981A2FD91F658C49B75317FB963B2BB68430EC9FAAE98963A8EA85F62AD4F77E115D3FD979DB421A773F2454E6AF49BD950550B126921E2FA581EEDB2387EA285D652DA362BBABE6F7D8454074B6C9 -Out = 9CD37096F29ED2C56C7D2842883A79D712F6AB9F5F08AED655CFECAA2F482FF470D74597188C280E8FAA0B19B51B56A4A8B2B8E3ACE48927A61787341F5DC153621C14110710895E4AD3886ACE7599919C985C70A8B9A7891FA43D1CDDB30726A2D5027D77386E5E8B80BD7CBCBAA250269C250A8F2276E052A88997182528B947751DECC3E8555A8D4C6D6C223F7B6D431AE2C7931DB88200DA4D987FA0ADDF0C0C8997B7224E06F9701BFAAB2E99CB - -Key = FB8C5F864EAD033E0F3D427E76B5C9F5 -Nonce = -In = C1EFE0B080811DBEAB17EB4C00E62F695BA71BB8E27006187F6F224F29D83820BEF01EF26D3CD5FF85CD5B005FF0DE9A8795B20F31E4D98A3BAE15B7BFB60FB8642D77C12E488652A26B5E32116AA0F7177D1E3F46C31DFDF212683B08E84C0EE72A15466974FC5024F3A0FA2061F53AAA86B3A29114D165C150D6FBBF0F07645C91CB5C9EFBCB292ACCF7159203BF83A28FD040E92711854CDB4679A6D885FBADD29438BA11E9ECBA68F8BCD4433F7DCC6C263E41C3E64D -Out = 781D45863F3047C63BDB423712F166E4E5D018A6CD05B70E1131622E93BD6E0CB56735B5335001B9B971A671475DF0EDBEC0FAB32DDFD422504A941860C223D86B77EE2A4F7CBC4434738CF7F59059EFC0CFE4693FA9BD553B5EF3C1F311FDB66C8B4117620126768A74227874D9BC89FECA06CEBCEE39528378B1B5915543453E667860D94C0406543B341175650D865D245225B0964BE723516490D8F908DA7B73A72C790A5B6CD6B980D0FF8DEFE9BE0859163D3527D5 - -Key = 4ABBB43F2BF9C69B02AED5D4D82310F2 -Nonce = -In = B863168DAF023E33D00F90F5BD076FA62F3BFADC93F0A1EE0E1466DC87507BE3E0420F884D40511F5C1A6DC912E70F33EC90D52E2F98FBE89EF076E3A95CF011F6ABA8A946B409C196ED86094597D35C548EF84ACAD0CB3E292CFC4D43183F4D97C43BFC5445A5DDF396159F9662D0D844391075E5A209A00CFD49AA86519F7C3DE285D9DD02F3924D0836C725AA0669F3B98C4B42AC893B90F55D4F07B83CAD7F693BF49D72423A369E7FC563D44229CBFB5F7A25EEBB50DBDCA0852851D417 -Out = 3F22A08DF104CB891887000C0B975296A0A736B7D074739DBB7B16100EC96EA30F84438E3C9B6F38063C2C4FD8B39262D828F000B8176D6793F8537598DA976A29228966AF45F698BE394FD0FBFED864BB1B81BCEF8D9FED2BC7FBECEFC31D319D6C54648C9C0ADBB83B18A56E8C1D72DB37FD24EABA87F6C9767E3B3FA4566DA71D03539EB8E558390EFB8B1839AFEBE11FCD2F81774674228FB965D4A78164E57F5348DB47E06C0D2507B9738F3750D1780D49E485B9CF89A7C716F9A628AF - -Key = 8C366409428A56AD49CF09F5C790325F -Nonce = -In = FB669C4A5B01B8808E3A7A08E47D2ECE63202C4F896402163D88BDE3FA02A0C7EA924B808AC430A3A157B09FDA1991A18DE25F842E2DD3A221AD2804660791AE592E60D9991C59D6D0E50CA49F1F4FF5AABA0C81DA2C36EC169B420745357B82201009C2E2EF15853C65647FC93B587E25415AAABB8AAA7B441F8E1616A1DDBA24C83935C5A4755C19719837AC1EFC7275B37E264B1AF004513D53BC94BFF7D6763AB8AEA592FFCE8725BF2CC06C711AA2691475CDCDB82A28ABFBB1D166A20D3563B66060699F16 -Out = EF73A9BB5596BC30BAF024316E5085A71F83CA9C8BBEBA4C0F5EACE57BD0F19A9688590B4F255E048E90EE2F8316885ABBC82BD6F15FD6AD56C3C58D5FE6BF3BBBC6795E4E9D424EB570CA5775B39EF117F4D0337F88E6B3096F0206F89D01F1EEB39A388F42C44CB03AD06A6A4E914D545499852E2EC5F1F35556515FC7D04E884D48D92BB1ED179C485EE5E5B136F81BEDF14ABB843AC9292B80440FDB5CDD50EB573C744AF2444BDFFFD785FE3535F698F446B533FECEFC1ADF7752916B2B77C68F1AD08A77B5 - -Key = 0D852CA9C6CB0FA6A95F2B0D414A6F19 -Nonce = -In = 379AC957E6721F2C33CFA9C8E8FAA85B3AE28E346E99FAFE06C5F2497724D800C332A3DE25424523CBDEBB0EA95AA31C88B8A00ED3CF0E90B42BC1CF690618CC15796E1966AA57067D5B7E172A1F818C1C7EAF58C27E6EB3F647879E9785FC8362210C8E8C458A60AF1CFDBEF698869E3347645C6D9AE7407F8DC7A1F84B20C1CEB17E33320F9BECC4B3E8E450BE9F5956F74CF33F764526F097DFCB63C57C9798F791B471C494062BB6675C374EA7273E69C12B5349172AEED9C66AF0380490B74F2293AA22DA87976580994A5109B5 -Out = 7AE8556DD6A8EE6E86499658479AE39CC400452F06071044CD165FF5C2B85FD59DE4BFEC7FBFE20F578C1E21A53BC896D3FE5D77C7F908FA96A68FADA439645F621ACDDD9E2F351F1E4D87BE5BCA2D6C93584DC331DD623925B630EC01C296F64F71DF0DD92232C7B0A0DB821B1761A442CA73EC3FCBAB386B0FFA35754ED91B113D51CD9239DF73ED46BBE1485075BAAAFAC363F541870AA96EE7F21C4ECDBC0DA9F309B2CAB1C77D6220B2BC9EF5F2319607D7C3D32C9F007C21CCA676872818085C971FFB778138C5398EE372DEC9 - -Key = C071C64B7DBA548A42CF9656521425FB -Nonce = -In = 84B35BBFE1FFE781B931EEA1556DBA23D38673BB229EDBAAEA95A93736104DF3805D496895F105FC5433F698CAC70526A74EB67935788C35D87E6ACB63A285999CB981173BA6EB6F8402F89D4D2DBF0A5DE904D5BDFC4864C6E48B906090DC418E9A91BDA8BE63E3CB341B570EBA6C5095A478C0FF43C062E12FB180D0B74DA39F7B562FFE9F652B3FF4356BA024777AC34D7F84C45FEA5EC21BBAB205C6FF43EC92782BEEFD471DD8703FBD5DE167A829443F5F1EE398475A40049C2AB577B5A6BF2581420F38D22F46142B59C92ED80F44A22A49644843 -Out = 17B0379B31BE60CD613289C2176135F971DDAAC953B76C8B48BA9FFCA0A040EF00E97A320FD19C9D4CB269AC205DCEDA98DB7390992FA4FC567DE5A39ACF08DACE83858E03E3BDE07B75AB74CF4D90DA3FF2B95476F9A81853BFFEBD91450E71E4D5BB5291BEA641F877361112D65E7578390A71CA8778CFACD4D25F71C90D289AD29045358D1DC8E14983E75CCA03F12521969916432CB967202086B62B33AFE1FA5B5A68BD4BF19888922F814577ED0E4F09C50D884A7DAE5B08B2AABFA8FA159BEA131841CB0F3B63F826E36682208F78839D9E84D917 - -Key = BC12C0EA9A1D8C2F0CA4F4683EFB8E38 -Nonce = -In = AC1211AABCB5E081D8C95FDD138A42FD6F1D808E37077D65D8FEAC80791E5D169A32B2F333CED7B84CFA383B430BD7611726230664C2471C0413CE30006872B0707DBDA38F9640D5E376D050DDD5526A3313AD1247B6CE98F1484D9FF0169B7190F8D4CBE10BC03234E3CA2581EEB98DC5969E2EB57A4C5A10DD5B5619D80D5A9B9C3595EAD7E0B5B622A5A2F685D70CD687BEA1876C74A29DE026C1F8F673D66F1171B1633A05393A9896705A8E504BC474083DB285BF8DD893D3D699505345EB97985948DA52A17AEABF279CC28E9793D360E8D707D5C36C0047BDC6ABE83E -Out = 40BF0E1D3B5D92417849BBAE059D7EA6F22D409F5563957BAD0A4398F963AC823AE33A6F6E908AC004E94A5AB9E3E7C4184C94FC90EBFAC6CC70C60FE939453507BB65913FC9A97721A730880EFE22439DF0C516009A06FAE30F6CED63D9CEB707C331D0EDC2945EE3561EDAE176E525E66EEF01E4FE4880F8F7D79A32E45CF71300A262A5F78079C20D7A9EB543D2269579EC077A33EBCFB9289EB85C979951923ED96ADAA2984D6DEB1F5B3FA9CDD859EF877B7594E84B99E3A9D2C8B8F984428D18A1B59EBFB851CB8EF0B4719725CF07D73E580C18B537BE3AFB34186668 - -Key = A114856E299B436E09F437C57B15109B -Nonce = -In = 2D2E50EFC0C6378E1D6BF584C498600F883CB10A49E27325E20A018B0BB3F192C7462F1CF76636CB86F3CE38DBE3A70502A7A6F72EEFB76990773407DA628C11FBEC2E8478EF2F98F0BEDB6733F695CF0158B8CF5AF6097F84116CDF8B973F3B0A6BC863B12EFCEDF0AD18F4755974E9A05E554654115EA2B309DC37D41B7C1C6686C6470A7A528BFD2E8ECA7E28657ABB5BC34532C38365FA1BA9DAA3CEBC85A9F30195E6D4EB52EF8CD243AE7DB1D082501FCA2A93A4A81C4E1DEF5F4E0625BB088D0B2F4C31DC26561179DC3B46DFCACE0E82CA9A05058E2118194F6021CFDBE0D8C1D7B6D41B -Out = A6A0348A6F587D6664381AE45F8A0BC69C51F7BF6C26755452CDDB4F1F101EA2224F61BCDBA8E97067DA55F4BF59A5D7CF12ABCF4DF18B92E4B6921569051F5E70F25698FE0D6C19B891B48A3E03EBD7FE4A79A250A8B5FE6662D4430725AC447B55BBDAFB259B323872B4EFBB452FB968E979006EA49A789F4C3743DBC1306AFBF5A4B1F421C99A3AA07A2E98A47B4DAF2204CECB2AA86FB9AB60125AD0CD94C799CF3EBEC65C6F4F2B864C11F513CEA9D6280CDF16B1F0E1F943A444786E1DCB1851681572ACA9571699B82CE9E5275E6999A1EEB599CC8A0583D11D47938324E95B67407A0D68 - -Key = C722C9F2A15369264DB7F54FEB0207B8 -Nonce = -In = AFC793265B90D53B647275124998999B3D8C91440541DB7E8CB0E8837AEB4653FC35361B55D659148D9F25E3C109B1BB92C037397DA8F91CD5AF0B6EDE7667BFCF1DDCEE76AE83F167D937EB67005D48A9503315476A43A45001F621444C562563DE6901E969F6662249A6BDAB7A638405EA3AC01304FD2DB772CC7AC122CD3D65B749A3F31704910950B642C8E5654DC10B07C614C65A07BDE2AB52196999066284CF0F6EB66CD1A62C29B683A436C5BBC15704688BAB92972421903D53F2072F7B8D53B02B70F63E7A7503207360A4872E04CBADBFEB321BCDDEA5E89419FEDED04000065DF73BE58A79AB5BDF885E -Out = 6CAE06C13E54BB2375E3D3C741E9C61D3813AB63CB157E54FAFD28E9A4D935E57D74032E5E669844D277F211B480F0E54E4F0B09C2242FE1D5EEFF32E1313759A47E7450B55E09C437D1EF3F60A0572134C2D9B5258414BA5D84774D65FE545F1B80E7FC06BD7669D05AFAA2271AEE74F8E0C247070CBA2FFCA62B6CE5BFB0B6E75055F099939AC44FEC6E9A3615FD57B3723119FF14C927BA06DFFA36E91744E035AE7A9F21625D74BB62C41802782201D1043E5B9AE266997FABBB42ED800EA1E2F2A4E78C265E3CBAA9979ED89A8FC6C9F16BC6802A5E7D2D819A7D8357B9C40B5BCC50726EBA3DD0791E11489771 - -Key = BEF7E425E917D067300D40D19AE12ADE -Nonce = -In = 936C9695CF82D4241CAEDA1E8C80DA52CA4837BBDD2158E2CCDAA99EFEC6F1FA29D6ADDD6FE3A660F50FC6C2AE456BF742081FB471A317707C523638AA27DD85621CDED72631C4690A857512265A11C283193BE33BBA6E77EACD56E9DF9541BDC3567814E98F0E6D57D9B25440FB7AB62AD9375B2A96F60C4E4B57AD02F62EAA06793D0C5761369447B9A0621EC2F9AFBE8F52E8720CCF67E4A1BC7285463E8DEAADC248CD8207739F04FD13F72E0A7A0CDDD5EA0B7111582A389C21F499BB4349E8BDFAB0925E4C299773A9A546913D37B7951C9052EE9455391880A77CC66F133FB8AF5CBDDB2433F3F9D52F94A15D8A9143D0729F6D60 -Out = 8144D92331D338C920C0BA0C6B32C6EE28BBCE148F6B56B5D2A12D029734A41B8B4071E4A7601A88E8CEB031DDD38E4588CCAA900E8E23AA1C3D4AAD39FB75B90A8C47ABE3641FC6B04EA1E74FD4B4B9E72310F79D25509B3DCA63BEB093A08F7149A23E0D548DD5C20449C90FB41C88CBB6D1D51D35DE46D4112090926A7948563487E34E7507CCBA9825BB48EA8709239CB49CBC0FC09447570E1FDE99E1316BC24A5CD38E53F613152BA9BAFEB065AE30CD73DADEF90E4E907C0E55EA0488B9CDD20926B3893D8429E4C9FCEA17087B6933064976F2503ACD2D8D0DF4CF6F10BFEC0C914B0C46E6FF575464FCEB1EDC01AFBE446F77AC - -Key = 19796BDCABF22920277106075D0E0EB0 -Nonce = -In = 23D35E037CBBA0A76A46DD433B547E17B54A81782A51D13829BA301250ECBEB0EB598F76BE470D8411E7E58516873B4C9BB87E4B41C4DA3BB941C3F8A9EEFAA507D30948692ADD5E53AF8EF3CE42D6944D8E2994F45F4090B8934BCB09B94B3BF04726F42B00ECF9D9893BAAABFAF712E022F82317CFEC8AAEB7242BAADEF7526833C2EA481816856BD423CC652CC04301C7212BBE69F251BEBFCACAF0F12A19F99EC4A88E4381403B24322133373ABE881C0F97D706EE4CBF3F5F7E69B8624F50270E508ED0487B0B8116BE1AF904C23B4F704BCB8AF92B118A912B5CD0D759C3F73A6331E1337B693B7EA65A017CB62C51A4E4AC7C6AB9530DE747FFCEF27C -Out = D968A79959F5DCB6486FE846504AC0E8753E56410795AB9637BA84EDD9AFD692DA253ACFDE1FCEF40280D30BAD93AF2386B755835AD1CB18D472DAF37D7C69109DE9898E09C69DD8D5DAD6D6640246B28F905FC0B1329D44E9AD2DD4D5D467862AE364CE7A81D5433B00CAF11B9A1D7D54910CB2B01888348ED423A2BB40CE0CC23210CE10CB9B123AAA8F41A3B25114398160C0E9241CEF67F52CC419AD31E5E04C4CE91716ED99702AE69E7A1D501C47A53F81E611827C7694E9B4B9446F263FF1170F4CD70B432EFEF97F0916CC6BA81A8E11EC996526E9202F6910FE8A427CD0BC8C7BFA23D0DCE30FDD6C2F36B582A3C9B698BC5CC6CEB3F951B26D586B - diff --git a/src/tests/data/ocsp/geotrust.pem b/src/tests/data/ocsp/geotrust.pem new file mode 100644 index 000000000..33cc0023e --- /dev/null +++ b/src/tests/data/ocsp/geotrust.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDfTCCAuagAwIBAgIDErvmMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT +MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0 +aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDIwNTIxMDQwMDAwWhcNMTgwODIxMDQwMDAw +WjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UE +AxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9m +OSm9BXiLnTjoBbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIu +T8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6c +JmTM386DGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmR +Cw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5asz +PeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo4HwMIHtMB8GA1UdIwQYMBaAFEjm +aPkr0rKV10fYIyAQTzOYkJ/UMB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrM +TjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjA6BgNVHR8EMzAxMC+g +LaArhilodHRwOi8vY3JsLmdlb3RydXN0LmNvbS9jcmxzL3NlY3VyZWNhLmNybDBO +BgNVHSAERzBFMEMGBFUdIAAwOzA5BggrBgEFBQcCARYtaHR0cHM6Ly93d3cuZ2Vv +dHJ1c3QuY29tL3Jlc291cmNlcy9yZXBvc2l0b3J5MA0GCSqGSIb3DQEBBQUAA4GB +AHbhEm5OSxYShjAGsoEIz/AIx8dxfmbuwu3UOx//8PDITtZDOLC5MH0Y0FWDomrL +NhGc6Ehmo21/uBPUR/6LWlxz/K7ZGzIZOKuXNBSqltLroxwUCEm2u+WR74M26x1W +b8ravHNjkOR/ez4iyz0H7V84dJzjA1BOoa+Y7mHyhD8S +-----END CERTIFICATE----- diff --git a/src/tests/data/ocsp/gmail.pem b/src/tests/data/ocsp/gmail.pem new file mode 100644 index 000000000..f96928a64 --- /dev/null +++ b/src/tests/data/ocsp/gmail.pem @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEnTCCA4WgAwIBAgIIQkg+DF+RYMYwDQYJKoZIhvcNAQELBQAwSTELMAkGA1UE +BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl +cm5ldCBBdXRob3JpdHkgRzIwHhcNMTYxMTEwMTUzMDAwWhcNMTcwMjAyMTUzMDAw +WjBjMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN +TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzESMBAGA1UEAwwJZ21h +aWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuw15ghutT7Ne +eTd1u+TXCoyDK0/XwotRrrfP3+HU6f611WbUi+Eb4mpZ7ZnjBUBOWizRqr7XwURV +7LpwC/Xxn2OlK+yFFeTZYRyZqKhtY3UQsbztAlc8s7LmBTU2bC2wR942SfTpEufB +j+Qloc8WnyVVGqU3IhV1vLPZiNwUtRMKSZiuUDOH0M10icmXDyAl3zNw119ax6bf +P4fROHmLydGP6xcAXEQ9MnJ8cec5V3R505UaxVMROF/TZ2PricWyoz53Tu8AGHXT +81AH/Gq51ettup+CeYFdpxC4lEvZZwxeHo0kHkFv4od8g3HDYkjKfYkOi4vfFg1Z +hMJG02d17QIDAQABo4IBbTCCAWkwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUF +BwMCMDsGA1UdEQQ0MDKCCWdtYWlsLmNvbYILKi5nbWFpbC5jb22CGHBvbGljeS5t +dGEtc3RzLmdtYWlsLmNvbTBoBggrBgEFBQcBAQRcMFowKwYIKwYBBQUHMAKGH2h0 +dHA6Ly9wa2kuZ29vZ2xlLmNvbS9HSUFHMi5jcnQwKwYIKwYBBQUHMAGGH2h0dHA6 +Ly9jbGllbnRzMS5nb29nbGUuY29tL29jc3AwHQYDVR0OBBYEFOssHSlSYSvxTr/l +pRnYGdp+QKZoMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUSt0GFhu89mi1dvWB +trtiGrpagS8wIQYDVR0gBBowGDAMBgorBgEEAdZ5AgUBMAgGBmeBDAECAjAwBgNV +HR8EKTAnMCWgI6Ahhh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lBRzIuY3JsMA0G +CSqGSIb3DQEBCwUAA4IBAQArrTNbfuMTZTUrfImB3oS0ffMhbymSV8wCPvuC8+LO +yj/1rclI+0NRI32oUgwyjk9xOkPY/uUBk3KXl2b39R4tr67acyUPtuVGY5Nam3Jk +c/7oqREBJr+M/Qr7nYQqTMzh4LXekl/Nh+ZHRnRzYP+q0DE9f8AkiIs9ESziym1d +UY7u/IgelaCyh8CNZoYqui7I4DPfegz/De39rtbCPunC9VQtlMDas4FIOjQrSTIz +tV/xNJMR9ka57B4YLfzoTHq7w7zw+fqeebpyKa4MqOzK9kgrfASYe1YpWEy0SBBT +4zfVLXqyr5eDeaJJjpRJEcSopc0nIN9qBCLc2K7GI54v +-----END CERTIFICATE----- diff --git a/src/tests/data/ocsp/google_g2.pem b/src/tests/data/ocsp/google_g2.pem new file mode 100644 index 000000000..b663266fc --- /dev/null +++ b/src/tests/data/ocsp/google_g2.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIID8DCCAtigAwIBAgIDAjqSMA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMTUwNDAxMDAwMDAwWhcNMTcxMjMxMjM1OTU5WjBJMQswCQYDVQQG +EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy +bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP +VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv +h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE +ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ +EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC +DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB5zCB5DAfBgNVHSMEGDAWgBTAephojYn7 +qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wDgYD +VR0PAQH/BAQDAgEGMC4GCCsGAQUFBwEBBCIwIDAeBggrBgEFBQcwAYYSaHR0cDov +L2cuc3ltY2QuY29tMBIGA1UdEwEB/wQIMAYBAf8CAQAwNQYDVR0fBC4wLDAqoCig +JoYkaHR0cDovL2cuc3ltY2IuY29tL2NybHMvZ3RnbG9iYWwuY3JsMBcGA1UdIAQQ +MA4wDAYKKwYBBAHWeQIFATANBgkqhkiG9w0BAQsFAAOCAQEACE4Ep4B/EBZDXgKt +10KA9LCO0q6z6xF9kIQYfeeQFftJf6iZBZG7esnWPDcYCZq2x5IgBzUzCeQoY3IN +tOAynIeYxBt2iWfBUFiwE6oTGhsypb7qEZVMSGNJ6ZldIDfM/ippURaVS6neSYLA +EHD0LPPsvCQk0E6spdleHm2SwaesSDWB+eXknGVpzYekQVA/LlelkVESWA6MCaGs +eqQSpSfzmhCXfVUDBvdmWF9fZOGrXW2lOUh1mEwpWjqN0yvKnFUEv/TmFNWArCbt +F4mmk2xcpMy48GaOZON9muIAs0nH5Aqq3VuDx3CQRk6+0NtZlmwu9RY23nHMAcIS +wSHGFg== +-----END CERTIFICATE----- diff --git a/src/tests/data/ocsp/identrust.pem b/src/tests/data/ocsp/identrust.pem new file mode 100644 index 000000000..b2e43c938 --- /dev/null +++ b/src/tests/data/ocsp/identrust.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow +PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD +Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O +rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq +OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b +xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw +7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD +aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG +SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 +ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr +AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz +R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 +JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo +Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ +-----END CERTIFICATE----- diff --git a/src/tests/data/ocsp/letsencrypt.pem b/src/tests/data/ocsp/letsencrypt.pem new file mode 100644 index 000000000..0002462ce --- /dev/null +++ b/src/tests/data/ocsp/letsencrypt.pem @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow +SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT +GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF +q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8 +SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0 +Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA +a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj +/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T +AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG +CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv +bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k +c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw +VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC +ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz +MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu +Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF +AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo +uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/ +wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu +X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG +PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6 +KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg== +-----END CERTIFICATE----- diff --git a/src/tests/data/ocsp/randombit.pem b/src/tests/data/ocsp/randombit.pem new file mode 100644 index 000000000..d5986c21c --- /dev/null +++ b/src/tests/data/ocsp/randombit.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFkTCCBHmgAwIBAgISA+ie0HpCS3KjX60Wf0ik8lrSMA0GCSqGSIb3DQEBCwUA +MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD +ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xNjExMTgxMTE2MDBaFw0x +NzAyMTYxMTE2MDBaMBgxFjAUBgNVBAMTDXJhbmRvbWJpdC5uZXQwggGiMA0GCSqG +SIb3DQEBAQUAA4IBjwAwggGKAoIBgQCxYsED7KF8RGFWcq1tQdvRExLdDjGJcw1j +4uV6a/yt2v/wDSUPIXNak9Psm5V56AH2tV/nMuwiFAyqlZiPFcCD5clXoIkJBW2c +hXYM1js6tNlX6iBA0Cl/ug0+sNYiJP7GZAZFGLy7itGYpLn5DtawQfWxt4ENoZ+x +MQVAjRrb2oH/BNTBvvMjJNehxkf4RGo9BiwNHwxw/3SQHsObzLvYwnIe7pNCw5gu +Ol4ekligjh481WIvOS6/dOu2FOuutKKsOFasxyaE8qArs2Nwb0fSS+LG3U7t7jP5 +MuBS+kfp1/jQ8qvV5dJpKcw6D2q4qjmOiAHSXOY/+1GoaKus6xB7NTXbiMsHR/VH +hnupKYzsR3Fs4+agHXpM/8n6erVsXtwPdw6uFwrVlpAOvu56PiSgaBZLpex/Z4bk +tqcCQ2EJcjKUU5Ht5TKUFaXv7v/WLkbGdbdVDHh9cEnOthGme8QgaDPZp+mND6Bs +QyJQgpQ57hsS55l9XehXzNu5SOr/F58CAwEAAaOCAiEwggIdMA4GA1UdDwEB/wQE +AwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIw +ADAdBgNVHQ4EFgQUpAkBML2UJvHr4dXnxC2gVnY5NAkwHwYDVR0jBBgwFoAUqEpq +YwR93brm0Tm3pkVl7/Oo7KEwcAYIKwYBBQUHAQEEZDBiMC8GCCsGAQUFBzABhiNo +dHRwOi8vb2NzcC5pbnQteDMubGV0c2VuY3J5cHQub3JnLzAvBggrBgEFBQcwAoYj +aHR0cDovL2NlcnQuaW50LXgzLmxldHNlbmNyeXB0Lm9yZy8wKwYDVR0RBCQwIoIN +cmFuZG9tYml0Lm5ldIIRd3d3LnJhbmRvbWJpdC5uZXQwgf4GA1UdIASB9jCB8zAI +BgZngQwBAgEwgeYGCysGAQQBgt8TAQEBMIHWMCYGCCsGAQUFBwIBFhpodHRwOi8v +Y3BzLmxldHNlbmNyeXB0Lm9yZzCBqwYIKwYBBQUHAgIwgZ4MgZtUaGlzIENlcnRp +ZmljYXRlIG1heSBvbmx5IGJlIHJlbGllZCB1cG9uIGJ5IFJlbHlpbmcgUGFydGll +cyBhbmQgb25seSBpbiBhY2NvcmRhbmNlIHdpdGggdGhlIENlcnRpZmljYXRlIFBv +bGljeSBmb3VuZCBhdCBodHRwczovL2xldHNlbmNyeXB0Lm9yZy9yZXBvc2l0b3J5 +LzANBgkqhkiG9w0BAQsFAAOCAQEAXAh1j/hxsJMCMSfQWLSDMNQQirlWJafG2mao +P5ZwjkGyPoM6q1E/G60TRFSbqwvI9b1SrMipuz5fqf6q7VTac2DZyC7hx5RXvDk3 +ZD93DYYlwOw1RMrfUZtk7F1maqxESxd3V7L8DQWaPx01KZj4kJkP/cwT3t0GWgF2 +DLdltmWqjuFdrxY+XYTdvsk+U85rhosm/4UGlJENdagRMAoRuco/y7MRuKSCWewN +Vc57atZpfZahpqG10Bld8uf3ApP5eoNWKxbePFMhdWyj8o1N6p57pRn+Qp/mV+0B +I6IbQv9+D/qEFgHkHDPClaoRjM0+bRI53+uTt5I70VcimVY+wg== +-----END CERTIFICATE----- diff --git a/src/tests/data/ocsp/randombit_ocsp.der b/src/tests/data/ocsp/randombit_ocsp.der Binary files differnew file mode 100644 index 000000000..93d1c6287 --- /dev/null +++ b/src/tests/data/ocsp/randombit_ocsp.der diff --git a/src/tests/data/ocsp/resp1.der b/src/tests/data/ocsp/resp1.der Binary files differnew file mode 100644 index 000000000..dd5420378 --- /dev/null +++ b/src/tests/data/ocsp/resp1.der diff --git a/src/tests/data/ocsp/resp2.der b/src/tests/data/ocsp/resp2.der Binary files differnew file mode 100644 index 000000000..ea993bf5d --- /dev/null +++ b/src/tests/data/ocsp/resp2.der diff --git a/src/tests/data/ocsp/resp3.der b/src/tests/data/ocsp/resp3.der Binary files differnew file mode 100644 index 000000000..416678cae --- /dev/null +++ b/src/tests/data/ocsp/resp3.der diff --git a/src/tests/data/pbkdf/pbkdf1.vec b/src/tests/data/pbkdf/pbkdf1.vec index ebcad175b..a0eeba6e5 100644 --- a/src/tests/data/pbkdf/pbkdf1.vec +++ b/src/tests/data/pbkdf/pbkdf1.vec @@ -1,4 +1,4 @@ -[PBKDF1(SHA-1)] +[PBKDF1(SHA-160)] Salt = 40AC5837560251C275AF5E30A6A3074E57CED38E Iterations = 6 Passphrase = ftlkfbxdtbjbvllvbwiw diff --git a/src/tests/data/pbkdf/pbkdf2.vec b/src/tests/data/pbkdf/pbkdf2.vec index 6a027721a..c8a5356be 100644 --- a/src/tests/data/pbkdf/pbkdf2.vec +++ b/src/tests/data/pbkdf/pbkdf2.vec @@ -1,4 +1,4 @@ -[PBKDF2(SHA-1)] +[PBKDF2(HMAC(SHA-160))] Salt = 0001020304050607 Iterations = 10000 Passphrase = @@ -59,21 +59,21 @@ Passphrase = gwrxpqxumsdsmbmhfhmfdcvlcvngzkig OutputLen = 64 Output = 4C9DB7BA24955225D5B845F65EF24EF1B0C6E86F2E39C8DDAA4B8ABD26082D1F350381FADEAEB560DC447AFC68A6B47E6EA1E7412F6CF7B2D82342FCCD11D3B4 -[PBKDF2(SHA-256)] +[PBKDF2(HMAC(SHA-256))] Salt = 0001020304050607 Iterations = 10000 Passphrase = xyz OutputLen = 48 Output = DEFD2987FA26A4672F4D16D98398432AD95E896BF619F6A6B8D4ED1FAF98E8B531B39FFB66966D0E115A6CD8E70B72D0 -[PBKDF2(SHA-384)] +[PBKDF2(HMAC(SHA-384))] Salt = 0001020304050607 Iterations = 10000 Passphrase = xyz OutputLen = 48 Output = 47A3AE920B24EDAA2BB53155808554B13FAB58DF62B81F043D9812E9F2881164DF20BBFFA54E5EE2489FA183B6718A74 -[PBKDF2(SHA-512)] +[PBKDF2(HMAC(SHA-512))] Salt = 0001020304050607 Iterations = 10000 Passphrase = xyz diff --git a/src/tests/data/pk_pad_eme/pkcs1.vec b/src/tests/data/pk_pad_eme/pkcs1.vec new file mode 100644 index 000000000..48b732d95 --- /dev/null +++ b/src/tests/data/pk_pad_eme/pkcs1.vec @@ -0,0 +1,46 @@ +[PKCS1v15] +RawCiphertext = +ValidInput = false + +RawCiphertext = 00 +ValidInput = false + +RawCiphertext = 0000 +ValidInput = false + +RawCiphertext = FF +ValidInput = false + +RawCiphertext = FF02 +ValidInput = false + +RawCiphertext = 0002DEDE24212121DEDEDE5EDEDEDEDE0A5EDE00000000DEDEDE010000000000 +Plaintext = 000000DEDEDE010000000000 +ValidInput = true + +RawCiphertext = 022C2C4018181818181818181818183A18181818181818180000002C022C00010A2C2C2C2C2C022C +ValidInput = false + +RawCiphertext = 00022C2C4018181818181818181818183A18181818181818180000002C022C00010A2C2C2C2C2C022C +Plaintext = 00002C022C00010A2C2C2C2C2C022C +ValidInput = true + +RawCiphertext = 0002FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF010100000021FFFFFFFFFFFFBC +Plaintext = 000021FFFFFFFFFFFFBC +ValidInput = true + +RawCiphertext = 0002F9CCFFFFCCCCCCCCCCCCCCCC4E0000CCFFFFCCCCCCCCCCCCCCCCCCCCCCCCCC06 +Plaintext = 00CCFFFFCCCCCCCCCCCCCCCCCCCCCCCCCC06 +ValidInput = true + +RawCiphertext = 000253FFC43B5253FF0A53DE0000FD +Plaintext = 00FD +ValidInput = true + +RawCiphertext = 0002FFFF06FFFFFFFFFF00000000000000000000000000000000000000000000000000000000FF0A +Plaintext = 000000000000000000000000000000000000000000000000000000FF0A +ValidInput = true + +# Padding only 7 bytes +RawCiphertext = 0002FFFFFFFFFFFFFF000113131313131388 +ValidInput = false diff --git a/src/tests/data/pubkey/workfactor.vec b/src/tests/data/pubkey/workfactor.vec new file mode 100644 index 000000000..7d8999da8 --- /dev/null +++ b/src/tests/data/pubkey/workfactor.vec @@ -0,0 +1,43 @@ +[RSA_Strength] +ParamSize = 1024 +Workfactor = 80 + +ParamSize = 1536 +Workfactor = 97 + +ParamSize = 2048 +Workfactor = 111 + +ParamSize = 2850 +Workfactor = 128 + +ParamSize = 3072 +Workfactor = 132 + +ParamSize = 4096 +Workfactor = 150 + +ParamSize = 8192 +Workfactor = 202 + +ParamSize = 14400 +Workfactor = 256 + +[DL_Exponent_Size] +ParamSize = 1024 +Workfactor = 86 + +ParamSize = 1536 +Workfactor = 103 + +ParamSize = 2048 +Workfactor = 116 + +ParamSize = 3072 +Workfactor = 138 + +ParamSize = 4096 +Workfactor = 156 + +ParamSize = 8192 +Workfactor = 208 diff --git a/src/tests/data/pubkey/xmss_sig.vec b/src/tests/data/pubkey/xmss_sig.vec index 4e032390a..ce01952da 100644 --- a/src/tests/data/pubkey/xmss_sig.vec +++ b/src/tests/data/pubkey/xmss_sig.vec @@ -78,3 +78,63 @@ Signature = 0000000000000151b768d3fe7f8566201e891afbcaf552228327854b5386df2cf63b # PrivateKey = 04000004c04666e9dae87ae9c9902e5dfb51b03456fe1cbb6f9cc3ee779d0ce84089d4f35481147e1a11e92db84c2e767364374f72d34e9840ed7e7c4f5b6796a28636299d6cf36f2d6c05ec409f11de398f4fde26fa01cf74d6d288256b0779317aed7d443d3a574adb8f71dca9f1579fc0ec022c757d0a22087d68a006983a0a92b2a100000000000001e39649cd8ffcbf4f2868c121507e0d55f37a4529585f8cd93730e37deb41cab3f89a602e4cc39cbfc39e5948906394c30a9b43e23d3fd45093f5bd3b93d49f1af038f9ecde211ba400d497c7053196cc8083fc53b9754537d3a0f7ff36013ffe55c025fd5740f3d5fbb68c17d90c6a9acf65926bc474762f69a1d4b5f5353a829d # Signature = 00000000000001e315eb14ee98eb907ae9641f8f7e3ce7aeac1ea1a91ec98e007a0d5373b5914aadbf1b53bab5d7cbf351ae26b13e31aed1b51e8779852cb608a056c024eda449bfc68e807ec0d78a7408e7f6e7bcbc83d77168ee64ebb558e552f9134ebb8692d58f74cca5348404432b84febf6726eff437b950adc6a4c31ac5fc59a45ef9af656933cea726b4300c63b6f86c9e3a531e8bbd4c70f9067f811e3e179bebcb551adda6b7598c292d69a2c00f514de0b27c110c3bee84fb4e3b3fb8b9e7fdc5a59584b7b7a7ab5afb8a9007721bbce79a80886fcae251874dff1df7d40944252bc70b57dfc53adddd5b65040eaae3d8c633cd1a169b9237e829657394b6c644fbbbbf26fc5b03cc6bcbb2ad03532b4b01d19f2e458cbc4a9a40026f19e0653856967ec3a8eab2ee2df7a09e2051c7a56b47c486bb8fdcf876d71b0196b1f4ea793563bbb36a79bc621abc804fd99e69681d36ec91f01b0178bb727045f492d794acab282067ef4765f557d885b12c96a0661bdeb0a0ea84c48d5a4ac1e687b85874ab75e1730447453a3bb9cf2830151321e926938a09bed1829f249925d2f76372bf1199749ae738ee5f52c10804a5ec07fa0da06d0d6a51353697ff2f070c367550327871bdc4cc58a059d3495f12558bb0480777dc6d1e8291d78dd511428967e6d42a4a5664389abaf08049668ee4a4fe23e3b8ce4f1317b7d49b091cd39cc8402759f9168178614a83dee3df22f730000e7781635d5f9dc67a780c5a505f0dc5544019f3488b3f5f370f41eaf62a917f3193bccb8001fdb8e271fae6a0d0e35fb56dbbfbf6fef6d6f74fd79ba1c64782217fb105d2559ce9603ad40d0cd690b7e65d0453c31900b71eac81ca7d0f3d038668228de6314a4d241e7572539f9e6c71672574454e2c5ccf04020c9f6466707477b0e9a0af2edc1224463a620622d1102e66ec5d8e8b5f1c6337134bfde6485f294c657e705fabefbd09195f255308c338681d2d4f52913fec03266c028e503ef2804e4fe82cb637b32aee1e9f12440db77576c04672825516c1a92e0a2efb51f0eeaff10f6f7b781dead230c4783ceae443c6bb81b67d85640b11d591ec724c870c0b66b93941004ccc7f1c362172dbd6b04cf2b94f60fabe026b5ebb4573f9f7df8879ff6840afd1df604c2b6180859c519fc3c77613500c64a93a9360dbf97ffeffa02e50d48f0c5057a07b10adfde525c687f107724b10f6994c2ffcaf0d11c3d031991a8b0dad3e913895604361bf9f7aff1057a356638af4394a5b884fec4cdd0aaf7d8a81cc30b3444a3c71cabe9af7e9d9e7c6d9423d8cb48f3ac84fb1731a23705cbab512d24d1f1854710bdeb2d2ad9b245aa0c40ca14506588958fc1f7bef1793b82cc45f066c878e0ce87ac98c17994cd04f2605494a42e8cf9412b21df8d2ff6301c1ce577ae80ae92b58674d9ad854b9554885d860f2d396122a9dad5c04764a9c872ab6392d06fe09bac33e79569a6922cc55f4ef981a50cefa2ba1d36122f195748ac929d28745ded5fc14a88ee751fb6dffcfab76daaec74505adfa633102e3724245e8a1eacc2f1fe0c89e1625b9ce2f027a2c560fa82ce72c3f19127a3048228a304439a52fbc062fcaa5482e04c5a203f52ce16c61013f0f3191e2f060a652b44e26316308b91b9951c434c1419b42675afa5e4813366bd93b3dd2dae6bbf1be7d09dcd390da7500b6edd4fc3974d150ddd95cefd576a3f4b385129969427d80d4de4fd61b679eda7bdaad43bc837a71ab936350627b0c019c91a21cc48cb8ccf2ae0c59123582d66a0db3d02b2941838a7be3a7113bba1873891213a1ad93624674a72e644e74348e44f18b703eae62093a61fbe1f0b25f37806d9ccbc101b8b39f46642880301fe70f2812a2e64fd333383a48c445df60d36d93e9cbe9f766a5c7e68e725346f79dea08c16ad52ae7ed0a2569083081e937ca630de2ce702110c4f0569b241ab893e44a6d5e5b140f997bed7e4e95dfa97d147d3027186e466cf92e1f2aeb8b7155f266e42e769fbca065348216206ce799ecd33b6c17fe4466ea0cb509b9d995f5fe833d5a56d891f565fcdc3905bcf20bf3dd225f85b9abe9435b9bb8e1bdee70c4ab219909b9d6f1b9cb88d2c90371553492c44a5547b1f5994df9b2d9e0e982f7b0293e8701f77ff757bb69a0f4b0f4f1ee689fac86c6cd8aa070371efb1d9a8f43725678af9763bd6a05e33713b56c22d5fe0a06d5a5bf3a5de22cf3283db49608c1c43e4b95597f660593ccd6cef8999589c8702a7d8ee21afc92446a4392f9321f127f813e568bcdacc2c19b7d278dc7170996057c417b3a7798b6c781d51fe7433bddf894e27cb37d04abdf723b74e17c003b85bf21c94b4370e0b88a4dd5da02e7a5c106fe467a03ecdd5018bf0ff030188711f2249ac852c2f7bb6cab0317c21ed43dffc9e0d2330de3e6dac657efe71aed6cd78139f7161576d510d73c1d3b97356798d94bc42f5a10e0f8e06b86a23f80626bb850862df98765adeff79c9fd7e1c73e79b5d0adbc49646551c62c97f9ba2d28f2336d16e22caeccedc8fda0ec1549e915b3f4f19eedf240d024128b15ffb2739fe695ade8289e4a902cb392ca377e25d4c52b9c39952a777c9e34e428e121f911415c20e47852c731c89c28b428b1f51ae086f6653fb359807b6d4d8eef97dc553f27f1d0354839783bf80c197b7f1c2e3073cdc2960472007f7d32fb28a1c73dca9b929bad8a57a01f2616fcac7d7c0d3e91b5cd1b8133df9b2ad7aad66b3871b660966e2157fdad041edf35de35823fe9805ac0cf3b707608d4a349fdf498b3eecf6d9c94aea9608756cbfd899f7faec884b03855e4695dcc33f73eb5bfba273e3d4f8d8b005f1a6ba73564c98f94a72c0d2999c9d6cecfa3978e2fea2c5cf996bdc20c99ed54da9babace79e0068744f778e82e24ce1a148a13a7d2d19fca6707245444575d9fbf12f6d2273f0dc8fc7295f9fef1ed69615bca302d6352a9b07d4ee639e2f9cd30c39951d9da90d66c9070dcc2b9869df2e376f1c820df3020aa87f37b496d26c9e8f4a78dd1a9ecc9df3e2fe9837032e9ef2cdf3ac26901cd2ecdbe1fdc59efe586e3288833764378f7e27849c0f48eb1171de414f5c4834eb694a76c7b5de4c93ad38c8b839ee8cbf0b4032fdd09fab4f8fcb967c94634f2f1c6e37ce78097d7143876c170c8d8a14e05ca3d06fdc281e89b7501e2378517b7a4baa48263ca290d65e8a1d8ef0407b8c1c31fdfb76c5427157b5c25258c2f0c45bdba632be85c7471b6814f15e13c5191440217039b134c3a5f5fb89dd7f40ba309090c2b453481add9d0d5600b11690add80948a72d0aa4079f070452e977759f34feb69e65e97b9f85da6107d6440eaee8b5de6375963ce993a8c8586fd4d6238299384e70b9d872bfe996273b712764c84ebec68320d3e26e567c6b3f48be2e715b283360f5d2be9a0bc8ea1f67ee52f864081389a6bc29ba61218a7f69554dd850227774e33f7b84361bdc4ad7d2fef325e078c52f51f68b45790bc9c51b63cedc4f273beb0238a68d0e8ffff68d999270f4f6586e144871fe9475908bb3d2053d5f73bceadc7db74fe08af1479b7b81b48b2f433a8a242cbe759441c3ef7074965e4ac6466c1c597d26c82c655c85ca800c16cb440b4064b46d3463e66bc577b0016aff890c623875d1f570cc2e91ed9e1aeb3487c500c4c59c90181bcaaf383f7afd631a5738d58300d9b370d3d9fde31e8a00cd14843fb73e7e1ac703c9c8c62b2447931415424e7e6516e78120b1b10caa60cc56d13efde82f2722731a13193586a5d1e38d7dbbee387a94eccc73877fe9131683cfca74e3b8cc8bee3ec5c3eecc3c1d492d19b7e9d1f3b004e6414047b065c81b81b11a7bef605290ab520119cbd030c0ab8bec99501f91a7ea901367f1871666da7478a34578bdf4d1ca26a5f5d39346f66e3101939eee61fb75a39a9e5cb973085fab324342cee75cc9048b8fb679a6cd8c7374d4cf7a004da89b04c63f77e5881f0223a2bc5a32e0f61a3102ffb389505be47daedb493ea86bff68d96993c65e0e12b7cb0ddf6a61fa02bd3bec1bd03281745e63b8d8e07098a1d3161da76c0bc953ef16c065b5f307cc9e51fccc933e19b44db3c7e762b105db6d87f5f85eb7ec62780f902a9515ac5c9cb66ee9a8d09230de2dbb486a51d850709d0484bc907d20c8f0885ce88fb939de487e489a0afc9982212b7b9f7e19380366d30ffb4de09eca23db901ca72112cb777ff83139ffd6e7bd0d87085ee5273afa624a8fc819064d081f988a703539160e0f8d9b169a82b4d8c7c8c0a1738d07981f1a60deca72c8f1385640eae51eaf53f329aff2d6f9ab423121aa673b5f10d72f578035e3cd085c7d27cfce0d6eb5a646a658a4567f4516e2520a10275be998d663bc3d1e4e122b067f551b3ad237435241da94afd0c07caf6ac622d14aa48845121cd923a2c584e7930bfa99588e76877501f39c601da9bc16b36dbcd6f1e87fbdc0f7cbd9298425b12ae6c43dc96d46195e3252f999d1b688548172b6c1fbd3deb8113954489450da2a3683f6fa389f1a2f8cd65ed586b07523cfc5af06bd164b6965c78c7cd2deceea56bad09287db7b32dc79b963dc6270e22f16bc564795a7d9918838daa70f9c7185024ee77af53471384e831ad76d116b5545dd97d7850fffbd360ca5792411483c9ccf97918dcba886191df30d826badd699f5a556212a964de95a61fbed1d39e16e5ce96d6640ad1bd497e1c4ad28e5b5fac8e4ba763787ae66a47ec8aaea40b17fdb53b19fa9962a018431a867dd718c3f098f4e10c7782ce45092c6ea93d2dd139bee66e1ddf44e5262a290f31be60dbc8b163c8bbcb0bea107340a0da4577a4093d789e6c6d463ce14d19dc9203d58d4f77511c3a9f1a1753b76317967574480968ec0e3944b8845d6e5068a194a29a7ad502c843154d30564cc2a46478954b1ba590fd7852dfa21efba1da63895d7094c8c4528c7cf5580ac01ce8b700fcd9f59afaf960f61ca858e21e6d9467c2177260d931638d500cf10bb6aa5383d0d028211876b2e3b904e115f9e944c18496dd61cf1fa690532ea083163eceaa308d76f63d14e8bb568f5169d16656780f5d23b8a64afc8fe80a8a0d168af4b9249da7c88a35acaf403d7578816713acacea6f69253ef5ef1a6102c0bb49b5b8dc03cc4aad1964224ba0531ecb2d1ad96dcadff2f75c8e6624aea4744695821d90ca9e5ebf05e0a549a3522029e18f00f6b559bf4f1b13194e37380fd7d1636a6ec82bc74583c9e4f6905ea07980cd6bd001a4987af019c6d634b657df54085ed72dcc718aeddcb293638c5b1fee237ccc1ee97c2ce72a4018148215f0a1ec148504f04dd79eb7eee9e909014e34ee69b758a71632b77470c54e904eca281043fb1076a5b3b0b2275e3b9abb4fb678f73095808db4a5b39f68220ffb92ca6ee8127dc715e3835102818e7a6841760459b7eb0a344ad86843ebc766e5089540ab92a1ac1037a85343214b18cf2f23b137ac5004e8a7969dc07d945ec7fb70d6820006343629149475ac1d19388135bdf0590d5926787299f68356546002c5c49c13c74d75b6e7b2245cbab31152e470615ccd5cfd91969bcda116a7d75a9241550e676f65e1b6a80bf324c58cdd7f9558818466e985c06d2989195cc9b9983e7c04850b645c6cb11e0ed220ec0afcbe2a94b3e7cde8f047216e562b8589964d7f8ccb6f1ca8d33b29b23257eeb48bd19967ce00e8278cbcdf0827877588263e4b978f62234b28f01b0a684e102e410e1d70e0625f0cdee3d2d45010f716d4689e7fa15d888d32dba8507ca700ebe80898dcdcb1229f4126826e60fbe2331bde2dbfa9bd900ed774c00d663ffdcdc874ddc727dbaf4c21a6b8b7182a2df087bfafdc6a44ddd95af7abd8c3b1c6f46d65ef212442ca960eedb49d439a85f2186f46022d7bcf578b25bcabcd4498ba209728c9ce517eb1ea79f62c7011ee17197b0877cddb49c8f5b17aff7bd2bc9bd63697b9ddefa5b5beb973c814257d3d2796b2165b8f8f9dfa3adfdb0a078dd7903c156fb714cc06f3f4883229d30492ddf3334be28a28f73b654d468c48bb27eaa32bfbaecd67a9cec4f17ffb68312eefdc60bb9c18e87cd219c74b3c6e9d151d4bf2097d373e7f8c60d7fef7d8a70aad84e33fe42915387ebd49310434a30f0b9ed47f7c213315a175899233168373e4e67cfec4800312adf6e1ad429d9a94ae3b3306fbb7ecaa7167c23bd50fa7bdbe1c4f0be4109cd94225dc97c793c1d75556230439c0d187dbfc7eb0f727c14e376f9e90076e6724edec606697c5de05b0560766d918dd82d7fc77e0def112d7dd2718545bee94b9da9aeac5001e8a6d91d85cfc1c79856d7a341a9ffc5a7900d963ac256aa3596c5989a441ee86dff184f856377771fb851510bd640db4ff53a48fe0bb93f018b5a1383c03fdb3cba36ad02f3f2aa275474b1b793b57c25b4a2c323051d75ae0cae3028a67b4b4077c0b8e34b625c628128b1eb32eea418b7306e1a7e47fcf36e787a66cc1560cd8a185acec8fbfe880be832eddf8497decfebe243057c7328f0a58b115bfe5a246ec1554c9c653fef7b0659bf2cc44b4bf319231ae5a4ef128f29b9705cc17808a699c1f88c4b5c02015eba1d4d6d622a07a5ca1f5397b2c5205d5d127974faf782132c70317f9e282a1c75f70ceb01c3c3971e1c9dfdaefed9dfeb5b50d11ed4a99303c32ec32204b00f7178c7dc188660cae8c7ca51d710f0e568ccf5b25e5e2f37bc76cac4723539c13b19326e73db67a3fecbadd9ad330264f22a03f65cce3b661ea6355d2dc118ab1f2a7347b18af0ab0f6ab46a10c8fc0bd88b0a32fc6f12c8606ccf4620a7e306f508c9415fda6d25720c3694e87b332aba99b1a259be27ebb7cb3a111abae11d79c311edd2c3ea82e3e83c0b35c1445c272acc5c94f5bc2cb4915ef978d6306eb8611f1628980a6979c0e6b5029dee52f05daad79dc4fd6ca4daaba9ec6e03e4c1a0ec0025db6855e374749a95e116b1bbc68aebf1f49c26dd194a1c9dcec9bebbb849cf1742c9d41508d77167984d69cb52a837dace1fca426c5b2a0587ba004a8f5a4ebc4eefea24276201a901daf8377c0191eccd823f13b2e4c51e61e3aee426a1b15a95be33d04ebf5426bcd01e0166cb15b03c534f757f45e889cd1683d024480f50c5617e4bbbd749d35c3036627c80d599411186b0533b8d8500c1b97b06bcc3a2dc2202fd25db4931985c2865b4517358d53bcf22255656b3a11f13287921878fe83e46fd5ccd203b937c7d4ee4a7580670d077dc2fd7c9cf14ec99d55ff44936c5f40242207776cc19b1613f56bd6c35d9e5ba6807e2cee0519c7d55aefce82e38d4738e508d1b025c23330dbfd283933088afd5e61f44f9461592fe9877e8dbb86b803472ae98ea3434bfa347bc40c41a991dfcfccdc80b0d070e7def92a326f67196e39d85be71f62873cc6bf0037f597bac5f8afa06d64ff9f0ba4846e8855c4769fb8db096689c16998ef5934aabe1c6c248ca031d0108e7640106d2a2222f2c2c0b32ce4314f404f364a51f1e9a264fc45d8b5d8e44b8278cb5f21e00aa68f6fd0b2c37bfdb34b51a49cb3a753ac9d7d48a5de2ba5a355d3c9cbf9782ecd3765820d5064672fa59cb414bac5d7c3fca2b0f49d80df3e5da7c064deb1f8d45ffe6db5118d1d31d0291a51781e16bcdd7e8846c0bce5a44d4e0e08f8a385e47c8fce494166ac84b7ba4aa690187a0c0f1c69cfaf1a04f8f4ed9dd7f76836ede92a35d2547d7fd4cc1adc3ece791366086b0a4742fecf8bafe557c3bda186cc11877f4bf0122a64d0e7132660d9638981742e52f38a1b97f1d0a269b012d008a2d3374cfc55c17c3fb607125d28c8d61046e5ad3df033936579706ba5ace7113a3bf232bfdf922f464b51acc2177a3710d7283240c79b17fc8ebb685a1aba2e4fdaa44663228708371c86f3eccb15f7c1e390825a621d80855ea74f8ace91a8d9f6ab64dcdc6403c15df8447be0f51d09c26ace86ac39cf2ff7807e0d3d5ca901b26bfc7674072e1929a6b11e68eceef8d7ea1fdf9ce4b16ab31c6676e0c00615bdad830cf26026b2b204812a7fef8db23eff207f115fe95aaeaebf190a4c599bc2a0e8ce858701785b8501183b3c33ba9cb208547ac800dfdb2693e5a9721d62a3b2e99cd4699c21c5d798a8e5a2208dafb6eae926a3e3caf67f707c83b7b8fefd40fbc719e58c986a62e8f26e9928b6169e8e0fff49f179bbc63064e7f6d98ddd71e424819d2bc5004f98093eac1acce6961ed3250ee3a62f59ec18d32235554fb22d95ad678640808ecd101562d4922687d97244b77ceca2b5f63d0c91cd32a3071c60be2498d958315c805946512024f45981f52ccb4fbc3da83618d652d6f73a60ca98379ea608c91747717e61a73511044c979794bb3df93ab23a594f2ce763504fedf205c425e65b12eae8e017d0d4fbb004695c5e409c259d82cb85f7f07ae8c1b6894a001d6f9489c8f676d38cb1af25d7aa975b1527344c3932d7475865f7b82ab1d9f170f5c43d1c19136938c7efd15fa943d7645e78a3bdfe071b47583569ffd672b33f9dafba6ce3250c22c6357c49c2aaadd2c4880349351af19de21c5e48de8ca91020b5cdef43d5e37a2c1fbe25afab36dcfef1248afcf5f24298f9bd2a12ff89e237172a8f40ed0662d20a38990b176ba5cd52f47ccb606d47c230b1b8f5063ea138e5019c165ed090ea733ef59284869094f9fd5eb438b48be91ff28104b862a05b494062b3fb58365e805b1f05cf6a56b5bec4e230613e0129348b5b6253cd2ce4318c1123aa8661899577ea44ed6ec7fccf11b662216e8227079a9fad041872454ab7e7cce282256e62d3430df18f1f81d86b011e1968ac1ad296fe2e857e6eb624219f3d5ac311a75c8e5b3288cb0fd200c9f5f7c49df3ddede95fef1fdaff5f599be6457f1c0156fe9714adb0b853e507a00a52b703a169284f5b5a503ce2d37e3c13f853e7f87120e68c323669fb6c0fa8f34e06498cb1d3590a8208e62f044fd930e196e031a71daf8d84120278a6d00528ec5440e61f4c1a84a9ae4391514c420bc9afed591adcfd02f96069a16b1a77ced3b62eea851df4307f829a46b4b2aa1222bed7a76cd463443c062d05d9e6b1b5413dcb0859f3fc25aaf3251cada740563801acabb4aae7e4fc98ab8e48475a904e005760593083e95f1eb452a9300bb31c6902a4366a4865234951498114a1987ae6cd1ce55489787462f98266fa7d449c3e2f2c0760f2bc939beec05bc0ca002ebcf29cd84ff74e5864543c5af07189d7fd66a0a1fa4b90b995e327af25690b2bb949e7d84b49363ac44c5046cd5e7776ea01b26a8624ccb065b7b12eeb9f1af123b4b098a632df2ddf3b206f421b267e2e33d57191066c302eec891248dc22441af82f64f41afa5cb9207d41095d63929b87a775842a7b5213e177b1b457e001176055e5934e9529a2feae343f3ea30738a5af949edcb7723d5a2025d63923e9c229b8ee256801ca029155aeefaa527bfb85650e3d97d673589199229a917624a102d791791d2a2f660f7a9c62c975c78094ba1c1829f08eb49cca90522889e33646b1142ceee64a3dd82299661792c862a39ba237752ccead65ea1cc61875503c71d2ead43c5fd88cca6a9b139d4ab4c9b43f74ef607dba5290b218f0bd50dba0d86efd5de3544a789ff0f2d9cbb62fc4d92e8cc95b06b512c4c01916574bd0e5619f8a26848210f6fb3ef1ff61e3f4237466fa9cd0232557372f1417790fa219a09a783799ad9c5482fdf156be7fecb2ff1cb202d8d1a06950296eb2924009a63b229c73c81d571c805916bbe1f817b6c6edbc98383958b793cfc485705ed70c6a0966da7a0a5e2750cb541b9a62ca7df7716ca910297d89b4749aae9f73ad2a876e5a47c9a066f21b96a010e6326a31a6faa375a1b7cf99f8cd3a80d687fcd45b7c580f0f4a8d7abc5ecc1b49f6914f349310a02e434de5bfc02a2e8b4811d53e8e782730bbffe2157d74cf39e9331d00e959c4d971e209058d8869a201fa35090d1796063ef863bb3e709544a1a119f6e29861a2605913d3890264efec5e3fdb7c074c469dc7319cf3e99086762902b0ac24b7dbb286efae5bf0a525935d694d39589ae5245f3af21f2d10ec38c85d74ec8ba684ffe45d3b3111247c5587d36edf357394d724ca8c2f02bb6472d093a26cd5be72ea0638d10ac9380655da08cc49ac47bc2fca4ffd3a0d331588d371dc8d18a12d0b1c9447b5ba234c0bc671337d66710e5feefbeb4d354f88266b41b2fabbae24e09c5e6d81394855c9dcb9ea4bf94b9850f948da4fa328fa621bfd148d54f879fa38f6b45529869f61a99d7073ce0cb645396645af8d294dc22f03f25db0bddaf0773e6c6ad715158a0040f4d90a91c8defcb64fe75cfd73405d4b0a7d9bced3209c02516f611f82123aaff020ba4af7140a0979953ad78df953d85f0339dd848673d419789ae9193ba398036519032a1018b1db1c0cd5adc9426e6d4276a6b205b972f9380359397a4e3243d4922dfdd9cc7ec6a79639da287c3f42c966182bb1f38a157abff75b40f430251af0c652842c492d28d0c23ddf0fc47f0ac6341bd4b7379af6ef24504742afb64ce9768649f07d9a7186ce84a8472f382c45784d9f70d2c44ea7d5a22782304e6238d4fcb17e0ba6cea961523a3a15f9e6437fa814e38d1b3e55ee5f0d9a9f2367ea4ef72e0af9de2ded6fb869d9210c04329474960763de9be5a91b16c79b64a11344890bad2beabe5a92fa19720c611f5669475ab5aca482c041e6fb0a822a1b073006c3c3718eb194ba9784ddb3142a5a32cabdad4cf5bf10ccd6a28a4d870194da88a7fc80257aafd57f08ecdda58239f4e29414bc88dd5e1e7d701bd43fa625916c7dc7a59f362f79152012b71acce949d018817b1761a93040732859a1a984b765aec20b6b0ea0d74d770ec4ca90e66b0808c7d713ada381b629b4e166ce8221d8a75f6c33815612e687ee65b5d478512545a54beea52995cc0503187b05950c39b16847950bcfb56d3e103ec73f5f48816f8bfe459765e8cf071e30a5f91401298625ade44efea2027f7914a3e604c4314a080b32d7530d2d6e5de0fe99eea43d13319b1fb20694334a90f1525ae7ae7a06228a8fafed67d1bd89f3e322196be04cac6bcb10fc77d4bd26fef75ce3b21026f6d30f2095f00820313c144591af411b26c8fefce9cdca1b3b48ddfe1d1d7a72fe65fc2bd3273e047985f60fc51b47f2ca01dc978f7ed519af58481b08e06840a6aa3035c460b10abd8499904eef64c573d5e131bb71fe2555eb0c5dcee9ba9acb2628ae33374ed061fc7af668033ce1291b7adf7db406e704cc1a8b15739110c5ae62d4a251f40815bc219edebb747d182ac2082399284d5edee2e63533ca0a23b904cebf5e8e16c854bf17355f8c6c684efaa680ef4747ae6868707da580e2779ab0c7c9b219065c409aa6210a341774de252aefd80e010484b870d1b5a5b1c0d52e36e4915265ebb23753c10570d4526b1f0e8078cbb79340300219ce9bca11b0e8f705822a1ff4060a37d4f4d39ae5572a13f51d2e501f9daf43f582ed4dcfac8c4b863200017571ec9d09bbdc5627ff69be08049595f4cc3b98fec92827268423515e34ab754078d7334ccd6317b123bed65c5c6d7af7a30f21778a3e97a7af184567bfd191b7b8d6608d0f0ef7e74b459dbb5f3c08cd7d9efdc2e59b8348ec5b9e90a5181aaf33b2da7431c367a216c590cc7d691746f65c3acfdd448577cd3cd25a96e0a3a635e61a3cfb451b50f09fb93ffe439326e3edf6738d2b8fcc5cffb9b2e346390b930da33d781306531a9f4efb15eb4b9ceccb39acf827a8bcd705c715c5cf39c4f51afd65ecb055ee33efb5a50c34222bfb657ead15c9974dd63638d94d489a91aec1417a297f02cf8f4c1927fa26e152ecb54f917c2e1bdfd8bd6d99118606f125a010f7d51c2de63e05cf4722515fdbe26560a062768aea2f4eb7c0706245eae752ecc02507fa930a42ebfa3de013468b3f1ab79bc128a0afbe8e26b4ca04857ebfd4c27a00287a65f1eae6851839140ad1171e01c3e209f6d5025f1b2e1fc20cfddcd85ac3e30bf4b2a3733046f63c2bb6e556d3a0221e6ec46a052026b96b2ab0adc7a66d086cf9fcdb2f95ce0e20459f683b32146b5b9f9815ae651e714af914241965adaf38d2e99a15c876249853d09e105e9be4d4695dc28c95e207200c8b3ca04dab410442ce37ec9e22c176a7e19f1507d49800b09be62dd243a94544fa93e4b5be327844b372500a8cd91b47c5629a92ae5e192b5fe92ac13457e8f2f9bd15f5905ec3cab2039c2dc6b38acfb6fffc7e0bf4186813868e8ab7e9929b3261f788eb9b0bd6700c519fa78b81add9d5bbf6d15db3a50ebeb8eb866a33c21202f4101e4076fbfb2ae8e083920758661119fd1ea68a249d4ff777ee3e86f0a5d70ef23f810968e50f0a0a55ea1385b4450f4cfde7660b08669f662faad44b8334d88046cea44d99941bb0e9be97391479b6ba4d6ebe58deddafff1f0a73c076482e7b08564fcceaac78ba96d10d9867771757308197cafd7a502ac1d454ef87093c8f9114433d78d4ce48dc1c8ee8a9641c1d9d95454bdbd97ad485679bf60fcff77d6f05859c5fcba60ff72c4a7a8028f89afdb5740515c640679040342e880e3f138ba3b +Params = SHAKE128_W16_H10 +Msg = +PrivateKey = 070000079537ecee1c0647d04547437ca9ab78625946b04aa7e0c768c2cc3db91ad1e402728fad8d287ff76d6cda969df484defc966c808757242a4b86b76310a2a2909200000000000000dedfb899c637c4cf0853585395a9e9439d306dd639db1a67bbdc07c21d9e050438ce94c8e4326e6c56ace0b496e3f1f862ef0da734329913f045b522068eff33d5 +Signature = 00000000000000debdde700cbb43a9be98ff8c5460f50ba66b56e1d12513c1005176e9168914102b9d80c529960b0033c06e68b8121e78abcf83276731c1bfd2d34f42ff4d8d79036330bc32724366c67b8c3550aa3f30b8f3c820f146e92e6cdce536fe87726bf9fda5b9685871c7a467ae9f9fa98adc0af8dda0e122ffac6d5c4197a4214585bf30fb33181b165276f5c99aff3285a46ecafb91cfa96805ebd3d1ee1a75d6eb39241c0e15d296d677cbd9a537ec8cda0f8070fa69d9368eeac5c9d51e5836e1cd42f646c4f165deeb4e4a3e7dcb053048192da64b634e11c048b932aae0c3b5dcc2be1d18f9a20037585fa7dc493fb2f281e585524bdc27bbf080f640c028578eede1508a2867a2445236aff6b2299d1c631bbd63790693df8cbaf1a311f448bfe9fc382636fcd06945e04b212df9ef1a5299695755b6ebcc7aaa00640975f9d32f4b249be0734407af5d80b168cd0a0f5881ceda7bb055ce6faefba239526a5292a40d6e0e2b5ab6c5ecb595c3654754e4c2e5b70e6038be712d7f60edbba1ae2ad1898d116065fc7f687261449cfca4d936e4c4e0599be73ba6826a5d2b715719d8c6445e4ecf852e665028b52d257cb806aad4077c06ff7149eb3b1c489e7a4978ea3e2eb5381790786c4beb4f003b527b7a10e1c675c198bc517f11f12b0a6a871f95b1a804d132e48b57fc56883fe813a6350414821c20251ce26d79418904293121db8ca93aec01a07b2364d28d1bd6cfb3c1a7c97599e70b53da9dc3461e89729faf792dc77914d192a77649b3ee416ed8025797038bf2fee722322f52d96faa6340e8d65e5aefa4b24cd0ab5cf68ea817842596b2a49659dbe42ddc7bb86209d8f0685367bb7b1ccdaa0cacae3704ac6b532226b37719c1d8594921c438c5f1a4435754c1e9bf9dc7b18a0b6332594795dbe334320837bd42d6fc1c78f24911d6976514b71c71bf2fb6f0d829ed650714e3f53b779d7c1c9008dd3b739ed3d98d5d00eeda830e3f36973826a8b06b2f94d3d4b2e8f2b30edc19a9339ba043ec7ff654dc0987df7a1c34ca7decb95ed9d8c9861fcfb5a52f5e73b9aa09fa9cc26e9d081d3ba972a5fb0ad90fa0e53a28ecb9c1f9c6dc2b42b4da5ad877ae372def80039f42f692a4b97fde4458c6b568e61064ff5c3b0461a1fa935641a2e4a97b5575485951efc5a4c6374b537c8cfe5e9858591d87c3e63393b07b4f1cf77f3f01a343a9c1931e7a594518201ed9606cd46ca1cc2a2e5b4bed13594f96cef519fe80f10bcc0c30c6d7236b2046d6bd66d9b5e8c8bb616c20e7ba86deaff2f815fbfe0c3ed35cd901b897bd5da09596c9b63519ce7bfa4f5c8f11ab80ab81f0ee968fe1a2fa8e9870284cf908a85a18ab6d7b3d2ec7eb53d47c34663d6bcb575a9d965027632b9a1bb7147e23e7371b9406d0c0a90892a46efed3a1d508202e2599daa932b6fdbcb99c750d03766a84c427709f701d6bd74b367803deb1a4945643b71c2b11085f9ed4290f5e21c568db5561353734111bc4c32ee9bba1320e4a816846410768cfddc7e5b4d4304072f1f692ef52f6342bcd6f6804fb0e63501db7ac1a2298b47c08370eeb89cb8c33e258bf9fca569696863a7cd69f0ea58b88ed21b81804789f3a1fed2f5005c605d3b408a3b0819acfb3aa963541c6bf7da8c8619d9faa574ea03dd2ac16ae8bdfd451de6244072a7c5eb0ff0b7f0b2b0e9db1f82afffbdee121af10643a275569ab2aa875f34fd80a7a1a8943991aa0ddbae6dd345015f54060b5d629732708b30e65ae556cc6e78b0a5cf5f50af8b683192397671a48e1da40266e06d7b58002263c709cfa0015dd43c904b30a03763721f0a50111c62354ee2525f32b579f01abbcd6c2c2599035037e4e3e02544ba7339f7ecdef49dc6f2cbdfd4cf3601bbd568ab007b59f13bc9c2833bcf8ced9462b922947dcef8bdae028c5b9b7087de900bd1bf1da597a8d2da2b7b1c03f982cc6869903cbc29b0c58a99276ba114023f25b19b60d37cb4f94e825f569299421a4f74dc3b2798efb32dde721b311c65df8ed42f4bb69d408275c095591e02dc591a5ccb9c84d4f01b4b582a7bea8bdfcd65990ae7e9ad063c1b6fb7811cf104ee9b08ab8e46e23f85eff3e63f89af3c924472d8cc26af3e784d4cd6e3d46bb2cdcc0040cded63629cb84bc45428ecfb96fb093ccbd47803bed4d55cfc7830663da359bff981ed072ae96ca0e1361a45d8d14bf41c480371975b28976d3396b58e294c4249162ec0ff22429b34d992ec19721923d06bb9d3b887c4683f60396065aca3502baadcb945bd4f8d0290e3b7bce115eaf33f3c5c961a9c43ae7be38e5513407043e9597abffea615c278572af8c466ab0f2bc4f73f563810d74473a00b1126251a40ca01e7f2038ec4e303b88c6f9e24c87549eeb69aca154f6a983cc8d77d140fbd07c4c635c5202a4694ccf0e94ae9d50020839d59580047c70fc1c12b2d207f5cdc6a377ec8737e1acce80fe3d3293e7c14c8da253e8cecafd1a90370d43f6af28b717121ed5e85bfd8f5911b2054134f3aa0e0c023bae4e5adbcb3ada528ce1bdb3c0f1068bc6c528d05dcee6f7315ff7703f7536b79e33ab34f39072a84514c1ea7b414cdeefb6ea5090674886b42dc2a7014d1452e711e9de4f29e1dd3cff9b8830943d8fb5ef7376bb247082314ddbb4f56218c9bc90eb48e21ab1ff77c786ccaacd8e401eaf0f28c657bbb4c30fa2ff41705a694d923d9f4f3fd6237b619b119129378706c314db3ce4e7955dd6bbc0c7169f876a8cebfb5f6bf0d798eb614dee007df4bba69b48e18365d4243615095403e0ead133cba9847102d83f65c926bd6438b6745b526c55de20b16907a9756fc6ad1dea8dda7cf81b9e15fac00df9c4840b2ded41206e2a492d1e24bcd630fe8a6433ada9049befaf1851f6b1262730ebd2c7c3e2733a6fde3bf6a0af18ae01b0cc736aa0a36fb7d6c4d293ddcae40e1fd725bfdebf9cf153e3bba1f7ac5be393c925a691e22ee692b8986b99aa7bad8d9a932e9d18d34ed1402943fef123b3e7e12fba351dc81e1d7c3cdd3eeab5f9694b1e9d36c3fb0cf009c7d0df5df8ae2cc4ddbcb047ea81c5cc42b3e3b626270bc783abcae0e679b95f034ce29dbc7f4efcc0dddc747603749e8bbca16e3dbc618161ee3431648be4128b864037cee66944e3792e8135e8dade34c908b5249378874fc61ed7541d7a363167e1c73922afcc2071352e03de58810e347cc21fdea5a963aaaf547fa80708164dc98d09502365fd4b4f496fef25366d7e9e6d83310623292da1abac657dd4bfaa88ff69d4e0e421540e23b6fafdfd9f40c99628164feda921f9fdb4d27765095a9fa845628b1c01267edf464577ef82fd0c43d89453cb8bec2186d523e06948a8e6fd4ec9301c30d88e6b6f39764f05be03e36555356220572294da751e4926465bd1afeb93e17f7c06d2e149fdf8d7af284e97c9dca41df9ca90060e68e14d7506fb5921d56ed8e340 + +Params = SHAKE128_W16_H10 +Msg = a2a50241278f92c8ad617c84331ea21c60e92afcf0e48a714ebb75d0120a9d8dd0556840e3acca6c9a86451a0d5be95c2a25ba8331e8ad9d842a1440e90509ffca5ae64ce06a8f5b65dd852b69e8b88735022f520da3e29d99dbab904646d8bf58d3344048f279aeb1669f3277f0ebbbfac2267c2b9ac8b989695974adcb35eff3aedb675eb76339cca31d6a975a2bcb9b37d4e9d89631543df3c970b141c039059a8a7e648c814403cb7c3ab0051c051d1973c8738e6b6539f676b8af827bb3f33ff12bf0b063bded6591818100f70cd396ae573280acfa713675d233c6fd0d2289b7d2f1de03363414bff3f6f4042275b7baf15e3996f75a61b22a583666e0341143560554ba15d889cfd9a589c0b7dd7865a3ae70e40dfa0e0fe35887d2951740728f874caad076fd0b0e8ca4e98b3a02aeffac91a906e3282bf7c5956c96d242aa1135f897a4059c5c85aefedebd17955b8189df68dbc7997ac06c9af18f993fe44e438cdcf2543018028ac893a362c1dd47e155dac60f90050c03031aa8eebb8479c4007fea897e272b049b451183cd9eba34a451c0e1ae3432185ac0b4 +PrivateKey = 0700000718c654baa192a0a438f785f6942cbb325bae26cd4df8f729fd9f3da7446c0bc233a25449dffc6e8df1bd619c99ce37831ca1c4a7c9e897246809923a9973fc32000000000000013e3cf18da047500e7e6ea714198c89139aefa72ff7d7e590c26366e094afe1fc2eb651da65e74070cf608e222a4495d0e15bbe40f3c43e50837e7cf50e703cdef6 +Signature = 000000000000013eca6f835778a14ef126b352b524091a1463535d989dc84ebf715116276b6a74d86bd5b34e3b2e921a0a6e4da7d05b04a923a7cf580abbdeef7813f9a9afce3aa1f71d2ef79af83e183120012e07197dc8c9b1ad7bffe5debe5b3a8255b113fed8d7371c19b70580cabc2c73660d0c13e04b9caf89eb5dc0908ab9e19555671d91ceeac473d37c66bc1736a87b13a3e0a670547e3e920d5699e0b74212bde64f280de61df5250a931e93126b156950e2876c729785ac49b9cfebf8ae8b345ad819c0c3f94540608dc441c33fb6ef33f759be6d0d87df90712edb06a484b631c52d6fe3438c3075567dcd07e9f2776c9f31a7acb90fbd4d20523ed8b5c6fe4dd9d7eec148dce2664c80e096c6699de64be64f6c655db514a95e70d097475399738167b2b1c23cdbcb1615d1bc1732b600a177583522681e285928ba13efe4cc5b949105d23f24529a11ee289f356f1e9e66d05637ce972391e9ca8610d50ff8bf1dae7a96e6dc5c7eb308b0d95f3c8c9f1d2473770efb9e8fa4df6889578b6ba5c565149ef428acd122df433fe750723cb65086dfd1b56ff0621cf5cbf609f6aae768bf453e9b0841058bfc2523bdf67729e110aaf83279ceb6fa18c9069d86a4f1edbc017602872349820944f42d74228eb7bca86321c88ba392d87b0b0a015ecca04c57f8e15ed1b26254089a95c3d684d24708c8408981bdf1dffb4b31a467a178a62152a127c708ffda4b82925ec0833205e5eaecc697ca1f989c9a15c0094aca7e53149493af81eace928f0a1a06e477b2242869356d633a3020d34cc9e0a7440652be29c89eef4a6d249bcc784fe22fc2963d5ac317f06485bdefeb07342a655098988d17a427472863ff6c0182063a15065c59c977330b027b8e9869f75ec8a53962f77c8db011dc2dd2fdc118205aa0f32027ee134e42939a60d6db5f23c727c74623ff0688626da4f355c738a5890305e8aaa804620cab165e3c2ade82ac1febe49bd63d8f9d815be02dd6684c4bd61fecbec0a309d30c0cc4f7f09588c6a39c801db86822c8f96a2d2dfb2e7088f439a08aba893b55620de605103c485e3830f040b6f0cca0fa3805576e6903dd22052e6fd456b5d18faec4543452d57cde0fd6a993d057f81a82dc24618d619b9f6c114d587033c7c769cc0f6a1dfdc18d329cae3dd4710fd64b527f48a44ec365eb20af450f1f7715a1e37356ee55d47a813fbd178aacb6a0561adfe72decfb485f033944f268e501902782ca21abb073a16b71dfb063bda60cd8f7db8d8643e24c6dd994fc83c0a39d672942409f53a24a72b1ce1fe2b13b5fd8ee3ac08bec6f9ed51cd45119fee647a951744f6e4590e12ff4d22def1fdcb47b1a9bd6cb8cd934dbae43858b29c74f2c8be7b8a06aa2e2fb65c32e36b375439a41d90d58152132aa4416aa0eb8b5c5e197ab2f0c8b1e195b4aee0bfd2c7dbad5403052c77632f8c68f6eceb7e7d3e3fda36ec41b02c91b6feecad03f48b968e0725d54baebbdf9953cfa115d380948b62a045ad4e03c4b340c23846d400c8f0e9e380d4499e62fa0bc05db160b72eca3475524b56b6dfac5271edb64e139ea7fc2b3c7617c2436aa4727afef1756bec676964d7b4c749d6beb8366a85123c0fd3b9eae24d89677b09a57ca64b49fe3660fe350fb163992f19a6f03952f946292b02ca0fe1329770bf2cfba6581d9f09ad928c2ab185bc5bf5fd365e8b6c67f365b5cfda63687ccd2b2c1c8864c265698caea8b7051a3424129304103dcf59d7292e1f3d1764231a26fc134f4dedf13f9422f10da5e76ff79992b7cafcd2c00035ea987b0e713cf5005972ec678e5d163352bfd0cde361e6e101b72c14f61bd5926f961eb0c3d94d72999fa876bbccd489e5f407c287aa1c5ec0df90eceee93cffc9cb079234f62123e85fb89180edbe6b74ddfc1e910a7d864a133eea7866ee208a24d6ce40d6ad163c648ac0342ba881a2af4069669926c77dd7adf33a5a5108d0662424102e0183c0eead65aa8140405b4a6c705ae1ca4c03086805ac22e46609cfea8fbf1100114bc50ed781b8b66e898697dad68c9c389ef61955fe24ccfba2f5faf8295915f22be1259d7dc9180ab79532a92272e74adc1dea57c5d91119004a83a072905b52f0046a979c13bfc104456603d36ee3bf36aaacba0c8192244c3382aaa548325ebff30e8973f690db4130a4d0d8200df6cb01be86d7e2fa6586a32cb541034e2cd1e87d256a9414c49c88192735680919071d84877dc7045db9debf6acad8aa281da5017ade13aa14179e463c775a1df0163619bddf19ef74c2d3d5877b3262fa0ade9b81c64c0db12a6c829f557d8792aef8163434e2e5500d7e7f6898990f0e813b88191b28f46bd69234649f06ca5d788a936576fbc38f1add43202be8376d1085040cda2f6cad126efd579ab08e547ab3239c72d5e185a3dc576bbb02ece602c3650e93748ca53c60c4252de9e8dffbb0a74cfb3a6a02219b1d5930d297bf92e92b7d2e0bc3eca1f13f54f218ab6f3f3709d71a7c53e54cf0867c8ffa0777b0111adec10689727d25401d531329a8178c4a9567d750c41768f8f3b522ffb035f4ef25f176d5754d41fdb054153995c07b25dd59275a08c20332c06c29c37110a912f1eb699560cf781dd5a555eeee28d53d57ae49466855598e75f33f56228da802be5c277ba1c678682fb5202ed39aa3078dccd5b4a6ca7ac23e45dae6d00a9040bf911660f14bdeb7ef187c910a845e7db8fb0fe9bc5f4028d935c463d69360079868340685d66bbf115b6ae04acc2be4df9103c539891e8057c8c9222ae570a35efb682e40c10028dae43dfda9a35b100ca1114ed17985195d67493e8ab81670491307befcaae25ba69f92f665ea65fb8a5a3fe9760358767e7c6e2baf5a5627892618f1cd786c8987fd17b1f132470b0669a08fc6b9b417d6a36b2f394e9cb03a1bd5d63998b2e6e7913f54789d3face9b8459243bdd44ef3a0b004b608989cf4739ed718aca318e8cdb146dc0daa2283535c9d1b4346d16705be19a39eb2119e1dbda3d2c91202ab3f600ddc21aa77f5c3dfcad53d18a0020ee9f456b00ea60eeaf8f4b5eb4635a21eb7b0a85abb8b645eba29c1fd01d59b64adc8f50d4205bbcfa818d77b6da9273f4de212916cc28f1a7b496034aac85e3b2886e150684fb563d8e337cbf64ebac1a8d056457632d12e5baad377565431d5359b98ad26e85f4c9c89bd7b7e8a61fe166d4aa9c5b23cbaaa568bdb40fd76beff7cb745c0ab9bedd66ed4773428f9878091cdbf7744b186cad4604b50a2f323e0693e842007c3b4b1f71e908da89ddf83af7d9572717d25edb3dd7122dd5a7170f84eaf45f13e81528cfdfe262f59e1b218264037f2523a7107039685dfeda0bc3a9461015e2eff310245fd1299475594782a13658d96cf738852c762c037865cf3ff0f25a82c28d7528906d4623f7d1e692c3ba4d5e7001b10f19cc264a93c59a5737316474037fe4646e81fbf1 + +# Params = SHAKE128_W16_H16 +# Msg = +# PrivateKey = 0800000840fb747748992598c9ef276c7a3d4267441b36a5f6a4eaff941532bec21fd5f0b9af8772ab881bd5e7edc8dc9051955dfcee0dcd673c823ecf1094cc9f009de1000000000000125a26b6f6ba6f969c26ff782fcd49c906a8a02b4b4560432f86cdb8772b576b1f37b1519272304ca907bc5bd936a360cb1de2a0317470ed12fd31d0ce1827d9c177 +# Signature = 000000000000125a4be9f6c05cf78a850b3e86961f270a67eed71f9fbb1eabdf1876b594c725d8f60ba2ffd24dcbf2bea442413f8eecffa036b171504d693783cb050e35c58f63806d60267eb93548d1d07c4c5ce596e56640085fbcb03e44d83f43fbdd1151e79212e2c4171095ce7550aa8f45a313fc9b28a9070d4c9b447b05d5d5e358c8d206f91f94e06a2bf8e3845833a0016ed8394ea3bc93eb3020c0575177a5d6e0692d784310d71aa016c9097ed52df7cc38ee67f2bcbfb179a0332a996faf50da1efc531d96ab9fcb443997240278f18a8277c1808e10b974aa6bd1995e8cb21d90de4e02298ce070f5e1f146ded1e66153097cd872f7d1be2692b7b7f9e40408f8c15160a7aa87c4041c475891c0197a3d78bd34139f79d6467a744196fe3473f958be7c3e9c940ed925b10f38cdaba43cafe2fd395e32d0b7be90311bd015c9b3ea747bb39a1778cc0144cd64820478305d3c898cbccb7a4cfffdc073c0f17ff292ccdaeee5b9a4f814b266fec7862dc3ad52c0877487c688ffe728eca6415e1def48ba6d8e8f7c9a67edccefde140f5df76dfeb3d583b628e3af28380324c59fc365e9c827adf5acbfab72a2f19ae736129eca8747a261be5c9fbf283f8281efb76dcc4487bcc77e51e65c393d4933d4040e3481f99c477111f832add067ef4dcebe698ca5717702019b3f63e71bb7239150b35d6f2fd7a74d0af0227a45bf541a0f88d001c3415f0cbf4e4935f29410bdd838970810979a1f8ab7d467ec5c4853e6590f8f59c639be04446f3e1c90e5aec65eefc74762bc49cc352ea8285e4387e9402b46796cb9a2db7dee3c6d1f2c40aa2b7e95f5f4f2f2c7e3d5f41bccb2b003c9a797d3c265c9452b9b98ed8f961626d17672de2338930ebca2c53ee39adb7a049ba35d0d18d916d1ae410d181ea7073afb98aac4c63f805f1f67fb390003ee6c57b3f43193ceb8eeb1a22b1488d6c32cfc6a2af3b975b980d26ea5e129a08f731f62a4c9e23f0308e27b0d51a47d931ee9ed71dc7d735e443ae35972aade3e0ae2a6a1f48cb3acc6511590a9fc2ebc9eaadbd5e677617fbf407c3838d1e00c146046ed79dca4825f402612248c86cdb2a38b6ef1773483fd81227ef12ddf9d924f321612281ddc2f02eda61c68ae9673b08a0360cc030dc28e1b7a57e8c5bc2a9bcc0d6927661ddf8e72f44ec2cfe62a3e8b4403c955b6b237f299f858aad53552f780e48a69f946287f81e0a07b9d9306e06e628922822f9b210035a4efa79db3659710a8770da4ca7f943133d466ddc9d22a3d086254fbe0a7f87183f6bd011b166513ce0742fc8549f247bd728208eef6f327cdd583f4d0ee6d3cf4278ac15c48853385ec748ac09f0c282d99c753dd4bee5161a6d0722507e0db0201c8025b04eadf40a1815991fd21d73afc7d7f3b6759f1c045876be75d07ca66380ac8fd1e69fad48500e84607acae702b43bd7c090a4c700af2e7fec6e8fe998947c8c1427e21b211ae4425ad8f001f48f5f7333f69f4e5b1072e85e6d54ba019274d7573ed4d810f69fad90af0820b51fd79a658080716b694742e3ec5332be5465159294d00197b149b0da756eaa1814590c5db6118ebedac265cfc875ae1ffa2fa3efeb20113d3d9d57ccd4e2b2c31e1483b1724701b6f7411f5abf270ebdcfa7f59f9a7938a17e9408010d8b36f3332810733b14c844dd0b51765bb22e5659b261d6a00124361528ac23ae66b3c4904e40b7691b81e4e20370be62ae056b57c1fbffcbb6a0d3ad371ffd5b4cc27ed047909c8e248685175288eccac2e64f39c9af161810da5ad27845fd65ffe5038552a5702856feb23a4d1101ca9765d7e1c4954ba480e920141fa78c40597b2c8126d7a212a6e812e6bcbf2356a9142765ababc33d7202be770dbe14ec2495221699600aae7ca4ea1a513f5af209efcafff7b77f8052f5c5af3f17f2b6732183ae0f020845d12c70acd42a4c42a94322751269021fec1757c4538d2400f56cb581f92032eb4d1f291278918c469c9089ba498bc23cdf4d9e97d4b0025fb59644a56222616643e5dd76beffd78e44126ca00c846b680270c0b675cf1b6a7f226152e92f415c00cc43b3e7737faff88a0faecec8f35f75ed69df302b3b37c6a1126277b72d231b9b093cf76a430c87a3ec88081cc139ceec64b2d358bb3523a91538588a9d6c28825e3b0293f7031580d3b46606c3ed23a13a4c777bbbd3c6ad0dceaf615436e40f25407c79b5b96517ac23343649dd4343378ddb75aa7450b0747121c8acd216eccff4a5fe356c1eb3e225cdc619de63afb55fa2ce5a468ce944d56fd065075675fb25ac4687f33ca92f3587fb61f8b01cba6807b3b7720212ba5537e8b70c7212db1700ca093a02b2ba1dc55523bed2f03cd90d4d5917d59ba959c8e32913b14624f60b8af61a516710d6cd043c9a54fe3d9dd50c40ca3dc6f77fbecf13a9edf8250b3b17bd9ff4ba32afe3770c47218152e8ccf9f05be964e9f14c094fc8fe21b2f454ca6b81079aed652c57fe491d9cf63dc834e169e64941d15e4e52fe3859c49ac4df41cf68e6cccd840e882d053667184a3f3a6f203984040f92dd8639ceb188cd774803bc8f281c03c7982d85f6ffd12823b5615fd263300c4af3b0dab7ef5c1430a027af10f0ab4066b07e6dec3d169c95a90cdcf210b184dd920a95961cf79e6b940954c0cfd0eead98586eb1f58e6eef2036bfb8744d3ec2736ff7e941eb121a9c342fef5cdbdc63f87aaedb7c49fee7d99efb6d1aeed728632c3a0bc006946810d1661470ed33636f227433177a23600306a05b1506936c25d5984b97992f297f6cdf24ebeb51c51fe38f5c90a5bfa5bcdc728c5bfc3188724a4e5e629920821810a8ed2319c0f02a20f9b3cd075c3b5dccd54a4c83a7c9358e4464dc363aa3aeeb3cf53b7916d4602091f6091fb2918fcec29e8dd4a09cee3c349272bf20f209f1a6156d38ede2b1a1fda5e5c1a2b945b54e5161a1671bd75f3a76c44db846a81eee5dcde9a2e14d142d8c8ed82c9792fa6715a496fffc76d5d4c2acb16a94b6b2647bf5032c9ff4ea783229feac75fb0dec7152fd4f2f76fdec37b81eebdd0e9343b36ee1c1d9ab78429b4805d581f4cd9cd845ec6519f72c75781dbff7d6ce407d1be672f9dcc8fcc7c512e830f44aab461e481e1a08a4790aa74ffd44d0c557d8aac3639444ee7ec65e89e990442aa8ee890db44b67f0894f3de1b7edf94b8fdb19308d97ffca92d1a18fda2d8ac59faf0049ac5f643b15a882163e1620e4d0826d495ca7cdecf9ce37b6a7509771ae0d5d5e655a23dcf02cad1dd046734d822f77f3f791ed46e1af1b442f6bc2796d4a1cb69e36f267408772831f123f968d789b836b6c8cf49e2f1957f674b9d8a9f74615f01209e2d3182a44200d356381b1a70caac40551e0e4b035fd948bc37eeec98853d15cadbcc48749c1258b2988594ccbeb5bccdacbaf7f52a68a8dbbc2ac80594f3eabfdd44496c35efcee04d11a28fca8a29b2fd98306caf6cea4ed6c1b96a858a1f08846298e82e3a0f3ed61782940d7e238520aa324db6538ca0930cddc1a47105a20054fed4d772ed7efdbb089c527cb2b18ab1a54ede937a1b2c5d98126cdd0fc58fb29e471495b29166e75f37da7ac5edf5f7c8fd5fad70554fdd0d274783b424dd8a615a3121fb59f616ab3d47a4330eb1b7d51501985417114d01ed3a502194bcc6a17e78545ff9801d34e06944aff5e745845ea611fe3e2f764149903e5908efd95ce3001c85c79bf037b322 +# +# Params = SHAKE128_W16_H16 +# Msg = a2a50241278f92c8ad617c84331ea21c60e92afcf0e48a714ebb75d0120a9d8dd0556840e3acca6c9a86451a0d5be95c2a25ba8331e8ad9d842a1440e90509ffca5ae64ce06a8f5b65dd852b69e8b88735022f520da3e29d99dbab904646d8bf58d3344048f279aeb1669f3277f0ebbbfac2267c2b9ac8b989695974adcb35eff3aedb675eb76339cca31d6a975a2bcb9b37d4e9d89631543df3c970b141c039059a8a7e648c814403cb7c3ab0051c051d1973c8738e6b6539f676b8af827bb3f33ff12bf0b063bded6591818100f70cd396ae573280acfa713675d233c6fd0d2289b7d2f1de03363414bff3f6f4042275b7baf15e3996f75a61b22a583666e0341143560554ba15d889cfd9a589c0b7dd7865a3ae70e40dfa0e0fe35887d2951740728f874caad076fd0b0e8ca4e98b3a02aeffac91a906e3282bf7c5956c96d242aa1135f897a4059c5c85aefedebd17955b8189df68dbc7997ac06c9af18f993fe44e438cdcf2543018028ac893a362c1dd47e155dac60f90050c03031aa8eebb8479c4007fea897e272b049b451183cd9eba34a451c0e1ae3432185ac0b4 +# PrivateKey = 08000008bd46156c87f750bd6653f3418faa7750abf03e5d42bf2b46c69dccb14ad624e948b55ff93824a6d3acbea9fd9468a23a511ce23757c59250378065d48aeab8de00000000000007ac30b42f1877c5d5fd3013781734205c59969113e7941d8bc9df57c7928d9b5c5eb56ea9e196d429352311a9a028b32e8b246ca306046bea3b58cc659d5a28a390 +# Signature = 00000000000007acedcaabc7db1b849f611ac87a82af5dbe9fefc4484d617022500037757def1ecddf8254cc4a7ffea0b11ce61ec565ee20790c68ae51b9f69d354de444c6475b4807dcfdb624429e989fcc155a04e930cd830d362cbbb315318888e64eaeb1fa4131c6c547bc3753f2a4a86e6d93c06c34a9fa9d97840cd22cb35924cdda10694a248943dd2efab232c37528a4bba726045c48023fb3b26ba0fc2a9560e545aefa1eb3dcfe7c55f0ee472e5d836dbddb6477c6032aceb039bf0a5fd50cfd75607acdadc8c8429f29e6663ea5af6bce0bca581f72db30fcfee1c17a405b4ad1598ef60c84a0bef6f98891e139fa1933bf42cca456d9e2765a1fdb21ea8b9ee9b0d6315e5bfc54a93bd12ce9ea8202637405754363ed8381102e39913cedd34c84e46ec3ff218fbda7709b5c560cd9f8127c9c9282a6dc1802158b921ba8958b4bf057d119ff4eaa35ec917eff9c57587aba7bcdf93aa2783e58a78809c3c2cd0636d7a5ecd318b10a52203578eb5f6b4c65a9260aa861286344501a3fcfe266b9d65d17aa9ee0c429da47294ceaeb1f3500e69435adf7a421a5f830892034ab4635c9e7133022ef71af7122565a79cc21182adfed9417cf699eea4ad2cbc64969bf28bac9cf098789fec560a0043d5449ecf366da8aa8023aa81ea798ef1c61d0058e51af5f22a4daac8e6bfe7af65f220e1007376d5914b2e94f597dfb1c6cdf4b82e2339dbc83eb5e33158d734058142abb9f1fec3d0945ecdc5b3e37734b2bc01ee9e7d8e61f83764df44779b62adf636c2878cca7739bbf1495cc7de96a823ea5646aa76f954e33f2fb6869802b244e1fa4880c6c25d58bfd261ece6d982e2e5805f0f531e1bdf07b4aa5c0ccc4da85789db7a6abc3d828d0d87b67e5e26e8ef9f97fd3948ac0fbaae4b6760fc6877feb0014af9c66788318c7d2b00a13b1658913634a9c6a4feed7546f625bd54798fe8c6199e231044a0ce4ec4a56a0884fcd13b1ccf8d96f81dc1822bfe719bb99ee36884081612ad25e36f4439294d1b7c6a9daffebe87445568d15a98e1b13f1eb19113c6972ca16481d5f519a6338d6d8b24d7b497899fd2889c1b0986d3a47aee1d1e7095be77bc025d00353c13db90bde19214233334a677d093b88aa71da18e5c9d7fd80d9e588fa33c655e25c5793a4435b26b347a2d72f9dbc12e1183d018fa1e352c2190c0345774bb611dd38392e532cf1f56ff3bd6f6db6586ed52e3423470ee5066b0dc434ebf3924950bab1d955ee0a6573c6e644217df0ea031130a5daeed14a8e00e0ee35f8deb4ebb6619964b6fe93974c051dab38c29ec03fcbb8f863d53d7fdb36503230255082490acbef665e2a9e1c8e9a6e3724b38c237e39a4d618da97f53f102442ff8e566d979b3e44b2e903cd616ac69110d33759bbaef5d692a85964f13135e0016d155e5d6534653bbbef33710a01a4673ff0463fa643ebae71fd13195383abd01d9265fa5b63198715c042fa41913a3359ff63ad3fe4944e332f93bcc9d43b505076777aec57468b05e88634513f9991fd33e8b35c50e4aeba93a6946ac3379b0d29d1c54b909d329f39263f07bedb6390ab2769ef12f2455b70da0fb63b52aae8b76e15f8e6302cac3aa5fe051edc967f9c0a01a78398064ca923ff752f085f992a9255081db655f6ba97c0283b615a5db8b17c63273f346f728643d923037b4a0a82caf210acca8443ebda48d494ed9be5a678c466def1719f9da28c744dac8f4c35cf93997edaa4f38608f1f919a50942a56503d8cd8ea51b62febd08b0001518483a6f7ae2ad3cd75224cd7400e8e551c6f78a1e5229a86878e296b40476b49d79c7cb8eb6e0c63a08da4a2999e72c13c52c9df5c0185fcdd12ed8bd095d9c534f0b5b91816748647c0ed7106770d0b759c8921d9a21f12eab26f4dfa33e94878c94848f0d911f420d48a3b4255b1412ba3c9d8c95e542c7e9075c8f8fbc62ad9ca94936ba8f539a34e205dc9802730593ab0b9b48172e3b58c6aa36e92bfc04cf7c3e450fd4c3db22a23d461c4f582d5ee924ba529c60c412cbf4917f9b8465f5af6e6677f972194c7af2db5c03636567e329206dbf8f90cfe9316a5e261b5c73e8d4124d94d5775f323026d6d109dffee9a19908ce3bf07041f204e492ea0b1f09a1470e3cfe087a0de85ff81392487fa7d69f3acb85a2311f129ca80755450311c6abded684faa0144dbe7b12d8e54c56d12234153c5f89d9945899bb5d7a95a7da13f267952199663c6e325d322a141e498b125115dd6033b349ef17cc35be05b24a9789d133adfd7cf21b5ef8bc2bfc3c7035112baf5a97d3dfb05285fe33c2f5784759fdf44b9dce74100e5fff767104d26733134f375ec35660996164249e3fa1960bd6d7801a3af3cff89b50f881d5c8755d8983d423d96531feaf0174fc115d5987ea3571c230a3dfef5b09912b84add3e546591936aca6b2f24ba152cc8f1d77be7f2b65be491bfe4b90c6420e6a14a36bc36a79334d5422888eb49e4e5af10c29bdb19f2ed145ab4504707e710206e0c5b5a4c7e54a844e9c7cd512870f99435625e1878143b2d0af2498a092f2aa029692650b9d74be64ed969e86ac226efd16535479f763c9fc4bc702ccfb5cec9b4b3ca6128c2d2fd39e651e832c1e6fe8d78021889bbe69ba39ea569ae91c2ee07632a9dd214f84f638a464457a087f895ac1b4c3054f0de5d0ce0dfe0597bfa924d8ba27e971bf6ca25ddfea203015256972f2ea2dc79c0381f5333d9f5cb486082473fb0d1b8824dfe9668ea4805a9f53f2af99cb910ac9942aae971c17f9d15980c2a06629f81e1a39520460c556b8dac34b18a5cfd17d6507615b5e9b18f295767de7ecdfc529b71aad17ee8793cba4859ecfb0681c039ed2bb2ca599e5df104a076d185825474519d34296fd79e233dc59670e3f41a7bdc5af123fea56c7b572290802ba085d0e0dd10e80d8aad4931999fc013d51ed50f19100fc28752a9b99460f47d7447d011425f7a5763ad6ccdde937f022bb3c3e9576063eff60f4364bf2e21276e7bdd36a5830d68e143881ca1cf884df46ee88e26b89c8b052cacf8cd339068d28b3e8b26d9fe39cb6b78106af82b78c26386a50b13ad159404abbdc8d98981396c479bf2014d70170ebdd1e37a1eeea962e6ad2a1882affefe1f54bb8d7637a497e1404fcd84fd6c353efd5e5cc8cd9f79b33cf0b136513efa7b2fc5fd01d63c0af3a86b1b7d0dbea1d017deebe557ef2c5373d70a90ee8197d915f2c0378d8512eae6176778c64f13dc4e12b52689ce519188a157e09a350f0a6a5e3d2904cddd2a10add17a681af662695ec23ca391ff2fdf25a7f3fca3863cad7c2afe2f01cff3250174df53403cc0e5b06d44829ef9afa79d09c11a3c87a851e3ee761dfc15e4836d3f1c915e5cec398e99cc7342070fefc789fc72cdee1262e7b1461be786ea758c5b7f13bd70b4373987fa69dbd762461efd150e8050921eedc19ebad58ad53b39dd92e12958b4c3f02f546e893eb9078945f76cc1a41c2b34f6e74e6d730642389068054f9bcb824dc4da3e611d71acc2e9c26cd4997e9af8f06f1dfeaa61677a262851c7eadfa879475b2b467bd31e0a506829dbe13d587f19376f33d99e5ed33c74797cc38a68a6f4b509e6441f289d39b9b3ecb5391d12c1758e517ddd4887d31c9040e3c2de7db559167543402e1da899ed7a0bd33709386dc52b0ba17da4219bb8df3a263fa677dd3dc1fe16e5739a3ebd9367d4b749cfd9ba493d1c07a1b0c +# +# Params = SHAKE128_W16_H20 +# Msg = +# PrivateKey = 0900000984369827bc857d2d241a605141f471b43a6596f233ee9ffb9286fa1416510ce72e9b8d4a54814dcc087c691c5dacb7df69e1581f43187bbb6e989d7a045d4a1f000000000006ba5337c3ce10e9bffa3904848df0d84765b58d7b2dd3dbffcc1acd7747f620f82d69a72f5b43403fe90a88a59b741d2859c7fedc9d29e0b5f170ebe309a2b6f8cdfd +# Signature = 000000000006ba5375ba9d68c616c5aa343c64081bbf551e022637ef3aead85d541fa014abb5275e367ddb5f5b14e194807f6d7c859aceac132e2828dc5cad4aec111032a092fc677712e7d12f149e050ce1191ac676b172962560828f43def782d06ffb31495b0624629066f5ef073c19e7701f9179e01357c04e67b0a5d9f2854d8c9ee96a7e2aebf09d6797cedec5ec5602bcebec9af5306d4ea40f2c4c9f600ca9022ddcce4afa978e7665838a97e24a64ceec4ea2013bf502f8f42188242d7f2627c042e25ca9557150ca84a201fc566b8de2dd9c838bb87129882766a68eb866a4a667d0627ed39220b8a48aaa1166cd762ed21b3a78712b62346fb4e510cfbc695a2ebe7e423b89f41a031e7f9977f0616f045f223e7b12e058d1f2ad6478f31428fff0f561caf6f84cd772278954826cc96907c30b7b1ddac7f6e74ac7a486506a18268e28935027323ca940c87e0122ce6c44ae0de5a92a6fe5ef4832177cccb1bb48e1743aa145efedb2bc7c8ed503238dc1736cf37c6d9f85d5edccadc4c0788458a2b0e5d4857bedf7607b4fb02954111148de51bf01b53a1a5f95e76f429264845ebbb40a985d6a207161f01f3fc2638f2593fed62ef1fb1b65efd9ba7f07fa0079d5e925b34bc2a2f032ad948d8fccd3c9fbd932b53efb73b66093588604353bfddc5b2a59ec751dbdd5717ce46bf793345108d86ae5eb77226ff4a0975e91f1ad963f499bc2b802e64826f6790799d8dcfced6e5c0065f88feb68ee0f63acd4affb18a745c11525729d20709212a95ffb32854c88227d46b3b939260e4b3a212f37aec404b21da462d4ed7f1800915c9bd072c33389ac0eb0014bc7c90244778be59df0d89fe019c152e43e288b72f2347c883edb4bcc22ee54df47d1815b22a62b13bc1a7171b059a0415b4e1c182c92637ea91746d492647f551d3c659ad05e0ea1bd6273426dbfb62e3ff7e976a240c5900c88fae8d67fba758117ba36c686a8dffac29607546ac96605260ee623a0a08f1ec627b4f6f7735020e0333b2bc0b44fc6c9a24be2a97e33e6ac5f4dd76c0c52bd5abafd38cb53df8a46d2df74d6949accafec6a53517c0337451c2c3ac277d46bd1a5573f63dd8a4447362a250915733ce000906a914a84ff33a588d802528d71af415ff77d1bea2b18628953c73816cc567cfe86d3f48614236d42d3ae35e70f30a06cac45db38fa8629b938699836cad261372f786136c4062f22ebab43a18c80b9f4be981c3b1eaf16a9edb9dec6e37fb8a6b522a5186524d51dfcc9182100677f60f5f5361713f69786488f95543160bba2f1ce738c1882b046f4c8b7129150e65e420f34c69930aa7744e95136d13789c81ca3a73380509db5681e3ff94edf443ec2eb08dd1595f47dcbb5e7ae55e1654d53105c10ea0c9f1ea61c53b93dbf51485fda0306d559befebde6a9c82f9655bd2bcebe530bcaa42b5a34d8da4f7aa1171a5556e55937e88d92329590ae3adff8b3e8ab3efbed133b705573166b37f2c664c435970222a409ab3fe3616ccd0006e0080055c74991deb8e13c6360ffc251774e13890a8ea379bac2d4eb82f3682bec0cb7886c13110e16532f27442695de91a302007751193f338e1670bd70dcfc3aea65a4ca20733804e1e587c817a570b142d051fd26bcb01675ffcdbefd58431da32c6bf54602db0f167e3f469a323391f4bd8809f432a0267a570ceb9c3497b7bf8f85018e942431a6dc2fff21c071bbd79e6d4eadf97163e6e7d521ff2e220684e88f2cc557b22dca25f34d838034c0149d0089ec1518534a99548f920fc630e4e50a6e337ba4fda22289009e9cdad7d2c10e96817531ae1a4cc3c1e0897713fdf7f4dfee02a7e76ffbeebbf9bc5bba568dec88e56d1a5bc85aefddc10b39766d9d68a8e200e6fabe49a37d64a40750dbf3c0306956c1df039ccc41a1da4f216b800b5cea2cb9d55aee4f9b0ff25eadebf2d58100f92f09f48cf8b513d40ed42bad7ac289f5d8f2ff1dada5befc416e6f9d9f47650c05feb70fc437093ca828853b2fc24fe1948f823fd0f1afbea376b68608a4635fa7edb7f3f85b46631fa626ae4ad4cd9c844e6448693ac672d9e0a4caf3c0ec9cb993a4f0e5f682d177116c02cdcb237639034f32fa9fd5859c9c6b4c60dbb92dffb6379f2717b57ab90a635083354b6f4467057ee067f89aa3e1ca0681cbfc330e95c0137f40c2697902ffda2630dfb344e5113bd906c13207dd54fb55c453416d61132c13cfb835bacd47352a2dcce334ecf2b1e0d2934b7370ca0d015f5a74e0a11e1004637e6bdad9cfc975456217b2815868e6f93a13a431f0c644686e3bb8b7952344c644666c16c7695eca2ca322809f494aabe68e4e0b6a2668c01e016d25740fb40de51fdbd4b640c4b56125a193de75efdbaf661ab72a37868d0586565bdf84db66be56df3544ba1775d2776acd41abd560008c56aac75dffddeffa96d9a3f00e7ad74f1ffec518ddd0f369ed603103e50f570b1e5dd1764d6bd4562c102da047004d55b1fab5fb2d9c74cab4546ccb11c68d42a6058fddc304b576d6766f03e809986a8158d75c738704f6530fdb3eb06a8b87b031cef7285152f5d13d1ed57d8a68598cd1d9bdf5fd7ce0b1225d22774feefbc6971f8d904eb04347c74e21b522fd14cc72f73b3a5cd69f1fcb12c29151f8e405fe8afca33b9b4e2601e6e2f81b1167c5c39896e1d23a670ad3aae6dd2236b9a5e8b74ccbbf47f832c3f8562ae75fa8b840611ba4855361764eb59204a58b338459899acbf14e6714d39b740988cf20431a9fdb9a3643d85c312523bfa1c59af77c71e0ce25733c8ba9ce2820633704a87cffa3dc5cbdfdc931fad83d85a7c126baad7923f0fa2167b3353894b80d8d5506ab1fbd8d15d05c866b071cc58c9fe21264da34c7afc12998e2813d5899d94cabcf916dd7e9888dddc6f2f53e822da12aeb3e912a5e631c56de369a640c8c85f749e6b2d41611d97006e628149c577997f0c4a4416cd59919e39b6a1797cd0472ba4115bf4aa5756e065f3be8fb63b2db86eaeca69db506f55c0a723f40707db73ff1abd96ee9225ee44e2be777d9510159307c6da22f4f200b0ef434f1e4e1940caf530544c8c8a35e49a18866e5145016bdc914c3bd009a8d91df34bd0d6a0ef1989ee50998d53b825302632d7ae7b27e0cb21a62e9de5354522654d1637c42b7842884ec8afe871f9754535279f283160b4b479571ddd3b8a63d56aa00dcb570d99c06eeb3f2b522243bed768ec41770808d3bba0429f8e1d50d406bd50d885d67dc777ea702da338f075c64003d8f4a3852d2b820dfb00b11b20c7b8035b0f1f95e2368e4c42dfb81c86618470d44bbf36c2d48be95e09afa4f2efa33769efe3493b86e80cdea375b9ab723b818c8cce3701426a8062a6a3c3fc9cecad32eef692f7b82ede0d9e0c9b4dd4e6d72fb88a3091611118cbcd25d6d25c2acc4c173858943667996f07b80058a93016b57c56165e73f3424e9c77a157b80264ab6ff23101cc4f16db16c0616203a1c8cbfae8902638d6a48d3f62817e7daa7ca8a6241c7b9b52f737b5b0da577db46ae89ae4441d210fcd8536ffb2cce255dfb588d91afd39baafdd9a4d59f71013ffb381b46e16b6a61925c40638618698612ffcca9dc1f489e0f45797dfe359fa0d3b7e1160c29ad82a9a575e67cc5f1622c9b2a1f542f74a82c29b35a55aa0db16858a043db5cf1b11d456a73186a1cdbfaba8f24943caf62fc60388335e0add28703c9aa13c5274f91c0253f021abb7a47906c5ffba6a16bb6c9997b25fe62ddbd3b841a9a951a01064a16e22fc7408c416af2af09d61d7b539987df00dcdde975017e8f34b79a73ab110be693d65d39fb0779f4f89180c5af124eec27476e2b3109f24e02bb29bf7f7603e6a6e2b77e71b0df8aeeb5d03fd38f2fb1298926145e05f0349f7adb74a7079d +# +# Params = SHAKE128_W16_H20 +# Msg = a2a50241278f92c8ad617c84331ea21c60e92afcf0e48a714ebb75d0120a9d8dd0556840e3acca6c9a86451a0d5be95c2a25ba8331e8ad9d842a1440e90509ffca5ae64ce06a8f5b65dd852b69e8b88735022f520da3e29d99dbab904646d8bf58d3344048f279aeb1669f3277f0ebbbfac2267c2b9ac8b989695974adcb35eff3aedb675eb76339cca31d6a975a2bcb9b37d4e9d89631543df3c970b141c039059a8a7e648c814403cb7c3ab0051c051d1973c8738e6b6539f676b8af827bb3f33ff12bf0b063bded6591818100f70cd396ae573280acfa713675d233c6fd0d2289b7d2f1de03363414bff3f6f4042275b7baf15e3996f75a61b22a583666e0341143560554ba15d889cfd9a589c0b7dd7865a3ae70e40dfa0e0fe35887d2951740728f874caad076fd0b0e8ca4e98b3a02aeffac91a906e3282bf7c5956c96d242aa1135f897a4059c5c85aefedebd17955b8189df68dbc7997ac06c9af18f993fe44e438cdcf2543018028ac893a362c1dd47e155dac60f90050c03031aa8eebb8479c4007fea897e272b049b451183cd9eba34a451c0e1ae3432185ac0b4 +# PrivateKey = 090000098c1d3a0175b8abb791ce2d00a1e34377541671916210170e65f5aafdddceb8b6d2d86a379a2ea2de18d968eec40332ac33bf9ee1f64c7ddd25bf9c985802ef1f0000000000064ecbd2c23d15ecce8a733b5a269d5b1a12fdc31f7c3d8ca01e4eb0188e589e908a0b4278a5119c2ae7929d25cd02d70fe97e64ef0d702a5fa142856a78cb8a6ba409 +# Signature = 0000000000064ecb4a168719aa6ed21e23b863054df17a2444b0fb93cc328b8d485ff2fed17e6cbcc8896968eb04ac2f82b2e090ba5df482a628944b4b3d85a4edb5aed933e55236727ca018469c0da34a8ea6de1fb1ef76d6dc3484ede9fe19c8e50ddbeefc993b604f73610934e89917654ad7bf779ba0e92aed4130e83cf803be29c9dba868189d400aee18abbf8106d548837e87413559fa5296229b7aeeac251ffcbd01d301936599d07292d6e25e35233556d9850689819cb4e80dda51f6cb05071f5ba6911ce03cb862a6c4258cc7b3254c9194e56a63d7a348909438c5157b64532c65e8620fb0f8fbd2279bc6b2bc6b203a29fc0f7c94d692e48e069dd6148eef2a260ee0ea42c6308faf8da46e7c76e086c26e87ed45d2860e0220215dc8d8a7ba20ccb6033b5d61694f0a28a0a28eb20bac4d8f235515c4f62536ec5e69aa61458bb6aa8faf374e489262abbba5c44956f424d41aff17cb3b5b39956d469cffb539551c011559e9b81b99c0d58be920df45fa16df6ef4ffa389528e39bb16089b12e2d204cc5ab3ed255596b99fbc34b2085d5c7de70ae2fbc727f3c0520d5a57eb625f23ffe55c47f76aaeafabcce8a3387b47cb1ff0b0959e61fd0e61b05d640251f5e420aa4f99e174e7d79c8114eada63d32a25b8a2aa5103df07b7006a129cf65af72284b2877d7e9dde4d62dd75e897b4097f8070ce9152b7440674385279e8d8e184f684852e47dbc5124e528500fcd340bb45bb81b777aca826efead9b41d4650f980def5af410cef9247afef894cf824e1276b3d96d2ccf4366e4ecc6eb20a30cfef7a4cbe203974b79f81401d181fc31aee7dffded2626e207351e85ba537ba7172103e4f53532d0462ad1948674e7182e46e106f28ee3140522f3d9aa5591f868de3416ddd5974f23aaa02cdc69fd85400fe7771f7b00657265d759f78a66b64fc060de28aa5553377013ab610cc90e3a2ce07c4ed44fcf36f321e1cce41d4ec411f0287cef31eed3f075d4bc0f7d95e1fb5a6ad3178ed206f929c1005a584b215761e19e991d65fb1cd98863422bbadd9ffa283774c4781829b97e2acdb81913fcb27a6e0eaedf64903b9aa8dcb5c6f1ce594502dfb01bee3f4175e4faef17535139067f8fa973e84e35a792b22a83e6defaa6199d02e912a391630a6458354e84b17db2039bbb04cccc9949c7a2985224a5480c33addaf128397d13f7dbdae820c54f167038c26566d1f27286d21aa0b1406357a155c420eccc7baf959ebe0a46300260ec48bf3c027517bd80ff4a04c9532249faaed2a97a9bd0a647fbc80d73aeaaf835c1f445bf6d1dfef01a493f61a261092e84d6106b33cd400fb1ca21ce5955971a6779afcd1089a9a98de6a9669cfe4d5fda6704ca8994c3357e73b3691c7e80c7047aed0724245566b8dfd3bff2f5f4f195c29ec9441dff0749f7b0eb6cb8fa5e76a3b0299d888e8b61e4df587c7ad40ef3c7242f5c0424104971cbf559ee39bc1f6b85ea37bd61a1a8f11ed25fde3a7252148750038ef37b2c180453b5adfdc740fcac9c28fe084fa2f147ba8e440ffd7be0c011b43b506ce0fa11f52204f0e94aaf2d71a4ac5ed206ad1b7d45f67054032d2cf591a5bacf8345835b1aed1c638ed4bd91900e2a76227f1660bc812c14d484ff1bff464e0289f77b1cb1e01e0df5ede77a384858b0392672afc506754d8615c72853cc00fcb4c51cc8a4f0f164e0a07a8f1b1c0a669109ff5b336600b21f86eb3ae94a9cefd979feba585615d3f03f812d1ac58d935537ee09b0982efe2fd26c143d1fab276532ed554c37f3d3a6dc26df2aad6940e03a3a09f12ff81f26169a47eea01dabeca256bf7f790e036c93e3a17d366d818eedac31ab0dc39cead22826c56cd9ccb2e7f462021ad365f73d9f34e964e9efbb3a5df0cb29a24f9f1e81e481ad4fb4a3bca42994622b091701e3b85f9db09727cc07b79bea8b12b780da272102dd32078d94eaf4fe6118b34a6ece4037ec2fb6bd994112b48f0539d7922454635db08124c87c9d4652b716aa450098615c61195d3e44d6fbdbab639135ddb35ca514fd989182dca30423ee062b00dc0b8577a6a1851c0c4c9a7148a4bfb5c16e452dc58b03937526741ec8147f9a3d22243929730b857173207ac5f30ccc0e5d64aff0668f76af2463b1640da43f274fc0ca4fb156fff7a1527bf4717f7995bcd1b89887490b90e5b2cc9c00390d10f5bf5be24429df718332d5a0a74991ee3024d628ab11cf3c13b7f69d758c0dc42ecea7479984efbbe374ad31170515987972030fe57466ea7cdadf8168c337777fd41951cc2fcec58d5b09355220e8c74e7ca478e064231e30f888d6b7a4d759fc77875390b0115e613c971133f9850d08c7493e7401b41c996a0a2af98163a8415ea25db89387c1ec958f882bbcd47a5d49d76014fe36290e08705258426af9bbe0b7e11c1756722cb6ed04b487ef9dab1560d6fc232a1de68b14472562662fc11ab0b028933dc801e451791f8d9bfc7437327c330c50f077156e5c3d2e9655c71a59c2fc92d6e5021cc878d19a4bc5bcc18e619204434e4479a6d7ee2494f6d4087f1182f1a171ea0f5a334c5bb983eace14a2b11f9af65d9328e1aab2a7ebafed79fc2b5f3136d99b238ef21338335e4b544878def8c04502a678ece290da8710ae4376a8608e296795a6fe9a0d1afb720677c0384432adfa1e83f0c863224f34b69b23e5f704b08ae11b9e0c7f2059708d8acacdfac0ecfe97751b2ab94781b0ef5ae36d2e6908a7eb002760c2b075a7061075eed0dbd6d4f8fa5b19665a9113007bff68307e7ae1a85aab1df3a71555bdadacad5693bec505e86a47c64a34d1b54c304cdc9e6a64500609e49043eaf58839ec9826368779731ce006c2ca6b0b66497d8deb5e3a77efcf6ed0af52faf749dd23b0582b476cbad1d40671bfe39d08d355c0b8ff25fe139d686f37f23535b9ecc905129995cca4bc6aed83f55f5e8e92f7fa91988a42f972cd37578e3edf082a077335426af35306dbaea1e0aebfa9b4ed888d98f002c89cacab836891c15279b488a3626980dbf8e1acb8e0c6c04e28c3db71ab0e6262b88cad4a2a149b8589ccb6084c32271044a051c72b8c803697cd6409b2182ca8d17b2d26967d5140c2164f621591774587940f2ed675ca26cbbf34771e30b55f59964dfe1a59d15775e9f97630b48ba75abe5f912ca156ed91bfe3502f2fbfd1b8223e17d6685b463df8dab6d0714246ceb377368855ba9a27db147274f5349287280c390454fd560350d60965e7dabeb4cd684969bb0d44cc82ccb27d5baeacfea85effd48ae2bc956642192f42cdf942a5a00704276650b80d3ffea8445fed12c54ee9073fd660617e394dc7b6538b755fc8ec0b6f35f7b550809dd850234e761525d42b44252e7f7316f9ffd9f582bf96cc63bf8b37bb82511ed143e949643a3d57619b6683bd723de96988e81d4750f3c3da92ce482a389682b7802b70fc9df5d5fc3ffc7428b86920905954489f82c9f40ce6d38a9f9535e4c9ad2f2ad4fae6521ac8a0c00ef99fbe983d7fd0c31b6db71f295a792019fe8066e838d5dc9f33fb927720c1274d645a0e0421e1b50d7526ace23b8f4d615008cc1b47a455a58f0538041b49fcfd81d083ba066d692d1840cc521ec8ef4d10e145e0ed9afb68fe33bb05333443a42f81d99e5ddbfbc407bfed25d8f3479aa56d0ef2e68bb5b717d7d8d21241aea7ada2c58e9ad29b7cc972b1c13ed5d8104e633778d1f70ff5e0a57e9f2aec868a4c7a9335bf1ccb270922583a83488e6c572dd9bccc2e823a1455c3437542f65ef1843eb496027d36531c390f2bed41d17c2539987b1e7b2c2c083da39f8caf4acf08303b675474d7fe1ccaccc0acaf1700f9b5220c22109744e0b40346faf3c6e47a387a3aa8286879c75aa8de0b7e2c837fc42b45717287b8b0f0e534fb0 +# +Params = SHAKE256_W16_H10 +Msg = +PrivateKey = 0a00000ac46251f7c4313bfb2cab206d829a6133354301daec1dace6b406f425ccf84e31b9458fa28837bfdae56dc5771e77dea529725265a069bf4dc716510d53c5edb6596cc09b51251091e0220b8c4ea6848c3a03967bc9336d3b72ccd6aa95d2dd9e3bc28ec2796be9630fd741ff7ce72155c056a939bd553508cb3bf661116714b100000000000001834637167425144c8a451fd9a30427d44cdd31aa290b41992e00c7565f50a611f8e645c9ce03482b1ea82cbdfbc48857909cfefa5359beec06cb9a9e53d73365299e82a042fd74c701adea9cb64901616a2da1134b89d13fd0f77d4adb5f3bcd4945c1b15eb30246874563a8541a92f78d712323e74185a710e563e317f657859f +Signature = 00000000000001835bb9b16b0826f598c13c13552399648d495f4740fcc691c944d1c8f7bffb50992187da5fd487115700c52afd050fcbc5e6071c3f75ebf4dbc73c8873ef0f59957028f637c6a5448c04d1b0f021456395b37c7b0fa8aaa9709f3c5a8acbf3bc9f2e173a89f8107e03377f6cace66651b57baefcdfe80a3a92047813e9f3b7ff50964aeb1be8b9a003893fce8a4debeb570c7a7a6a5a0cf4504f81d7eb1509296a216812f2cb89729dedfaa35ac441d504661304a6ba0545ffb220229634efb076c455dfac2a28ca0a04944d9368c1c641948e1798b9ed9f3c0a109c6088e0705888a632021837e1ebd67c0c64b6773baf95bddc9454226e7515c0015cc70105336c137ba26758f107c43fff43965e87c0a87407388a7aa477e2d8afcce1a9840681e88e1d4f6f11e920b728fd609a2612be19bf7f59b7f827e95507afd8d88fdaa3de3761ac7ebb53c8557ec06c7158b2e0003303382466968151c91a41e850baa50f1a10813992d0675ea62d43f767a0d844d9bb6f74bca3c8cda7841017319ee90ea2a38108eb71e019d0f62e7799221e801e361a3c85f4a67a6120a2c381b80f7df2583d9253150c68ce8a4f753c49c548c62c819bea0f1b85071188d834ffc087863a35e9db35f7e0cd741bab6093872021b1d71c09c7b98c08e573f40346976a749896037c78434b480c45d83b134b859ef3af5ab04e6243ab130304834099b4e4f35882c070f9835aafd726cdbd61ac419944702b840771bba74da81faf087dbc2a99e14331a875cf2a96e373ed4e6ae725d6ed4bc6757b940472091470ef95025a1c6ce1a4ab2bb51bf5eea7e33d76712b1027002b3402cca3920b2ea342fa9009ba02e8004e98b4bb4f8831580a322fecd84eeb39db530911df87ef56d5f0f3a96801d49399311ca4bc980c19ea6488e920392113e7eacc74340984431831a39d7ff4ddfe503eab6b1faae4a3a17f064c47b111020cec376d1b3d31fadda95532236e0a3a2fb831deb20290caacaa62c48f3c73d8cf9ce5703af1bb59b34bd90f05a6c57229a441b08c744f784542465d109ae61f40184ed55fe5b84a487f61e0d8ec0a6fe0c5963f956a0f806ffd21eb7f30d898ea0cd9f432c3644034b674f7eba8df346a045a93bc7c20da3763c52d62955f44a0666c1fd43ec6bbb526e12a0e80ea5b785462e18ddc1bc75899acfef97fbca423470cfe283a7f49b0d122b94a62bbf01e850b88b5353247356bb99b95b8d790b8011b4c41e9204dd3c0309f4543a7ca7938e5dd85f8101d7749d4df64c5150137172774cf0d9be6961932c7566ba60e1290e4a09cf9c5acb7d32f1439db813e22cf2a6c76a774b4fceb294353d338fca661b7e6bf43fcf3f4571d820d64fe6afb9f233f0db533a69f5ed28888beffed42e22d35147bba8ae4b7bb2d5d0b44116aec5bb803e7e919f66d4e4f066b6971c48a22e52d8cfca66304340157af360d803a102298673a685b85a8681121249ec83ffd0bc288cc605ee97ce848e4fc53eb7cccd70a252b4e52246b82a0cf9d2e6938bb0ea8dc61ce8531bb6b49cd43e22a56d80e6b95a0eeb9b35e0888bfd7f98132be974eed08ad2aa45f1ab0f3a84331dcff8a220a1c97e23976c37c9e19b8e88fd0466c081e66c284ecd4639929e79b30f0ddebd331364bd616af89d54107fcb506ddeb00264e9e083a69800d7c834b7a383cfc72d1eaf44f6b39e648e1159f7d499b07e9254352bfa58cc926cd94be841a2bbba6193bd786b2150bc51a956d58e7e2839d79fc64db16351deafe135118227c497d10cd8c615bf7c306b7c4ca4f7d6a2852f5c6ff419560dd9c22a879ae268ead60d32317307045288dd337e692a57c0b5f15ac5a9934fe0871a87b45f7916233269b2d79164955bb79955dbc84b4d2c6425175df9ce12e4cb4c4660859bc45b485c521c17d2d9e0b95958fa8c6fd30be7715b03436e7d23d6def7cedfd6a26c82b5c6377a37c290c216703844a6b8075918ec07fecbc888aa354bdfb264717bafe113282b88e3ac8cd171957dfbf71743079fab560fbc752b690c7a9505ffc8a5af1d55d310e31c2f8590487c0842f448b3bfea1214b1fa9043ca33d0dd609ca7efb2a391614d02516a72bfc4b1791f6728be2a365bbab2f4c40147d24efda9a70da3e7872d54f99958f944e6704e22c1fc40c21dd4fddc05af73e76c610d10321acf73581091003a1fc8e8fedd36c73be5f5b614f22e848bd996ad329fdc2b1c6541672e9b367d6d7e44d1c9bd6ee70ff0c2640dc9c7c6afd2cc5b5e7570d2802f384793cc3ac7a184762590cc73e671f4e2394f250272f334214ebaa5d7208cb158ce65a43424f5189bdc5fe5b9282863134fa922bc34358aaf0859c28c1f79f974ba521d00a82438bbd6b1e237c9607bf32e889cf6bc707228f31554e05d7c96ab5892665d099b04cee1d68c69a329e20291a9acf2f5c94379ea0adebe998f5a63fd9df3c0efff3c79c2f6b4388de31ff55f0d8cc2b2bd8e2e8ca0cd383c1a40ffb74033fedee1055a94724dc7f7bf128e0a5905dbb0e7ccebc46ed5685e52c5ce279f7dfe54c3bc6062af5fb663422769e5b7e37e2a8bf6df91887794199973a922311a1cec8737a589826d66ee1e18848cf31a211401e17dad96c442acb17baa02193f3353b6b756ded22ab21282a97e83b9cd31e63de3f0742ffd4684e994afcac7bfc79e86fd38cd1e51f8c0295e831fca1ec719d649cd75eeab215fd54d27291614e1da20c14c7de1bb25f9c2cea8426fc7a5ffc0da0d495825f48cb8950fa64547610b8d4f598243672aadcda0db3d6f7e3d93dc9c107ea5b779cb0c7b3c8046313c2df097655ca2dc10e5bee923b26b055dc09370171161f533399ebbd402d0da666c32710f72075457e180328338e23c4836f1f78ceaa3040c4f53dde65eccfc3890b6c08923540417b4962cd26b8b1a8c809b157e1483d385951a1c7ad1a889b3581e368e26cebd9df3a0f2096445cf72b43084c3796a49fc5902191bcae3606e716b2fb7fab8b8fc9ed6f601ed56b56abf7ebc95e2e4d3c1849a55648de5379a57da6c97dbe14a55fb3538c232886899bc90db8302b6bfc59b6008206108d120521adb4e70903f160b5bf1e833a384efb076d4312badafc01ee918a2de237e2f05cc8e48c381d5769cdb444d40f75ada815534626e1945692135cad1937e82fa46c6479ecc4444ce0dfd175ad921dbebb0989e4810777c6980a01616c47151a2623aa059bc59238f42c8956717ac48ca00538e54ca80d7519bcd986610552a6e18d60e4f3820aaff28e08670cf5eb86056f8ca623ce2233f7e65798ff5fd2b9a9e93bba9ee2121030c93850fcef6b7100a926ceae2e74f8af98b766777419d719c917826a8636e9f3181e14c0e4e2c8d2545bc456b867d70b10402a1acf5b02786bb93141f7d0a725146622d6e5bc5f3dfe8ac1bbc1c601394bc536513af5b55109139db2e03b2dd1809b8ae942a784b1a0f000e34b71944e32c24672875e19ce8ea9c35110d3f59f32da1089c12794b021f6c2fc415c23e659594dbc52a35a97edb765fd34747c0fa4d75097ea7b60acb190b2fe39d46448cebd964f2f3ea112cd2fac6a27045e40c1ea69b230922a02d218ee8f208a52360b88c7b5e379343c53f532ed8a6131bf06edc0aca963e74d6841a4054f61f96ddbc446db3cd7cc2454a15adda520a40e9bb6cfd5107a2ecdebd2e7342df3b71180cc2121d2dcb62dd7dfbbd936b6cd2a5eb1c6ab0d06102a3a25ecf22eb5d074f0b6d9d948b79e2c94476b884c82c479bb28305f4024cfa1b99d23a0d34b3afc4f9c9b7d1e142987815c0d5a2857b82ab120d930bf1a32d7e34c0d9c8767dd4250295eb937c8818f20c3eb268581cdb2750907e2cc49236818ac48c19661f9d736b726f4c67b09f6ad0f88faaf6ac21639326aae4816a40b50bf61332a70e38231f4467cda399338329a05897391efc7a4018ea3e2f07629082c7b57419749aa0fe0905bac71b362409ae64780486e2eefc37238f3bcca3138e729a6ea97f3f3434024d6b95701944e53e49cac760d96ce97914ac7865ddc9983057c64583e29d02d915ba0b2481ccee8e7a4b0e03e2a7aeb29d9a1407bd475fef2f3e5aeca77e9eaf4e6b4f37084455cf8713f07cf8b265f542acd262752d4cd77c6579ebd5db53960da23482ae6ce4877dfe859a93b9360e54772bbcd5880cb8fb93c5563e273d61fd65f21000e4706055aa7a9cb20ace3daaf824a716a88dbbda9d3b73291cfa76e216b82168542493c1db0847988400556e06e32d0f079dae82aa5ca60ecdba9837494c832aba58832721231aeeba7083138c3b0230229642dc9441aa14d37acd41561173e5e04bc554d7ec2ce3f491867647ce796db75dffdde27ab8b1d22d32d88cdeba4eda5b20ed205e219391f4de674d279eadbeab4638184e100074d0625fab1bfe0a3edf413371757fb087a33761f2105b9d2c2e663e8a9b10dcca3610cf10e4e1294f625f12ad09c360aa1122062a0095b53ec1823e8a3e1b8f8915878e6ce934cd1be7b0901ed3774ecbe8ddcc458e1fd8e9332f322c1a6a7f3b4f4f4a5b36f6243d93fb10973ff0c602e3ee73a0433a1589ec69302981fc48d80f92ec60c977f4ccf0f97299ed41c58a24220106d6392ba0f0bd775a7b47a14b845bea0cea351c5db170ba114397e2ab7e807e5b19a27a3964fc15d7b8bcf9b33353de74057f816a134756fb74e92a4385eaea3c380fbc69ffc0e749ce1614ce75688117e2178b6f3c41c46db7e6370009695c7ff36bf4864e82b80d18caefc4b97ad3e207afe41fb48b6bc4b75e6afb7fdd891ec6de771c697c29fab10ac6c77493d69bb211a0cd740dd48caf1b28d7c3b376c559025eedb7fc00fa016fb7ebbf58fe14d0fdfc623cb9d3665d5accfb218cdd10c5092c4418e4447da7910083ec5ff160217214bfe23e9554234175231ebdfc8e9da91ce2f257dfc47d237813df8420f6e10514b2cbbf3407e994704a790244fcb0c24664439247e0b5214a9c90bdfcee3cf5bdaaf1869a0d78f840c09ce6c19c1cbd5c3600f1624ac800131a12fb38e7631db039ea82f5890f758f849ee87c4c2cab578598c0ff8abf15aee8ecf69030f3c508a7a4270141c39b7011785fc655b3676f8ed7e6249324950e501c47d216ae902dc6581b3d690c7165fbf67888cd45f9d11e1dd7969ec20bb6c546103057a20a0ce1c55b8be0cbaead099aed2d5a59367733e132c2c3e0d01775d3b192543e930ccc12c67f11dd5cb78820f8e8c80b553dceb043d97ffa6376c2caf0927dee8d1be76071bda1270dbd3efa4f95e3a5715dacd19209ff036b57f1b7bf3e66735d6610d26b19139d7baee616d48d65d8cf035b5d91ac2682a1b04748372c0e1a957f3814698a89f249c202b8afda43551cd4a3e2de0dedd104cb4d2a49ef3301c1991c29da8b13ba86cc176c1fc511870ff80f1e2e88c5ad59aeb6d29673a536e9129a9945838a535bf889bdacdc15a96774906cd4a5837efd2cef39d717da810b3ef33d5f6d3aba2065be99256bffe7b49f10e7a847b9f8b621334211b875aa68ea73f5f0c8a2d36d8a9de2991b0b787295de5217577e38898024e4d12846b4e8de8f4cd73ca8d035bf6fcc40a408819c0f303cec4d37a8616aaf08801fc8d615fcce3ca8e360ea80d9700bdb93b66bb6221c420f3d00bb8f98f34c7e84d6d7f57d1f36c85e8dc1ba5832e191ba9eef7d66e03860e307cd66f0ef044bbc816816f2ce0212bcf064af9a450c74e0b1cc2b0d1631e7d836d1c95678a0151b6150768502d1f0989b578116cf73da520ff7499ec9f92dbbfda21256d109d97c6fa528104297648a129540183a4d9dcb488c69e51eb355f23c41e4d78b9778aba94d3a8e9fd598382039ec81b25830eaddbbeab576fbcc1fce428d6828386fc4f1d1c3dd45d2197776ad7546582837439e8d47fe433a62edd310073fd3c2729bef77bbc951d35f455abfb114aaa248a8f2a06f5e359dd496250bdf85aac3dd6009855eff64c7c247c32a263c23cc90482aebf60644cc4ec0ae5a95ff6e39dffdc8014f3247ff0f821c911373bf03b6ba6f744e49fcf68523ffe360febe7dbb3cd5e7c8ba1be5e3c4ad157ef23dcab2d8ecfa390129e58c2cc1d451a93c232872efcad6ff04ef1de4dc7de774e7eb733dcbe9a82a348d66353c168e932704da6a9ef210fbbb5918a64e775f17f9150d6a70216457f387b81e0e827d723d26e17768c949d09908a2aec5a588b19658db430c1138f618a5a653457ef032d65fa94635441978185f7287c6db837d69512296ac84fcf83637140127180c4c88207db5ee843aa762246c3932565ca4187dbb70de234b8f70ec9d213259410ec555c3d5778239bc8e223b9bf997c6411d20b3b1e9b52c753a48dac7e1db4cf75e3697b765b7665db87c33f8c2ceebefe4f37b3d0dc076f67a6f020b6c953497f46b6ddc0d9cf9221976ffeae5e2bd3c1654bd3123943ea476c5b9bc9f38aebab9886d8dbba2dbea39150fddfb163bce47831e43c18202a6d7e5b4722dd826f1849c845554e6210f2f6edd06a68b89eb922ac0565822e1787665c673f9b85f63f276634255dc9d7ba1f42bafabf146443e594a1d9d676f8996ed86b36cb127ef8d7f1d6de4fd81b5018129eb4bc65e29dcd9ac488d28515f95713b3da40505711bce45018ae76ebaa3737e9bbce7092ccf44191b1c65dc5cf41ad63cccc9d98bd32ac00c7db79ab3b4a5119a76b50dd28f224a60e20f0cecdcbe1e6b273b523a0c56d6f3d879010d31cdeca5b9be64e07ec7768618b5ccfce4e0f79187882f2058cf0e16337345c28fb6cd1bb02a15e660bbcbcff60d150daea562648dd9fb202b2b5ed069fbe47b9deba5770f848e5f98e940252fa95ef558897f4f6408c711945b35a70eafc3caccd2f7fbfd532e8acc0f80ab07e620d46ef78687a36b1bdafd206974ef8cf3f7070f1e50005cb8f6496f087e8058e4b65e0545914d7a4ce79ef9820cc1fdf3dee2e0162419e173ef97dc0cccf4ff69e8c95476744434d372cb7a892532198bb41f82f39f42eba101864b9534fd19b5b101ab69a2f47fc67a5833a5af750e3fad36b9bd9bf5e6f5a32bc7caa1b4bcbcae4433917d7a1978e099315379ceb295f9da99278eb80cc3547a94e68b5e7f47b325ff969d2f76625181a5f7c9787cc4fd2a2b795c99bbbed7bedce7d0bd354c8baa728e2ea2c68a7ff95488226bb514ac10eaecac91347daf93dfb4f6705f78962b908cbe6ea216c345d2b3e3a0d1f0f67f009084bbab4c8755b7fc37899a06d5f503dd2313cc552078da840062a65bafee74e63082b3537101a60abe7bcf8ae1167bc3a71f5d4a701b4bc395a494e221b83ef8125b9eaa8acbfaa08660a32f8c1f08d8c6811d762e29fd64f4266268138a5a361a0a6d26851208d7ba8b996e5f4421d1779a07b96ab463d9cac328d2f8a555e96bcafb9c801c543eb27e289bf07e6fd09bf34c14d69a22b4ee799af2d385ad822a43f20d445ee754a4768c8b9acb22e3937f1346f121beb4092597d1767d24bbe3cc6bd1d91015fe53e7a5251b435f93181e8ad12c932bd82ad91e0357232f8ddcc84c9d703b0d5c9ee9871f90656326c7e2873ad0b27c953b5642fc1688132c7809baf0775ceaa0bfe27ab7f2148f445079e21833ffb3d57d80d7c8be88786799ab9fdca11e8b073f3e3376ff9aa42568655b17f5b2a456e7aac258419070c89ade2ac7dd07e14c579a019fe44a1cb91f4b316914bcb7f4eafd6dffadfe84b679dcffeb630d3bc275a58945c293712ba248559db53e4c4847af3acc1fe4dc2b6fc1bdddb6482458fa78ccbab9096077c2767f8da1d8559624b0154e144e21e22e2680a2425a0b96c0eb2da7198c0ff6e3968c34fe40afe257be18771dbed0ff7acd8044ba2a4f99c69f9d7f2a203c85517a84d90d46a0a4a0d74c7a91cf143be160e4c6e1aba8799392097a3de82634ea95d2c9e4da7473159c689eb05645306d45f4af479401515b1d6fb197028250da0d40bbb350450629369e9d37d347629a25f0afff06cc58d363f38d3dc87c44743bcfb43912d2813dcd1394ca911f9413b60411d9d0df7290b162052680dd75c0734c8aec58a358cb2b1950ff0da463ccdf1d64c1a5e49336a9fe1513d3bd8c2215e27c33b463e3895244c33a15c359e34351fb9d15b02e77d5740e6d424012d8dfdf4eebd472d12e716a186a230787e4bfba306abb19489eb089ddfb5bb06edd2f1069e59330a271bf8a0c225a2dc9c52a2854afd8caafec04beed1c0107d0fe3e315ebcf93aaaa16d1a0ba16a8a54a315d60711c203b84a0ce76ba66f8cf653aa7081c3985845b4baa465d2e6d8863048ae524250587bddda9360f6dcc78ae3cc01f76a0067152a939dd3eeb6d8147252e981c5159c80e5d834bd87aa63ad8cc5eb562045a1746203f1f654aecaa8ca4e5933c51e2ff493f04dbd9185350b9af3a5784d539e06b567985c4d247cca94e833a4eaace57ad8d41820f8c4fa85fcc588a71be10bde65c02af3f2e13a8bfb6ae2b0fb7b2ca16c1b12078d6b7dff7bbe7d465c98674d1b9303237a7832161e551e750bfdf11f2f17938cc3a7458f81061e4f7a13f1c6374cbadf02743101c46dd16b7e2fa0b194d0e8afbfb23a930563b09501b0679e9d615cf7d893304a30f647f2875c1c0271679f0a6d413a935eac173a127adc5527321f338762b18c8ee3530bb2e50f4a369aace58f93122fe0748d1841e1dbfc1f6f99cfddb6267d83126d5375371da6861c98cc94c6b557be6c2904a863ab85abe161aa1945c17395f3a0b4e783eb907cfe56a0bb2bb6532963fbda3216b049d7dafbfbfb31f321b9f22943d3209cc2e86db2a269ef687247fa8dc333c6e335930be4b020ce56d79dda3cc7477ddba6281805522d5ab5e8470fa7ae98a88b6bc4aac86c191fc71c473e6b4aa5d38261d0b847deda346b8a2304a09aa6445acf8f5245ab87234320fdae4d80e9e52658de4f3ce64367c57bcb7d5bd2f3c66396f55474be8efbf491b21e6187c6f7ada54ba7996f70c395ae53d6cb9b099c3c25fa14850a4ef76a4539d873d27ee59e9deddd9a682253993f02fed379dd104a5efbcf9b88c2c6782c671f22d03d1128d8443f451c80d045fc660f70ab10c30396930a914b339795e868c454e57fc38d98a4df19d9a5ddcd14957ccff25aaf2c88dd2967419fcd8da8bd55a41ec03bd3e222a212c7fb7b51e40beedff29f735cb2fe87b6123ae07e5dd9d4652acde00ee0c35f62e32ecb03789eac0deab31c165a912ee3b4a860c9dd93a0f5c3b145eb32a95c91436a5b87a5bfb6e3719094433633449c7628784e023e1e364cf99713505c6933bf5edcf958f0307d6268d265880438f304805be3b3d33c7303643b31ec443be8a19c792da73ac84fc4384619d089b839bde658c241f3fb4e2960ae16c2b1ad97eb1916222f34641ea92ff9a2a4f8260e7ede2c80eaae2a169345f7698bc63e7a2f01b61c0d342f1d451e8db46a16685f47c074dd24b0474c930ff87aa1238d2ce181a441ff9ba0aa170f00bdc4f01c205df48b29c05333261871c0389a717eeb92924104278a7fc92412af19ef7448bfdce9ef110ae23f26b714ffdace10501d4c4c67957947376e8a682992c29dad88a3e1f7c824c70add159c912aafaa12d6e84d11490d2bb1ffd348bdc6948f606bf9a1b5a4b76bd45bb2b5e164991a84c0d2af355d24f82b1507f939f04c1faaabeeb7875220e94b161df90799647dc7b2c4171713891ed332e7632e6a65e8d8bf0aa1baeda2036bd77a1bed91ec072de22646756f2ac854bb5588ecaeb4f6a76520369daaf006e443ef6ff1705e4f46ba5065aff4f8bd59c0bcffaf5d305c3cb1c7cf2b72b25973790f7dbadc8ff82d216a9d919abf1a5f2c9469ccec298f3dd3f9ff389d2a46fbe4a46a0cb633ce627041c943f7d3f417e8c7c615fd87fae88751fbb71e87908431720dec5b183805225db7ce00a3b917da0112a0a0c4383169e9e92464452df04e48e1f837ff63c4b5fabf03cbf77cf8c87d7c01aa689007f4b224a6da77a444437bcb3b1972e2374cb0cf47a2e1719cad192a2624f05f5d624a899acc2aa7688d50f194b894313b8cae9c5012cd200ce8b82d0b0b8f4b895fa53eaac89d6afa393f73233f21f621c509b84f946ee1e2663baeea2f05207c51cd9f983fdc05cd424abe29b9264861760ffe514a192dc42a99f654b74bbcec1a6df2ab79b347d450618f3de60c29950662c679053aa585fc21fe5c401cc9f87bd57f80129dd349e393a6075d0407487f342052b0680184be2eff9f126dfa874d6ff55be5eda0a9972a635dc6fcb4e4c72ace7041a13a45eab3c64bde84313fe2a58647b9cf5e7a64b91a25b51a4888d9a4a6ead20d6c5a1c139dba8e8ebdf47bceb358deac667c1b105f1738190b3605b24f289a4c315ae05eaba1ef07909819ac9b49cab9377dd5545f3e56ed7bd05db0e37fd4ded3e25b7b35a6f8d678f514444cf521450124aa8d0c121ca12787cb2d5c8f7ab4ed26c2ee785d280956872ae7d98adbc04e711a8f28d3e9ba769eab916fc0f27b38a75c841fcd5ce927b24a1d9ce2039d6cc9ec66b3ce8e2d7ac4840698aa82dc152865473e6353dcbddaa1d4b432b7deec3ec50ecf4853adbd4e08a246bc5229605e8643811a9b09f34b5bd4a4a413306cb6f7a4adddb99e6a1816c3573d095ca6da26f7ffb032822a126d68449407ac66abc20dc84321e43d9e015e305bfe4547c0e74b865b2b1acd44574501b475c4e97d22a4cab252f494a09695ed4f710e13b9fcb4355cc3f0f06270f21ffb67a776711e8990340202f81965afee1a6cfed96605dd427559266387bd362ba06edfaa25b9d2b3e8c313b3a172f0ebedb8efa074bed69ef7cc0dc6de3b0aac9049d4cea251e38acc44a683a84a74eafb19c3781e3d3e0fc1413983e897e808534517783aa78fa94bfa84d2eabd1a53d11512e0b307101b5006d7e35f83d13208c47509432ea5ec1bbbca247cf75d24e8b2aa357942aa65f41c557ccc9cc388b6331a5a85f7eb0050f764898c77f7d90aa2a67eb9eb5bb8f4bbf07b8cb9fd3c652aad1e2b1ba5a4362bf3954f0a950c8595e74a5217c8f2a996964f2ace5448c07fe0340bb388e986da83f98472c4db804d201d4002cc3eb4884a683a50f82d69ee991c79c5986cd9df724f2940807eda7aefcfb6bf3c6e928d951144c684b04ba7aefec8b48f42613e05095229e79c0b8555cba27ac494f84d389afed9a697e7fbdf484ab2af2c5122d935efca8aa48c0bcf4658e92dbafbd5ef1d4fa7c52eb8cb7261e1bb33b121d5fe746c9fe450329d3060be735fef6e1f368e69ce3dbb00553515bbeae3cff6f9be0ccc69a4dda7a67bdf9b0053fcf7b6b097c51938555353d8cb6f9551d0e164baef8f1136fcd69296616523b95f2da548d3ef4bbd1f5c0510de08132589f81e997020dc1eabaf99b39558824e21ce040b980b029df808dfde0a6aa4fbb0c3088be9d272f0328e6d98bf531ffd199a420b9e362a4317833f732b706f7f96898c73381e1ae0fee48edf1db0bc873e8ab4933c3130f1e33cc09517cc2cd9816aeb588c72134f470284f736336ee175fc16de0eeff5548b77afee26c946fb8fc125bb3ef0780154c40f2d835b8b51d14e62fa5c9483712afc412c71e2153c605b8a2dc16ba0773a95f062b0dd526e80ed219653e96a8d6f124fb1653e05eed6709d6d189acf7591568d8ab0c4ac004151de63c2841be5a4c65c38be5318752f45327c6371c7e334652c035532ed372d03776c1f2b278967a8b3f235b55484eefb8d11aff1631bc3c8760375357fbb773f3aa0cfa1ee4c7c171a8a787725250925d85ff720efc43052a167b0f6177d7ce7201345217426e567a019fbd157c867a1332129998d38b211802e4a4d700f8d3001e2853eaf4509366f65022282cd64f17c052d42763b36a2411d01d188f4d05c2d63b06f9e6c2ec2acb41cbdde892b84b7b2618957a5c5294dff6b9ed51e952b1514c451cb21d51bd535360df25518e5068cbdf8aaed51b0d3908bc2cf6590831b87b34a0ac0603111b63bf45058e8ff91c14cabeb61778d64b71fbcb714791b56913a3de6d03441c63325ca64ca5538a920032bb1fe792671f922ff6ebee89391354c9d0cf77e9371e889e859b2bde3ce37eebc449376423ff776e358f1f6f1a032aecfac5ee95ff9ef45ac9b693c7ca811bdf2d1310cc3281a0e2088b68d3abbde8fac1876577a5cf0b12b3b2f6cf4ce4af05198c2665ccc7d9af8f69ce4bf793f516468c9521eb34fcf2edb5f41f2fe1c49fbf7c7be7384f75b583b8d3d06c9a3cb25e87e2df5b375b77c650a6feecc3ed96f3c5c446eeb52e2a7b539216bf8c0e284e45668cc2548e5a95ec3f3ca6d2aa3f5507e5589633ebd23345b64b1e3e246415a46b18f89e6857011fd0aa8019f941ae1a5e6be09705a7bd27b8dcf3899d71a2133f07f7de62571e47f98b0cdf287dec098caf492833e039fb4f35990382095cd0c4dd0be29d1fcf9bac3d6a0c8386cbd6e5c1e7cfdc95f3e699540b322344e0f190901e2957cf3b74af49e56a491c70c37f77eab457523d38539ab7abd47176165be5cb3cece13381d29721c5e5985b2bfac88e412a4e688eff3174e5907c139621e02c06952592f0acfe291983942d8300b024d53cadc8bb810e9af7a04470d8dd29a99907cbb7911157fda1c086e39216883cc999562a6a7c4974af3c2f + +Params = SHAKE256_W16_H10 +Msg = a84ac56687bde5e2d8382fd88e343a128dcc899a02ce38126675fe2a3bfd6c2ad8adf8d092ed6f7951e042f8fc60a366e191c44f3fd3d77c8dd23505273cbac651a48ff067f90af5d467c4ac525872c4140e82358591a1daf8a7bf6716a6fea003d128ae6cf80a30bc06f6057702f97133de52648641a4f8dde73ca365bdcfc6c4bc3bdec3258b61f23105ebb52ca189c7ba30fc24f0752c66c00331c28e53aa16219a85c90658c615e20ce175028b6fc01dc0aa1ae9d92f5f8fb4212c6e4e0dea138c2cfa3f79495188eda3c2405e66b410c19617e4b5a2651e086b834182a0821b5794a7c417d7084a876fc7618c96172eeb972a5f323a924b6f0530daa8898f9907fcaad6ed374590d38fbc65de46f26bd8aa70bcb59b0119bfac482a1c10b415 +PrivateKey = 0a00000a1567db3f6ebc94f97e4f0dda7c92d25a84a40c7557037ff2a6595b586a027a7de83f8cce80fa9a9575dcdf6d1afc46db87c5eeb1a683c24b487cbcaa9722cedb4f8099f458545a83b1a80c3e12819df02fd16ca18831f7880776a6a7edb598fbad6340e8b0052175b10b413ac75252497aee63638726f12f4146f1d3d548ccec0000000000000006e72b47219a940cc045736a2f61c1a3aef4462ca66c1757fc15176d85d1a1e696ba325e3cfa6ec2d786763537858d7bb053e63c081d1c1955f7894175ea5dcc36d8e2bc9ad80965f3e1589919d6146da200f5512f22b64b7c2b9da2d42881360a3013aaf1c972a95ac7072e8c576d398f40189a8e982cb8da49775f5c61f579c7 +Signature = 0000000000000006eaac5708f8e22463e168af5a4dc8dfee899dcef58083e912e0a617dd4de5d59e15dd97a692bed54c5f166cda125edb920b4a4c12979d3880a3116cb828dcb431a6b20b16418a645265cb0a9b0e334e437f4fa30b5d5f1cc07f798622d72a7c43cd5df94b7a6ad62f41a4c9cd5665708dcadfdcda0b9225dbd38554c6f1d556c8ac8b2d76c8482eab31500e58af8d7ba6e80dd73c2409668ef72a536a9ea5766251179d016b9c347f15547cc3da260b1f91356932ec4f45fd582833d5fd2f3c96d70fe377c3c6e2eec4ee160736d07e5daf926d213f0b14e5e44359f62cdda1a74ca9087963a5bd407ea14ce35ca58e3d6526ed82b103f161108166e06488db790d80a2b83b7f12bb820d97f3cf48ec4b99fde6349864c147901c904ff8451c4012850433e8bca06397b847233a839b204eb3653be0746cdadee320d3f6f6ee3cc279f18bc797a5b66f8e895b98202afc91cb30e14df59df91ac873f919dfacae6d0c236c88057aa23b491d7077511bbe73cad0bedf2e4d5012da795f55d9cba5a5c26aaf3976f15ce6a2b0fd0bf5f2c8ef61608a952850266ca6de86b376f8ce4c877e96611d95ab7fd170274050496989fcc67704b06433f4c61185a6a30ce49180611b138c966acbc3b8e6c10c845cb835d80821d0c67e46d5b15c0b5774fc0c41474e5cb25ce183666805bfc929622c51cc63f1f53b679b0ccf32fe707681fa7ee64b0435771899a8dabc218ce88a7783e65a7d1587fef20a6a5f2d770f4a5813291a62903e643d66283ad9fbe8b1bcc2f356c0b0023604c093a99e824e9479cb7c5a6a75d66dc9d6ffc90f6412dc01db397d5375bece15f50b1af68e0a99f5cbc6567702c3358ee4e1f321e5bc9a794a7b1a5e9102b36552cf35b35617d90a9aaf70aca108b80011f0feafeeabf499f520f2b8b9666a7f767db40fbcf6694ea3b10b80797a1e82f3e709cddddcd4ab86de0aee98fddcf9bb4d23f765e7c63acf1b13a3cb918f2e13da38562f41aacfd5c50ff5dab3125a0e0fb0388c9755efd394ef6f313db8b5471bbf870e6eb6c21efa9c564f465ce3061bac232e630628710c937b249e09807c7ab176719a1ec7b9a8d6e4fc78c0cf2174aba3feee65da89877f4ade70372c06d717c73dc92438c38c40a199aeec1ce25cf6e4bd3571f3fed78a5d0ea28229108dbbe9b1b95b37b87987fb196a12219369be9cc61c114c421be19158e23ce21ee502f8e1749cf6017c483538b35435f4491aa1cf616823ecd2c2abe4d1bfd58d8376c9106ace73c0d21742062e784ae7418869d9a02d8f27150fe9ce0e933cd22d6ceb997c5da20a77951736cdf4bd68d4461a8ae83db50ed09028935c3fb899b166d3c182ca6cd5ff503508a85d4a9b81a544f94fab8a3751dc3e839092ca48e815a1a7996a1f48964057fa0746103baacffc89a8bfe412ae6c6764d061a8ce397879bfaa755661b51142f34f79fd3d527088dc33016ac78fc18f96f755c968022cae7a4ab197eec85b9a7398e1f33af0763ac5c9f760893dc008de9f221a79b85ef6a780935bb2b402023fcbb89e85a3d06d3cb15f8df165b85546885f26be9554c4a33ea5a130a0f34b74a733e628c86be024609425558242fcc0d977d5316b89da48dbdf3c77f1f207862e1f35b45f66dd781043f643573828bd90c1b0ac6d53d0b76df7c130e2ab74b59ea5b63dd49c37e6b18799dc93348914af274b8e696ea289f586bbda0dd7da3d1a3dd4230d6453caa31fb46a4731a1598b411c8af4bb412bf8e9b2e2ca32a9c7f0c85bc65e1f50803b3fe5e0ca30c6d928867e07f3b253c985d1eb12c17b7da9dccada0f50f1c932b6b4fe1e2d400a4e318247e06be0d96bbdbc4c391ab2c66f691d6536489ba26b34e32a5aa2f25fed50e31cb364add7ffb0a4e10bba1cc717e5f1cef7ef2cec413b61fbd5283656eee701fbc9cfdb2bc721daf97a7de8cf1ca144d650fac423589904c5bee08a85e2286f571460c0fdd61330c8f89c5b0ad061fe8831345fefb08314b308caceb95fd2f353da55ad81217cd538bbb3b5b1ef1a78fa59e61435e8c447f37f900e93fb5c653a20cc84c30984e0853ef9df0480c8d6f8848bd33d80c89e38fb7f71556b255fede1a2e391160a68e51d27ff4e40ab797039c28b67934c82c355aaf94426277ed7980fc900a534752c636183db2dc56f7f51a79897835c021e80480437ba173e8d93bf5eb17b3cbc5fb3656878f3c25b5312d2eb5512f14104d1ab8954e837fef1669e3885d5106bd84e6beb078429d1239077acd6a8b9155276e4e37ddf42c11fe0b9a10e1d8d4825aee331cbd66132b6e64ea46365af8423be7e1aeb56ee6b7868e172c169f6ca4f25174d1648add667089094a60969e0607e09ef35ee5f757d69c83e16df8eea601096131b720bc9d1e177ba6a4a8a7a89e46911948daf3409d0f020d62cd0805fecc9821237d46c9641413ca2b1c52b1004040277c03a159eca9993c292bce31c413cda56c7910fc346cb3e9ad9436a8e7d12003db6d36b9f8f624c4cb3b740492c1a79047a8f84733caf3d557c0cc4cafd29b0288d6446777844a4fd490805936d25f8b1cf27fa795df004307ad975ffcb140cda8cbc8521aa70e110582ffbacfd74931157e55317db0e3f1872eefc40c9ae89cf9f60bfec21150caa5728806c8aabbf2f31a7c92b1c854621a15ae8ff0889a83b17ea20f00add93ecc16eabdc33bcb6c2f8deecb00826f2f20fcb8d25c9791cda567d3c5b4b1db0e0da912a1d441c7a2bac2405b9c202af4d3bd005c0abdaa6d201b98a194cc7808c400c347b395bd2d9bc156c363ef61edf41bd38d26b77f18454d2f9e00692f81410043875dab98f1adebcb574479e84ed50eb1b448c2fa326b304bbf9bb5f50c40adf78866dca9d81087a3a5164183676f09a535c5fa6f159fbcf5fb5f47ed5a61aa08908bf27b21b2b37247d1fa83756e8d26ffb97227056f2086e55b3f11f89c01fc614187d6610e5584b2fb7355ec8a6a93808fd69dc8226e758625c1a08e092d8bc7dff82351a9f424c78173b2644499b7577168ee3dbed3b2e57f43bf92e6a2c1c3fef7604690fffa574861f6cd9ac8d2ecf3cb92ea97582aa28a8625290c2492423412b7217dd4bc848c427cb837b871d3e9d46f8f535754de12c6bbfd60f729d9a4daffaf6dbb579db7ee279e7cfb9a881eec04f47c42875517ecf2d3b18282d66a62b6079e4bc639eab1a24f509318e76077cac1b4742ba0a2cb6fe5d2c6cbc19132e94652a556995124368c73c22566d774cf216a873133baa1c4b91a6ef4f0f08579508453a4e41b6feb12c3f6a6bf00b86d818f727a6e67cc2aac8adc87d95bdc0be85a9271afc6bf0f64a41f88709fe8d8321e7986aee3f2bac4ec0051a560f80aaf81e39260c387efa9f7472acbcd81d417c9003dc22e76629d1611e04c2252951ec1f7df7fd955107810892e8188da75eb2600181ea5664ff3377aafb9218ca4d66a3309302355e36cd47d02a963d0b5f3d3306b3fcbf8d99fa515afe7a0769f285329dc6345c12457ab877b20dc7ffc0fb72ce4bb0a5327f1f8ad6bc9d7ef97340531e2ccbbc387ed75ae8d29eb91178616a98decebde1a12abc635b504cd35616921a8c7b42d21f65af7b095d903c35f65614b4f521befdb7dae5d0409d415283d5fc665a7f28b26dbedeb3c5486b94c7b3848ab72f10094260c115700cd7cc2d3c7ed362ee9d764f7317b08444aed240c967d3655c5fd729634ffbf8cab4a0558e7a0cfd58feaa0ff65502b2701ce0d9175439c66f682cea4ea86f70f7339cb2136d9a89779e400991a7e6dc9d6aa79553c40503d5e648b29c66de9199f77635d485bc93f639f333e0aa4c87cd9333613337d13d47262841ff873517bc35b436dcef77b7529e42de2ccfd87b0dbca974d7e8c253da7ba1bad95767459ff3a4034a95d0fbe769753783b1c55ec95f1b1d25c057d54866a2c4fff5c6bd5ece63ffea916d2cab80b205d86360cff315ae8d2f6bf2f33c03ca0ef701291f853ecba987c59344f51b758570900eaac308d903e42b36c202831b3f4404af83bbaf81be794776393a4593674dbad70e650dc5003f1237d997782e08d2d41e2b69626aa3cab29dbe786f572331f2ab7982f8ace0e2b2ae3c0e2220da55ecd13af40d34135242acd9fcc4aa5f011105d1f936f9c0766bc8940bacdfe6f3a44e44825cd4cc98898bfbdd97baa20b6037b4f33f3fe30c99473e0c419b29e55ef6dc13636df4a3f4748aff419fbdf3c8c4abdb1d2544cfad582d19032b7d337cce262a20af30d2f373544887dafdfedf57d475292faa053dbabe458a6eb2161b84e9494c72864a2141bc533bb289e5b22d777e340394e0a202f8a3b75e5759843704e102cce519fe6443b64901cbd7fbb1c53ccaa0e653ed9dd8cd4129e42354e24611881f26fad750e888a2a5d4318b4a93fc9b6ddf30584c263d9940663bb45c7ff2b14d93db2d23a8b08b829ae6f54e286bf5124194123481072d8740e99e7e80a7f16c2c97884098866c3eb4e86778b31007f0585e430250d0ae11b4e1e1d6ab718eb6c9c102d49494b641b2c4d6eb19d0b4dba3e7cca58348c1d5b3c1281b4f03f72f9aeadc3128fe85a7fc7beb4145de53349e7dc2574a2f8117f6d01e485959f3b4d17333c27d6300236bfd240a60ddf1b5ab754fe8da67bba4a5e682c74373ee0f7c339b8a76d5de2e959c8faccdd0dd0939a28c64c5fec6538e1fedbf7d81535a4493b6a5f74a2fe567678d77c914a3910aa61f41baddeca2ff6204a87568244ccf0d03e12b35ae74356ea69024a81fe3e0824a14ff2733c75b9c26fea22f4f37fbdd11590b73ce7b963c606130b2caa9c12675a7ad15f9228c886e1943c870da7a72d1bb655c451373885e8e5c97f1d0593145d457c35a780e13b4fa8426e6ece57bb8eb84bb53ed22058e72d023842dd1b0e7d3249ef5495286a7d2be574f172a3385979b2ffcaec690ca27a9c5158e00135b8a3e30f530e5850067137666801d5db05930439b846276d659e29bc1cd43bfd732e882d655985dd9fd5b11b9ba325ebe090c5d85088782fab7d3c2479b3d51a9e8da746f0d7d8ffae09b960c4c572f919a77cf13f2513919ff34cd1d6a9f01f3b1f6dafa185ed41e2d2d2fab3a39098571133cb6beab127d7cd913bc2eeb19c53083bc09c123b74a7b9006f1190a107b1c389e1d1249853b52dc27628feddb54be47fa0a1926857f3be5875148a163113588bf9239a1d82ce343180ea6cef07ef592f8e50b9ae35fc8b3d97aadcb712be10de51575ff8029ffb5b0f0a9f4a434b1f4bbeb240e1db3d768d4b24349dbd2542b40785872e1d9bdc55250c85968d6806a9d35683a310172d981acb578af037afc20e7d29e6840423526fc16bfc741e769b97acb60e59f9008957e7fbed484e2d7dfc2a3ea0eb253cbe8dd6bd4c2bbcd18974f198cf703bd42c3048d98916350cd9f2340b2a88f237c9524a86655de84d429318e47942761b44c3d2c0f2f7f0fe98c4439dda9d155431bdcbc70488438eac738b345d7b5cb74d40cf3137310ecbde97fba8059a74c1a5faf8b27506556b8e46327eec700c28b8b0a388c86a1bd70a6432146743923f588c220827028b503f9f8bab5b29011962b221ca91efdde1b8a7af52678f173c2ee619253e656a94d5eac25e94bb90b0d93570563f4bce04feb97a8aef8891f93d86624b502f4c7eed03520d0da17d9735b2493e4594d82f1e7755f4ca11c5a7faa50b87e1af3284b553c27b8c5df5e8571040edd83b417a109c6915c369ba899ab55eac0654969c20fa84d8f37495cbf0800c0f4cb20edf0335ec880be95d567045bafb67b1d70cb6c3a5bd4777bb0a47554609436f18ede235dc995170a40d9f193ae4e2b11d6269e57bb5033e4eabe7233b0031e24beaabe65b5874f31322d6714429b809155f52486a748d5e6e204415b0d52875fac8686e034a9f15386c491e97d37c24c1e05ae4544358d742ecbc09ae912451daea3c737cf53ab65a0bbfef6e0e8eecc25deb3a78b541e7e63f33e9ddbd422ed820300bfffb82648bcc5bb0f59afd0139f60ce984fa1bb2027b8a1490314d3f326e884bfecbf5f242f63b2de62de4b5662d7f760f01650f2924ccc2af93183093b4051689af49b6981517856a8f11232bc577e899d6132fb5c72665d3465e314a5d41068972c6f4ae3707bb70f0f3997a402f66933099fb7bb1c1eee192c9c50c93c498a8d0c8033dda44275e14a6518eb512e17fce810fbe958bdb832588f299247e344a4604b55e21e9d13ca00d6dd4871cee9d1e95968739d8ed0ec9a335c8da0ae5f73c1e492986ab536cc292d270bf75cda01e400628543906d58828d559bceb30148cf76a77305fef5b14322928613d7d96ca764332e085e4c5e04feaadebf910258ef86660b853f493f4be3b4106401a094c4dd8abd51713fca5fb6aa90cae468f775b552a2cfc84fb6d27688c7e4ec4a8d28b632a514ca2eba0bc8de9da2436bd1f2dc640628d0394fe7223802072d63a5c687831fdcaadfe6a9f04f1d004288bf5871d5881021437931371fd49766ba9118729c4e70bb3916600efa46580a4f1096facb100c83844311fad7e35bb90d40cf97bb121899ca4a451efc8121593d5bd3b2e2232791689b6bb6635a40141bef64de44da4c557627e45ecedfed6ae1c2d34c890dcfcf7815431c1bdac4ab6f1c405ea3b1040ead471a76b7818f6e4a545ed910837076da270c4c7fc66359e8e76458d6d67102e7149294a8756391ceeb9d4edb7e59685e5f08be576317dea3645a8cc13f81162a38a6be6d283499cef441962d19d88ba4f5803521ab46778488d65395ff6f27dc62cd2deae0d4eac8b6c035cd68e0a2dbfff600861dc92e6b93503edf3b4cb660ccf34e4366d01aa57a0e5d6a6bd45c7f4d98534a50e11eb6bdde81e4d6371d9e2332f08376dffc9140dfa9c84c31ec05577fd27f797eafb5b83476b4dc2eb8fa0a68e488c364b5883220505f29147a46f1ac47c49aa9fc568955c0384d6d3066a799cf0069d5c1a44c60c2cca25ff54d30a006b31266e0925d7058ca21739ae29c86ca703658c45393ddbf9b3c17ea8ec185d5d19dfe35446316344c51a744d004fc6a25511ec94dc630e7cd3e655754483f84dc1610778bc060be8116c10999c8f70d603d0d03406f1c4f748da8e3f1262a317f09ccb6773fc091ef19554d56816e312668aff8df0340bb0f4ca6a2639f64554523aab5bee6922081b84c0bbeebe77dcbc77c878302670bfb11a8e157e00cbc710c879ff2fa298aa90048ca59e1c4385035eab2d42f8e513548ba1449e1ef61a7f67d33df93368119f35dd607699d8e861f0eedcc5dc9ce4c311e45f62f6e28691f49ed0a214dc6191038d5d268fb5aea28edbc8243d46bc3bee138fe32245ec8cd6043268c6c88f4df0c6276673270ae713345c2ba462b117893f9f8dc9437477e8da4d4d5a0e642b7ac83f2594476f618fc4fcf84c66040fefa26d2fc673871a092a083c8b243844c68ed25b4eb558e623f43dbacea2a6a87d687e83b3361232b694742502cc8b1cdd87261d114367bb43785ddb5af419677727a9b8b5ee6f193beece635860a6f8f8649f027f458ad6557956a240e5a1267f9cd879bc2f11a92c9047097cc53465e184fc2af1d3a39f73e152d0d15594a11ebed172cdb008b60324687fec64103b6ffd5a26e216ad128c09e0d658b8ee271cf8713b22024707863179007651dd0987e00f89d3d231a9132828debedcc9ec101e1cdac7aaa20d997fa957476fa26b5ad7d417476482062b6e4c3581b8e1c74b7a8e208b2cbb14ca70f04467b3fd913a61a50c0d6fa546051f2d9b4507865f8a0fc57041bd343df998b184398a085f01ef30d79ba652faba758fb6806c2574dbeada76f03ee6d93ac1a5ea270776b8fa7c071fdb8fe0f0a237e43c602abc75718e401aa3f87faab33693c559fe1fd52eb47b926b222b25d12828bfb073e7987b0eb867bf08910f6c89d44276dd3cf0d901f286ad9e1801b0b7483d98201cf28e24aa6019bd463f8fb31ae28e383e116eba0df9d32ce420e0ea7a74abf65b4f7e83087de124dff73660518b13d5763d173dfcf70dddf01d6d630b62259344069f1d5a7ec5dbd61d1666b3f1e13f7c4f4855b4fe84857b9552396e79ceec049795fc55b73662672c48f6645a83f915c8903ddab5b97b0dd2981b4e0b3e81ec55e2140b4ab6acedc4a967fbf789931800c42c8da0eea1e4eaa6fcf1a43b1d0660f5dd104f2de49614f0a7af9d089145123713937303a6ec3f6291a1d6da57d13792718489b7b78c5b36be93aa5ee2a11d550908e3e8a2d352258813eec92808874c72b866fad7e8bfc4c9e7419105ac1a430e94f66e16afdb5f477d7fb5a324fecde3ceb940fd9f36842a26fd8f0b535bc139c0c18f5948ed4df4f811d63c259fc8092fca49a0adae8af3343bedf26a222bd6b638f16548d1927b78b8cd786b0cb55e94fd1aeae8839a36ee8ee183ebecc89ede3a8f41a848041c81900a4b83cdcd8443955484ace353394830ff2458f52bcfcfd452ec710b0386ab6d08fd570ca72737053ee8e98ea58a7da2630851d6ee39771692cefd491ace5afef9bda3947e1e95dd14fabe0d8b6aeb80b20a8c1b948ccdcf21135047022e31408ea91b58f705a5d653ce5bceebb69ec8ce419f135b6c512b25a6b70b1b089764d9366656f1fc25d0c46416799b59dd478d2d5ac48e4d2b1c116421a2f5dbca011fc40e0bddcd318b8d297797b6eaf06a99c3f0189b4988e6e2d45880b189e898bba95dbdc4ac152f55b5ad7f4fbff7848deb31c793814519117d64ac020bf0120017ecfaf6ce2367a46606d5937858efd75ab4b2f6809f0260554d4238e0048bbe139ae9659bf91a21089682764105a19355d02abd5ff30985038c0fcc2911916df2fb95e33faf35d9fccbb59d2e0690a34b189f86e0cfb987f32c87b23f5fb5ec09f2506e2e72bd8ed67fdf0f6c27bf44d639507adf5267b5b1f085862656729df027f91c70f1751bcbb45c02d46deb78849ab9a1d059b679269530d6c98ad95b9ab68b8654638deccdb6e30484b75b6185eede6ca91a92c41418b3e2cc8970417c20d796f44834c5c4642051b6877c6ffbd37ad31da237b37df81c7466191a1f847f16f2bc220f65ecf2e3ad248bb74f51f7b65b6eaa6b037bf30ee5137c58bd84fe7c6f4ae33aad895515ebd4074b449d2f32d83a129171604b74eeb0851b8656c98354138e9e4bf5fbf70a1496a804502498f46af08ddc6b8d0754bee7fdaa4663de5fce051f7e3d0f04e0b1a3e361c75fb5aa61a5c233cbd22dd2da8ad618ceac1b3a741ebcab50cae5dd7513b0b6c472b514d011bf7d2827a937e0b494eca49f873ad5b85438383a7f9bbccca6cc23e3261ce4ed419ee3a02744e0740a1421d65c985ac48b742be3cdeb4b933e19bb496b26dbb66720eeba19fd88f82490ae2557d26d57c2a23d7c4327b4ecdfa9cc3475ba3132e657cbe02e9da1ecaeb46aafa5b855c6fc0861e27bc19f8a44581de7bfbbd8fd23e7fa38f1abc991fd86ff55e90cdb9e10b68dc9f97aa3a6b4d0a3ab35d01b83e968400789c188f4393cb073e4fe28838ced508d22fd6a060e9db89cbff71a0a9a27675457ebd86aa63654fc3bbad4f9b49a20bf987e66fb3695ae80dd695a6fe3398e0617790dca8ef928b216f0af0e9f83f9747306cc0e687db37ecea8f75fa30bdc327fecfaebb2eb30d3032209c423b55755731e36a6cadbabc7a2097235fc7943e4a32a8acffd295a3a53b6ba8dbfd11ab893b38d7536c2b945107888a9712d562906ba52542c6f33c534a634a9965803a42c226e047b1f1f744e840dfe1815077fd4d9004370ea5fb4d4081ca57ed5e4d34111d319ec695b7168014888705725eea173ba50c5f71c910559f233967a2397ea16b9c8451a306cb20a399a8f12d8d3f16936477d2f0e9c6d7970010baeebaed72b8f53a26e6b27cf38eca4907b20d224a5c743ecf0c720ad136ce8e04e89b545ea8675a8d0749096def012f2f18896a3c2968ed11c61408f038f4addd804a06cb09cb15e12fbdd91551ddd64a9e9be8a19a4ef70fe42fd8278d7d7b95717e8e2f067b3bf1a64a7106b39a54bc508c8944653183c3c54f431b0c5b879a3c08479f3d64c5a549f208f9daf7b662f745c86a4759e708137a89ca6ed72446c49edeb83e81cd1f4763e8e5d70b0d3d89965b42fd575e618b3316ccf98e5a85aa6dab95c4ebd08b84235653f88ab8cc0476dea7a5bd329a28b23a4628841d15ed55bcbd9296537aea5f52a9ac5ffb6eb9cfb3b70bce35b2d605f85ec96dee0315a02e789022371af3adb18f2e71d2a8be1520bf4c85dd2cf5f677d6e500edd654d4f77f849f80ce97488f0dfda811c9caac78bf1b5812451062169c345b870668f6c997de753de22db07caf1a67aea150bcc1c030f0c4e4d4038ad49fd6dcb1251af23ce801ed9396b618989b859ceff538f235510f9e73f327c42b5018a7b5ae238d7add41aed6f075f7f0e5695322a98fe6007da7bac0e86cf40434541c568740ac503c73e590496cc4b908f77fb90d39ec3a34e72d2ac38f35838258cce4ea77b7624782523fcec572e86b321e314b8f8670a1e335cedd583b5d925f8c7ef7e8c359419c0299584c2050f9711be0e161541ced7df8f3d174d09f0d626b74b3b54656ffa7601599ed83543a397f5419da45fc76a02605eb8b54c6e08dc6e4a12ecd51b1cc5c3cff96a6b9106913ce433c0a3fecd029cefd03b81f94f60dceb2e3d3d0dda808ae1bc170fc2845032567c5b43bdcc73d12aa1745ccf8b552b5a8d6371de7e46562694a21734ef59c278aa12b5fcaee248c31207e9e7a52873b3942ca3295fc7402f0c3e414522bc9157694329898c8a86c7a69d5d8ecafacc53c1e1b18205f18b98f390fc02adcd21b4c9145ef30abb644203478f0908eb1761309e7aef66f13a11502e1e178f1fa0c21c39123a4b17f14bf577dd05daffb09850530b0b3bef2f5207e722e67a0322b13f221aa1d39fc5912101112329d8e5a50bc641a1a0933a1ad4f8d3d93665f43fc4fb64c0fd338859c43f15aee18bfc035c3e20ccd0edc15969e282b786f3b2bc88059162727ed2acd73fdf17c6a3f0f142b1059b06c283e35d69681eba84f5515e26e4003e65046d6df0819877bcebc2ada3e802612af86eeb0c9f60ca264f24a463834130a9506f1dd2aeddb7f181b6eb5df03ccb0f3f955fe8ebb81dfb9152ad961ae6cf66d2ca9c41e6df1871518d51a3f92a2a8a12f1b58c37556e3d734109d171a4d9d0de6f868ec431fd78848660ea8f97201ea0393e12175a001eb47c3ceb7709774fd56c6ab97fd3304c6380919ea1bbb6fb0e3e79c0c68a81b92d7e8818ff4ae5b9fbc3cf3f5154af2dbfee8f5c3eab56be7aed337d1b86b4ea669dc54d28192b8e7460f53e411beaee8a1fb3560e2cf8a165ad6a5c4401fc934c20f69d1d00bb0f170f12461ee25e9a700f9f00501fa6940ebf8d965676f7675982d1247031ef884f50e154acc5301da9e032b0b44cf789ad2ba06785cdc26802911679e7cc8f3d961d3170fe25134e147770164933252f92504a82b09cf5ae8aeb6b65691ca54d0a85d2cd2857151c6f133c60f26c6175c9b71e38b26465092dda86c000af2675a621fb1a78b327218e79c8a48f36b3291de7717505921522cd689ed9163c5d52d65b1a512ebe4b2339d14f86a3080fd58c7bbb48483b393657ef5fb1114c9060456ad133a69ec1bb83e78764c58c60edb7de190b34b3af3f9d53bccddc84ca2a0d72d05fd01c130c14e1fff2d68fc4a3d20e5fb221b322d1c0749071142955ee95110a1aee0865030112ec46db133d06ded59b1e20c398f1405a53aba9a4e666b9ff981f7f1de24a3905df7b9b948fcbc3b18b95e2fa3843d6880aa21727c48c33f946a562886dad45f9cb544785b8bc51adef7ebd6a1592bb3bb5b4d191372dd2061704542fcac492eb4fb6f970cf88aeaff92ff2d13ce52ff5eaac7f665548c927196818e21b1550ec1968f4f3fc38d7671996d4b891fc820164525c3b2e4204a98e2b2c5f1a5fc9d1bcd168c11d8832ce0506ec06127de4433c57bcca78d8d32398dc906fd61400fc357853bfd821c3b7ca81ecd19e01d3c227015e64969a275d16410f91c99406d3ccf49b7e847d7c3e549620a0c1ff5593ac29329d114556076ce6ac3379ef4671be92dff105a9cc45ad19a23f2f69ab9c896e25f33bebe4b52c7ee224eeea4fd3378480c597d994609b208558fbe16fcf37898eefb1e7b94140f95b29508d786ad2e46eee375c857d0b23ac47ff1744b7051849a2b38ebea3f175a26ad6ee5b2f7128f674ef22a426f03cb8d256f2939011e7feaf3d1ac542b84f0b0fa3bd3800fc7e214eeaf1721e05603d825ad6be46df2d8abc45e6bac79e9e34cf1970c4a0a89426e0648424751af78440b488df66756af4909843604e9e38a6cd0e7966dba731d494808c3c6766bbb5b545ebb04d7bdd19dad7a83b2bb82513bc1042aafedc433152f13f51bff0f5d6819e63e9e65212f8e119e8ec64bbb87ab1c7e843d10775de8160201d70447be796370e61973444c4feeb87f756b26d421922a7455cf5f0528e702d38e29b2f7bbca19f3ba6c0e04f5530d01bd7f69a4cdab43d957f9d8cfc0d2b07f2d441210776f9d0fcfbdf8e6697cb868f583b62437027164144ca2dedf1e5cfe110baec4573d272daeceb99c4de6e6bb18c9bf0c54 + +# Params = SHAKE256_W16_H16 +# Msg = +# PrivateKey = 0b00000bb4b87b847089c9f31201b44ea6c5e3184a0f7ca7c2bda48f4be401c0740c44b7834a14eac37437e594573364c23e624d8bdfbeda6fed404c758647610701aa46c00b19c5e9282043077e91337a154f6335fdca77fd70c367bdcc9f6443a364128645c3aec3b27f6dc099e654e0bff487b7e4f2ce2d3f921ca435a85d50326f4400000000000072402cf93e43ca36666dee77b8c6ae264a39293f7044f07e531d9e1cc38a485a0461a3656784413a1f013b8c72c09e297254849151132378ee2dc03e9f4eafb7d8acf4c6245997543630ef1531ceb471681731266f972de3274d2e43a8f79134a329a0a0901408846a47982d0f225e6e50431436552d72c93fe1ea938cb398ad54a6 +# Signature = 000000000000724038f11028f2c9d5fc607db8c41bcb310b0a0af7f122436b643712f7769e7256606293adeca69601f62c4b814d3c89b1e343120f40fa08e62cfe6aad6ed0fb2ade327a60b03ac1eb6b5a85074c4959ecf62fcfc6936da859f9ffa4c87c8acd338f338b9709822ca96b6e660eee58ba602ff3f34365ab2aaa03d7fcb30d2d6238858bc47a67734840d9d56ad991edd6791fa55fe1d76409c4ec838d894f1b629c5e3b134693ef7655c5af27224fcea0e948e357b303a47dd994f2bbbcbc2b5926d32b7f5fcfe227124483fb4419c970ba209fa234f522ffdc1afa08357ebc0dbff2aef784f4bc818a3eb7e08823f1ff2170bce4f76181f0448a4fd6700daa42cc9ad900cd7f080fec30ead0e81bfd602fe0d2c8edc4650a19b851b6dfea73af16372da654d16591e2a82e1e7f5edd75a49640ba94ffb1a062ab1c282c552c256569d0fa5337425972a38d4c432ddf0226aa6d91ebdc4812ef7428e7e9c262edb5394d2361e6765993fb454d87f7707b1ec94b88edcf587ec5c09e5830e9d920c27abe6894084fbbe0f1f002fe334094aac118ad246f723e6b59011b91fce84728379e3f83e9aca87d80aec33c715c95463a16cb9761f1cf3d597917317a50c89719dba472ac2fc0bce668c17e5a17491866e55ace80d4b41ce712f796d20af5034a7be75ee5526f994f0cfd1db703718df5e48579cf69d91f3863550240182ee4bf4d160d991480940873ec82ffea433ee9ddb760286868c56e9b61a5cc54529655eaada67e79a7f6783f79d461315a506866be81c1c83c08c71c71539cac90ac2547fc4a05a35dd8be84879f520dbb2b14b3ef92d253fccd8f265fea78f9e853cc7c62d3565d0175949f0a3c8492c570400d91a517ed9fec40e144f20e36fe16ccce9dc4df5d6ef6abe6c7b73787fab104840e4eb3beff452dd988c2f17a8376959bf40bc7faed8402faad231d772cbfec3fe185690fade9aa857b48b54167252fb8b1ebff9d1b8ac0695ec02cf50bc72bf7bc77fc7dde0c1b7f76d9a15bcf73e0e1487dca81aa40d175ee2ce3eb5441955d8006300b5e756eac6ce647a01706827839dc484579da113aaf2d925b882dbb10fab3db506b6d0cb33a8071c481ac33dd330490a3d5fe274f21c3a3ae370f06a80ece0935c7e6155ca1a67949a4f62b25f20fb6e832b72f4b6318750a3f9dfbde538637d73a4e3caa52debc61f6ef63130b10f97d80e49a1b6174f91e7bd2c5e9e42dda743a87991e982275301fdd9912914a1b3a9b726f878fc013ed767f7c4e96d0e6379d5f301fabcb230080bc58daa8d6db42ccd7b7066df16dfef55a94af9e4771e3fd242716e7a44a6da6ac244ce9b9fb7843564c5a678ae6bdf98fa0f9e86edf67e3a210681d8a0108ae102b278f1e5ec9bf8b5aaede191105c43f5ac7353d1a957f0b6974f1837fa3c577decdde4f68c5e9d0e3aebf72c2e98d974f9e76de872eb148e28bf3d36779c846f149bf3b8105fff536476a389716a43f94ce0523015ab070fb3a249a6ded9283eb642558fd127114f76aff284236ca0a2ed41ec950ba94fe0869e5cb15a33961f61300319ca886c0e95fda75482cd6463088c3ad70c05bad014ed8b7264f8ae6ad7de2d31314a2f8fb244ee89548c438b8b8fd1d880b963e514ebee969a997fa7e23c95ab392cb5fd1c5f7fc3750424f1d4e9be8f47d28a03b8ce45a8096bda1d5cbc4740583617a5036c952e72c1da9ae75f3687504a7d08df6daca7053592c43d7955f5066299eb8e8fea2aba158d163033ca42d508ec9cb1050482275f6ae5e3f75fa454e33ac5dac918775373749ebcd13b8c4e7b0905193c90348d647dd7a92dec44c6f7b6bddc47e4200569e5bfc646541c888426c9166678e8c0387ea07a703a6ac4d0fbc5c965fb902a965f3074594ca7a43725062cbc40c8c1d9133d897dde9a5cec08b1a63a8bef191f47cce7db14afa88e9faed23e1df909d3193bc5ff49316af8d50feb5912cf1bf0b86a26f1ce1ea525e17139264f8c07334f7231cffe14330c6fdb845c89d239ed62e126780377db2f41a12f0d1189726f66152bfd1e6bf381e2a3cd7831c2087fafb0b48ad936003cc161253771b41c78b43483d22b87fe360e749fc12997ab65ed96f4e7b2755bd7efdbcc0eeb9b4fa815aa8fe4a30b8af83b4f29f0ce5343ebf9527c0c380ac6b441fb30d53163cd021c8d311452d6305ca82edd835cf9421066b615b13a0b5ddcc3375b27904a4be5c12a187d135f3eeabf7fe940e5d96c9438c2a8230cf968e94adf082805af21e575cef7d6891ba9bde23824508571cf4e325422235186ee1b4e02a66fc129ce5fd8c234dc0126eb28f44ae39afeea7aeb307afc42361209d7fb8c9a58e18fcec200dbcbca7faec0697c41122353b4e29f106019beb1f9166a389c00bfbb754be10d3306ed9b6d7f65af33236aa9e5c7c2515c62fbf109950550b4d9ecb754035ac98c8a6e488926e35b28d6adeb587c254513fd0437228d9fba3e974a0104f592a13f2e24693c84222a799dc4608e44fcbd340747cd3a037f64a1cfd6b646427f7e5f7c09aeece3ccce31b7396fccbfa723b98339409a0cb15dcc897c00c4963c630032b67f1d508b47952c9fb4a45c8fb59edcbc4f43df276c51c871d56974765d74b4c042358b1d2a4ebbc34974d252d1dea7185746fd965ab4c1b65006fadb5ac3e6d7bd2fe800209c149c12a841379081d1a3cbe88e54906170d32b728f9a8e264fa50cae54ec4247e0b276860b3832e67e5bfaa903977be94fde076aab9dbde075216f48c56ab20fa7433c7868705604b8c0cf4dd49590317465e42d387b4368b93fdbab695e86a5c3c0a766b307c05da721c35b0be58f09b1cf9c2da761e6e20410daf521a6d265a83287f6d5e7efb825f7429204671e404f9c0b21ff1e96a5473252974b2beeb3c09820261726ab08b4e6d06d9cf1049e491bf8e4b5df7dc661af9be5cf3b87c3b080f8203291107522fa4b9ce751bc8b3707f88f6ccbb58f31d385090f61e07b1eb4d9b4181ba209fd19c5258b05584add01c577a9196371b57bf1649046a606b4d73320f47fd7231131fd3fd87cc329336c3c3ac60bb804144649ef3abc91e3f1d7aa5ffeea68af3ebdbe5836cd44f4f33f14fdd8b01e4ceb1e530b9ed01d738d2196fafa9a7b533483f71afa82bc13e08632df2af77a40013d2d681ec545e9e04dfed7354aaf9635ca694280d419ad11bbaf34672ea165bb6802c9b0111d0cb49ed924e09aa936ac2aefe27671ae3704a846649f117ea905d8374cbdf82b8dfe202036a0073886e7403aab39148efdb818cf573140f66fc6e5a8982fff7beb4920b17f02a8f82fa8888919b08f12c60c81d9f0f53f23fdee99445414230d7aa04a54966311b81e245c183c20933c9e458c2cd5a3f0da1505a3dc13f872cdeb2d90a3b4e36e469807a3911989d339817190275a82571af4390a82179effdf166fd3c43e3215368c76acd2a2d5bcf3396f63417a4282f70aad3c8471125bdff1f006bc02c9b9bb7ce7ec08a20250f9f95bd609bc6041d81fc9fff0dc63da26af5114ce716d53cca7e9721ca7b4ceedab329cfa8dcad55602dc2d55eea39df604cd99be2630c8d20a9f27d9b5a0de7701e5f005a118235956d70693ced2a423718ccd72719130a8562355b69602860413d047d031555b79910406246c6f96ffd7bb39e63e3d47603622cb82a93cb29cb45a52792498b20da2f5d1ffa29b72b06f7f81bdbc56be697cac260df4a47afb3d775e7bf7a50d70c4092c02fff9c4e43e2ed32c04884b68821d0faae4752d7fb2c9fb9e3512777105b2b25ee9791ad3b7cd2aebe0e484d8830ad99ea09798ae85b28d1fd358acfd5652e990c4adb3da7da22b50464ed0ea97988cadaa18bf032878cc4b862bae27667c05604cf216be932afe18f5581bee57f0be91f500bc72d9b2346e046f66ecf0ada4f71d04f0fdeef8ef9bb4786753ea4b37401bc19d4640ad85eeb3c12862c854e3b3fa5284dcf3f1d519e6dade241ff3c539a74e648cd631be2dec9f160cc45fc28de369374a386b1efe85d9dc8bd0e173595338dce2500677a3f7e56c59c15affdc10a791a5f0f90d1906d915e3084d73eb295651b16be1b7d44d0ee78333dd0d1336896b282d93e49aa8388b97a641a55849568a5b47a97b2f7ba3e587da9f65e5a63a8ba29a1453cfc256d71eecc154c9eeb40eebefe202795013969e39849075f4939a4b6084def8f8cb016e983143d7ea93eaea22a8af2294fd3ee94735989a99d40de64c45d77a6171e00a9cbe694fcf09dfc1d7e80f918c52edf383f73115fb830dc6310704632d56901e34309f3168af7818432dfbe2d921f282edb1357ce8e0342815ef83c6f05c7b83942bf3d3849d3b0307ba8fc77e7ed04fafd48b69eaaafcc31c74a094c2a78098a0c83711bea2a1eab1101eede24acdf52e771432dc8651e1d38a9fa4ccce9b6c538ed39ee9abc5a66d22b83400a186f56db2fa5deb04d3595c367e23d58d54821103c939e4f17d5ddf8d726e9cd17aff5b9922a6ad342df9b97490631c462daa66bfe160f4647edbba42e63fec6dab3624195272ee365db2ee8ad5373027b54255f29fb458d615aec5aeb407f8ecdbf1d2e0b1c2b76109cb3652fe2608ac5053bba1fa98e703db43de047ea60e429386e75ede88ff1a74acec03160a93ac27cc0039656146cddfc0eca6129a2cbe124e2fcebafee80cf1018d19201a9316bbea7877c4d092e5759230fa0d22491416e8c4e90ab5c6c4dbd8ed497c2db53de25338acdf484d5edfc3dabc0d81e2d635b6a05e6c92254e73fe7e1d928808b12294c7fb3d744709a092b0c551885707b7623aa9679b9ac70cc45ae9e4c95206bed67293eaf6702ccebef0c603c644948ae70b1aa1532b11115359e18ad907f89ed8dff359b599fdf578596c7adad345d779e79290d511d03527481076231d102b707eb5bb61f646ae5403414f959766bc5dab9a010205fb0ef22b821fe3606afc19ea757fb0e8c5336c2ba5698e93e9ec9ffc289ef06072834d0ae5d94d5c8ef07b1cf150165c69d906676264518d94918d253dad74220176500e0d87a6f4a91aa99ba64c1178e8260ef3725329b4647aa96f6a56f2a79b52a4cd0510767224884fe28fe648ee6793bb183d29c2d7a215268a94deeb890289baef534be7a2f221c578e989b079488a1daf5761e331d570617d95fb5ab4774ce626783ec67a48f2220914d1837b4f4ef24c50079b0fb74d50ce65810d9119aa6c0763fd3c73c16d2df55fa67e00a0718f211d8c958c3865a1f7616f5837e1b35771c497a13d193b74f82a9bc03e7d129a826e8aa777f390db65bed87bed0f7653e9d965183ec6ae9b21cf40b16b61eef0a52da8fa1f81a83cdf5a419526f8c06a71b1825104be1577d6295214267c3d5eb11799bfe53ec930b4b537afe1f9ac9770ea8e1a29606413fbd0555355e4a4c5c9ff16dd3420a9f4288a40b3d11c28f77ccba75fb776e13d77efcc1ec413d344c20160c9b6e543103acf01bea82469ee162df30a1230ef8f45859ffb6d29c05eecb9aeb2e8e57e1568f57a4ef20b11f7fc0b8a4626a0061430df5bf5b5501b245d0a598c3dd739a65867effbe1283f2c81535a64d3cde2ba691daf3938df332ec8f38757a687d68d831b415aa6302251829c73c045ae2b7d2b2a78277766248a70633373e2c26db34f9f998d9e05bfab5502e09ef10094c96ca7aeaf9260861059a4dcae0167f6d586a639801f64b7c05a862211546069785c2d5ff804d5e372d9491163e0ab3d4d7f99bac0c96063d2f56b0b35342997164359ebe6ec2804c421a7049571b01df4cf4f78e1654d790565de0646ca91ac1764ee0b294b5c25f509e4753e9d67db7d1f3677af55d7a89406abb666e3cbd575958648638b4a4e657edfea70c05fa6b79f5e6fc780ea4826f09491dd4e5117f06377aa0d21b452fb95d5ba24fe5202e23c1b6290354044553594eb2ac9bd36d45649ef8230dd647f78406137784e86d64e15f9c63f22f0973ca684823a7e9c2097e659b998d182c560dee3c10f00de113713bbe0e959c6fde0f346b3a41313d0fb332cb29a3f8a3c3e0373f7a782a562e317f8954948cfdbd45f2ca2a2dfae29916212574627a264eca38486e2ccb50cbd3eb72306769e0bdf9f4bd3d806ccadf1d98d9cf180ba3d119cc07cf33e383a6ed845f9e5e8e1667e0a57b9fca6de8c77eaa20134f0c9d4e48109c0fc2acc6d65a3a97d0ac10a496f38a658cd45c895f8b11b325b679e6e26a272f1729ae39b806cf364e6d722a1128b0f43a687457812057efe9e0ab11eccaf7ec2146c6ff9a1488326414e46e5c0e92ebb5f524125d6062eb58d9c221be8a588964cddcb856c5a470f2323297d7b557fab3b4ee4fc820df0c138c110438d0965df5887307e5f7b65ebd663a1eee68104bf7004839e42df4b3fbfe1db4df4576fd0a6828ef962b0cff32c55183403e70ad31d3f3f8f14bbbe0ae42445be089b6d7040895b630c3c8f6fb87201f6e0475e29428d5f412a0fd39294fd81faffa59748254706651bc0b6c66b4fe0557ab52ca92dc4330920981b6b39332f05b6adc9553c6859447ff1fba841d5d6ba6dd4204467bddb95b41c62290905e8df5046ca9c5d39cdc5d08465c4667eef3734b5620b045fa78d203e3d6b80a1dcac9b154639f88a058db214df081b87f5f683005109d88d9d3824c7a57a3aa904c8d21508b19787557ef5784d42bed5b252660daa55413864bd8ec6fd1a8d16ea9d5ec0b28c9d5e9da79a46548f425b4f5dbcd4692af569089cfe13b4e6e7c1ed4ff61419855fd8d25fbb052b9e8136b0b1311f765d9411b0891c504f2495431ced6e1b41e58d162953bf627607458ef0713f9a193ace27ba2d5ae1f2d074ab9964e5a094aa2e9511d1e10af43494bd6b7ed85f6eca55fba7c5d4dcc54e107d64f9327cd5f3bf2d7a61f057e055f68985431379892824e745cb23c7f380b91bbd793468a409332a704415b8f2712d2950c9711537c38592b5b4ba622285cc825b3338f176e8369753989718b37af5972a454dcdbb0b2bcbaa4dc25764df2d2c9baf01b068417f69a0a1f3a0d2e6732c9577d5f05d4bf5ac9928788e094929bb7b0cd5d257f0c0dbab8ba06a2a3c267c1ce99f55a9f1f9bb9fb507e81edd03af9e46b6de3525f567349ff745346e127b8dbd93a87ed29a294615b3b97ab4aba06eb356992cf67571861240a0a7a11440c8898dee6f16c141ea1185be36ea533c8fa5ed5b4637641beb4f29922e6a84f78c283b65b3bfb8ed9cb569bf88d88ef10f669c4024039d6a04a4e9e724317e5d21f9ebe6da5465f2ee425f21ee9db17858a1132d382002b9f25b9d0bc105a0b7387e3556bada00705ca9ed07451060ca2311a77ac9bc62a6c53cd255d6d2d1609eee4ff577bc47f4baeeffd3502eecf7420d8313707068e2b1edf4717a63f42323f70a65931a3c08299e93ae726e63f2b374b020d5d3f40cbbbd4d95328d7e9e00a057c96b1200513d93af0340cf8b90e8c138d30d8cd33170b75cc1d7cd440b0414f2f9ba8003ece3e6967132db29265c0b0f76e413b1504c69b2e16055b79e6e534c9d631248a73e2e172932cc96b31abc8f5c127b64fe89d0d256f6fc0676678cbff739d46c98e5d110493d78b369c3eff98f2887b55dafdac803c5b318c35b2d712879f5a504509de6a35780ce916271f3b3ef6bb7e393086f3507c146ba3b6e37ec8157e364ff04c0c86941996d913410597c23bd9c0c4e9eb14210fd054ac4c5f560046e0e20544a1db429d9b823e104e418d6e4135a4da93990c7227dd6419dd975a4a088afb682e0be2c263de14a87ad9158e4c0864cb5bf16277e6a7afa03b20fe888dc75470785d16b5b09939230961569ad7939f4cafd89cfbc9aad6bcf75d67d7fb7d510500eeaa3ca93e20304ecbf6718b63dd8b1aba990ae8ac416c60243a84acdf9f178a23af5dc946974c7a5ad49ab50cd3165fcd7009ed13375cdaf16914b64c970f48666a08c7490754fcbb61e9ea2cb2504a7ebbcc3f43c3b1e7bb57e43f8897940d3ac969be5f435e0c6141a6232cc0fd83e4dd4edd50959aa75a2841b585306d9de325f126f547b7d44860a4fee24c778dc448fbc588dd4572209dcf1b09ade5a0a28858ed7d6b6a0ef152af546ed1c79bc53ad057a4439e44d9b7001486be0dae7389924d93f61421d95c8a46238001d1c6dda5810cb330a7f98f92ad31a91b35cc071b67c8d6d174ac1f19722de1721ea6b6388dbd759e73d44e35eba6d310a426e3bf469601063cb56497cbabb0dc87cb9f8f2181ebd605d3da36a331ca344b7a38b8e0cc691aaeac7f2220f71e1f3257bbb93def2bf87bcc2ea80f4d89774fa7e788b48741e2df058c25f64ed4efc4871ffde16cc58c19a4c14c8a859dfef2d3045bef81efa53534cb71d69814ae4bb37d712930fb7499eafcd76225e602553f466e1b96b0966550eba8cbb432454b6520880a693c77baad09ed4340a525a04d704d7cb4a318377b6a1c9fa0f24d69ef12623061e15c0c4b91e877bbb5caf6d3ee127533c0762565dd3643237c5f66725878827f47eaeef3fa333dda58e330894a3093509843517175a3756e2f3674f95446105f7b195b233ecdad6a21ebc96fb5ebd77d09859b61ad66fece19d4718c71ca6d8465d83611a6c5c6d760e82a3240f57749df0d169570bc9399eab7c75552e49b80db33a99dc1928b387f6c8f2fa233cee544d5a92148a1ee0271a35ce702e020bc73bb3ee5e25468dd832f131cda05f9f8ae8c4187851aea7e11e80d996c2e7c81d294f8e8e939ef8968f0092683179b11d8d34b1aaafd7d21084e981abd89cc9ef92d4794b9ff666ccf41490cb89f57a76b7dbf8018d01a1a219352d9fc086f999c3609afe2618cdfb84d44b67b6f26efb7ecdc998277dbd6f2d4959cce0952460e052c29157ca8d0b2956f24c21a5c3be4b0abb92ab67115b3695a959be7c3ef3dcd51c172dfdb7d931b3025fbaed1f337bbfd51aded2b63c028b1a193792ab4b00b912dfc446f4e6306b50787203d899679eefd86c38d7292ee0f7b5f2e1b4d6dee5cd6a9a3012daa64475c7bc8816d2efe43f04b4f1b256eedbc04709a80d66ed21c53d7023fe938855868ac5a7418707e2c6eb8d0d8da7bfa44f9aee5e27a920a0bc69bd828b34746c3d9f58e7dfb576a0a1597828cbecf04e3afe5fc3b76457137d547951bd3e89d08ffdfdea394b9a27a4fee0f3f6cb5945af9341215ad25be77884ac039d35fd7a5554d334cd1f22e78a655fe5c404637a7071535afda837af3ef79d77fc370f69de5f70faff027d36606d9caa3afca25238e735795f39f004f98a427c2786ca8b48861bd6c6d8a8ae69d261d0b637881ef3bc77f542ced8e7b6a7937cf8a248422836898ed99bcea64adf1d87218d21bb270e8b481b7bbd1c24b56900463b878d83c8957baf4e840d487129f1aa76a5f4b267f7df7f71dfa53669dc4b9d66e9ed4d4c70ab303b9bb16e51fb54445305b5e322efac48ede65c46a19cb58970d06dbc1e8ccbe7b3d1abb2a2c63c74c9732d061bc7ae59130ec134cd63e57076035a1f0be766e1948bc0131ff3acb713c375567df4b23e11bd13d01fc69b5855b2da03a07080a10e78a3321ba1918843e63679afb332999eebe17e72e8e9622cb843d9ddc689800dcedb260cd548bdc0356f129ded37e51d4eab00090f9593cd2ea79205b69edbc472fdcf5c5ac7c7b95dccc12b1b2610d4351963ef13816af6b3a752f206eb04ce2a7360b1b475e56c5ae9845f28b7650d795b0ece997dca59e7ab67a21904c3f8ef2fc1f3aada16db373d7a7f1d65cf9883f6d190f62e42bac2249de17cf6551c3a5048720c90792dc7bad1f3003727640a0dd8603ea7db7695645ab1fd3e1481fc1e5a181bc22435520d3e2d24d30b95694aa7b40dacaa047634a64f075a420b0ed74545644bacfba5c6cc78aaf29aa525b4a8080df1c3760b660caa1ce61d6654e8b8860c2019baab0bc9b17055814682ab9ce20d6610be5d2d1ba4284cd9e6c6ddb9728edb7f3254ad03c739f75e64e54278eabc52dcc769848ce9698f040080f1444ef273735a783668c4199d7ed5e2f3a80de22ae54c700aa02e365f6c809e0347940408dec322b3598c5a1267164e5d870362d745ad398dc0d6c43791861d48202dbb66cdb80537677349cf1bbaf2e2b88ec5a73a695be88f1b0c0de52343c5a25466721888ab5bc63735b0fe0dadf5bdf9ce2e035425dcdd5b96661b01a2806be2af0f983ada49084f64624c64192a69370daa5d0804e149e19344f99df91d741385dd5247db4baddbbf8bb3fda820a46bf1c095fea012e4fc43bb317b00d7febdf44399ba0039b41655e5b82325f7e18d7f01b1646fdc97662795140a251cedd9ab828190242179a72a2f324a6e26c5ea114969d1736b3a875cd5bfd24bd587961c2df39af01cf26fcd0335b57fd404d7599f3f15cd54dc35abb9177653ce4966e1dba3694a4c0edd853be691e51806bf4165aa64ab5d8009613123e32cf72ebedc63c65539c985f36e74e1ded632777a299f2bb30ff75de78f7df1c9a4d9b29634ee7d1ab983cc1c072e85cbad0dc692ce966c310f93906352a7169910c3613fd19159cd31a7fccaa61ce9d03ca46948210f25a67228c0bae65fcca8bea93f6b66c87b8038cd16f09c5ba1c143ffe3fc11eacdbd0beba3703260a0c5e17c0a5a7be337a213567e78032f84ef15ca978e97bb34c64f763d3dafc7fe228d1371bad6bb0accaafbfbdcb31e0806fa0f0cbe2659612698c96cf80bfe053e568e18b7c47a490beae55be87e9c3ff42fa9bca7fa065894f1c27b0da9377f1c8520c551e14506decfc376c909e475caaa7afebd71f015f6992e3130ca1235ebf0a9d012289e70c2400c9a9d845ec91ef03bc3f3e533afe582a909e3df0b46f6b1d16785451a71389123bf67c593fda156513ab053d70f65d13cc364f8a7d3a735e8a2f922db3476f3aaf7fe74b1654318e2a508d9ab1695d481d65a25994b4b6d8fefc25eff62033aa83f547aa5d6337086534c53c904e532a21cb3a378567571cac162bcec05e888d99266264d45b0b1bae706a6cd6c46bbe636ea153c01837c48a74b8568440dc90a556defc59a89fcc4be9d44024ba1c1d9bc944c9ec48d5ce03f2e5315dc9c152cfece3275f673e1a198e00e6a1bb56daa02d19ca1d111c32ad53e6060a201588929c2fa6d88fffedec54f30330976583861fa9c55eba0f2a2822b35c1e6d106dd3f0e7891fb1c8eaced3ab3afabf255a06bc6ffd2caed6c3795b1c81534dd81db3e3048fcae1e552ec66ca25d61d741375d02303193e25c9b54827a8fe3a1518dff6010713297cccbe84c0900c00f37d1bda1d65521aa6c7f33581f62e5823c3f3a91a8562261bbbc7b3fb14941dddaeaf7b02852fea344938a44fb6da983427fb2a543d4e93f9790ff9302ea58cc57cc0de1f7b726bdf7dbe4efe305c09d52a6c58a761f0bb208f756f6773593bed4d04ae60e9f189180dd1891a1d1e64c3a2147503898eabc2a98c99f8cb6c102917ee9b2ab27b1b3bba38423e947ad4c302f095860c6023d1e2369bff7e1845b23d3b84c62e2acc034a0067e8e2c0c694e9a604450988eead25ccec822a71324e36d6a3359602a857ed4c1ed613d771b38056aa845e60fb173fde0faad577f88e96a1fa890b95c8a899de77783bb7335f369eb55309a8c4af6d8f66220637cad6e99fa6eb5416babd9138b7d3a335767c4a445ce9e0a83a34ca8fad2b0f82def34262ab51d57411b1051c6ed183d93c0e79265187089b1beee245ca519552dc6928b95daf9f3283c88c0851926dee665329db4178f69b43b5c75c6ec1ddd242917aa9a8d2d75fdcb6c47920a06b778d51600b0559b68cdad64d7040b4d209feaa0af8615764182cba890b50927e71585d366e174187213af88ed483aac405b2c68904c9af611eabb77e3777c55d6f45d9c5d374d08949564c214615e6dbaa9f49d8e52c457ddacae4d9175e19bb9384ee5b63b057f8d96be76b9f94a5c549da47d566dcb67c5912a8e422d1ab74526a9455c8932c567a6d0ee48b7563e5f35fbfd23160793f5ad5940692abcfca660647b6ea62d9ccf95a283ce641d1784abf518f2c7b7d8a6affb5b6385ebe34e258478e2911fe5ad39b7dc7eab4804392bf791b81854a38f9a8c7de774c9cff06b511aea987f7aaacb5c784a205f7a948c7a10d471ab4e6724ef839ddaecb2892a894b91a6640ebbc89856d36b0adcc354dd411d0af36369a00e8abe3d406945f99360f20d13c2267778e8b4ab1a78e4ea332438055657b31a77afde47468e21184e1be96386d603c71124ad4fe2fd451456e218822ae3f8e2b9faea667c7c7a11b3b405f1f6e44157c0e7bc698f2f2277131b3d17f7c0eb686da2e1434b44bc47d8ee700891e977a3343dafa76e21c5e8902fb3b84d539aa77f84496a49bb0698f1ec794be7de4e4887bf2f48f05f6350bc363a6299db6f47f1ad0f93c12eb0bba93686497ced1395149e3fcb57be15fbed84e56e0431eb0d75cb7592fd85d5a0245d59b4d8b3dfcd0d2a8b8269ad487237f3a33b9c13cfb09293db008f514ec45c8c442bf5cfd06fd30a0b6757e2ca9a89901817330828d87c3112891a9be9ca4e014fc5e2a739e2635d3750b95cc1083b50b230d33dd4ee1efdf2e04a3a5506295815b53bb6f7e68f47ae3bf84968836c0233126790e8459da4a83c182b9829f892b1179fcc6df0338f04403a3558103315a1855676cdcf2d8883ea3fdf5ac7cd33bf129ac22b78e07a9669f723d63a1b13b6502e7868b792db2f2aee1d6286926901b75c0e0239515c1cf960fda4524762dade36f79a1ee91e74fee02b490109f626aefbdf3c28d63a215a6e2a36653eaf7010014d434283cb5c9f0ff31c1ad2976757dd8e7aa7bc46cbaf5ba2a81ddb5c7d0de3aaf3a07cec7313e9cf32eb45af1601b36871484023d9f994bd961525f6897e0f69cb0f9197084cb275d5bd495400ab8218fc8412b8ffda7ab6e7936924fd3447695de37b1895216dd8a6ee42ea851c58e023c841b9b5f10fc73ae3a4ad6dcf9edd0fb6915aa575afdab62c63c57606b3aa507a873dff35f9b7775798aa53d3297a671b0f8f9b9c3fd06bd64c6bfd173dde2aa47f15bb953976f86203709be35dcbb09c9910ca2371a739c602bb924b167e683df4f4a900e0dc0a2761194b543c15f3f969055fad96de495dbc0f79fae9c03e09d4f29814588a009f0d3b81d90c855878f60df58cd916770c743cdd1 +# +# Params = SHAKE256_W16_H16 +# Msg = a84ac56687bde5e2d8382fd88e343a128dcc899a02ce38126675fe2a3bfd6c2ad8adf8d092ed6f7951e042f8fc60a366e191c44f3fd3d77c8dd23505273cbac651a48ff067f90af5d467c4ac525872c4140e82358591a1daf8a7bf6716a6fea003d128ae6cf80a30bc06f6057702f97133de52648641a4f8dde73ca365bdcfc6c4bc3bdec3258b61f23105ebb52ca189c7ba30fc24f0752c66c00331c28e53aa16219a85c90658c615e20ce175028b6fc01dc0aa1ae9d92f5f8fb4212c6e4e0dea138c2cfa3f79495188eda3c2405e66b410c19617e4b5a2651e086b834182a0821b5794a7c417d7084a876fc7618c96172eeb972a5f323a924b6f0530daa8898f9907fcaad6ed374590d38fbc65de46f26bd8aa70bcb59b0119bfac482a1c10b415 +# PrivateKey = 0b00000ba1b3d1c811483c1a6d349425f0a2b6534f0c88957eba643dd847ea0f2d86fd1d8161d0744a5f1f6bbb5912c005ddcf4e2530a97a6a0547d68b911e17a383edca813916dcb79108947bb7c5efa202a28fcd87034bb052603c2791d7eed312ff33938310e6d41cf5b3a29b64e5345c830ff2615c5092eda48eaaf3c406f73771c50000000000004e0723fa96db26ca425671e26422b27bafcc9004e657e0681396e038fef32bbeeea699f6dcd2f2dc3a951bdb2deb46448ab6e0fc7d9030783edab896cd826026c11dd1e582f43a889ccf105ad1153ab352c0f60608851fcdc5ab82a852c12935bbe339cb56cc579a9bf9817a6b35da225ac539d5d39f064467caf05666fe16c72503 +# Signature = 0000000000004e079e1aee316245e70102e45291492a424b7b3a8035308e07a4d19d909564605f9d398e018e44947b7d44635ba29a107de685df933720f434790357d7ac079a4e9918604404ccf65fd87c34cd792de4ab04aee495d77d6c2a357bd4fc40dca6dd2e798821d87c74be626485680a94892d428203838485ff8119ae263b7ba0a59e1718c44c1ff3207e3459fdd8dd28fc205e0f67be732a6b2e1b7e8a884b7184e1618894596c6644399ac4b0771f1ebd6883432e065213d4ec7a9714a4e43745cbd8090c55c8a6b67824f73606d41260c2c50b360259ca16fe0014557778298caf582625adcf5841d6aabec234cd6aeff4470d9df161083c3a6525133213096c6ed201e888f111db5b5dbd2ec03fdad1052dee7247ed3a2dd0a23dfda368a59b030c377147c2ebe886bb19e4e37bf900d934e223afd4d1d646086a1107c8fbc67dcd41b719155b81cf755a100338f8dd958a4003329761845f2dec1e8204f9eee6825ebfbcba623599b12fb204e8a51818a7100ef6d0e98a66af06eb60aa4a8d3a2c70f35927a5663c97fd6af4b59b5c2c272a2f605ae50a63ada231cbbc84704055f5eabb1e4bd59d4de36d6163a938e096dda3126608471e8645f06935c5b06c92df3dc5bc91f43d9325ed00b347f9e0af164e1c259f8efe8b9a05d06c1335b3fae5191a0b6d3e8a47bfbefec6a230f34a3a8ebf0ceb0d5f26b8d5fb97abd56746e2970334c6b302fb934d68c7b5a93c867d470b6ad3219de523c6b793cd81f03b0ffce24d083394e270e3b56e04a40fe8fceb65645acd87153fc61e3fa31ba91ed8196eccd6e843d20e0b898d753dcf5c99bf29b4e7244b0ba20cc98fd60d32aed7d12bd00ac785abc9cb5d37aa6bd9c7a5611484fb61fce5250bf273d95985ce6cb83f213c3146624b55ded85801b81adfb1ec4874b6b7fcfc92fce370dfadab57e39dc03b191e4e36f2b3b23776bd517571a1a0b75b8ed60406b8853659cfcbc2c49e20548438f3de8b2756ebc53160c978ff1189a669e306220c17388eafc13c85b47e6459e583f0851c0ca6a9a281acb4b3d959299aee82e62e47edbb28c73d3e27d1863f5e5a9c1f3d4c5544a1578bcd5d994b29ccab2d01f361523e91eb330029f34ffeb19746e6499dd69c8720e5cb96ebd220623a1a546f4f1bb54db0add751c6fa65ac31620c7490c05a3ffa1a032fb93b845efc4f7a2d7c460d9183c39264c2dfb251ed672c7ca6cc947ec21c692ff21c05686c307ea98b76e721457ea0bc386cf6600511a0a9be465318ed2dd304f869624faec0d7380a4b398b1b0be518922cb932a8f6b3a8f87b287c852c02f820a2f589325820d82a794daf339bd9aa2097138e6291dec4e01c7c3da17753cb96d08f31cc48fddcb69063497547de0f22909d59ab405cd0d67ca0f55a69611edaca3e2056f996c14c41ab97fb6e87e1f523d5a58f5a7d6050fbd2df6055a781a1f9e6a0fd821e64e4210546013303399f868493fa0a33e2317e8e58563912d6a546b978961d93a553ed44637e3def482d961aacc43c12f94a4601d25021eacaf3730befb4ead26853fb051b8fd1c6f4cf61a5564a7cc1f4b666cf7d5734e95e5fb602bd7d506cbe9c6fd27b720b56fb03aff94d674dd24689bc8b28271df2f40c5197f35396b150ee157e9eb4caf0a905ad2c4b9ad17e0c64dd90596324fb84b69b6aa9e62dba1968ef296a820d665a4a19ecc53a1c9642761ad5223c4cc490bcc20010333f6dfeaa403b9825d1ca928e1c5472adccc308695b6ad452e01cf9fe565370525b067b9db568ca65fe0ff751b01b7e974829e9dc7631b7449bdf66d015dc43b3d09df24499e193f1f2b94ddd2e35a92481ec7171b60cb359cad1c38f943dcf850be4ba5a415954d9b9efc907f68042a7d2015b4a300d206455026db69097b6e5e986fd4f6348f1017519bfdfe1c06cc6a488f7ef93350125a73d0b4d0a6a85ce5f362173c3dcc7608abb88f79efb695472fa3ab3d8a06f523a73a43b3b1dd64c6df09659480c272789abcabd04f52998d485100541e5587c70d1ec060a51e7382b13fe1f891689960dfaf2c4cdbadc2d4e7ed588d083ba70906d5cdb5ec3bb725038479cf44c833ab78f4b2745def77e46516ca01e40ef074e2531c65698da338192b290f8e12505e8799632796d443d06023d86ddd5a98cc3a52ae46964bda6a75c78b35ae5636e6fbf41560a26b6a0c64ab3c9a66f11f928162526222315099b54109f75b1376b83b457b0263e961388318bcdc39e6f9b6f83db465965776293b3c4409064518a26f9ccbd08ee288663f74229bf6eb35cddc0e97f5a3405e0ac617f8621de6d95899f0339f962452b3494f55f8165f8bca28d65782f793dcc30d0971ad629e1ffff96204147178210cccf60f0c9615c7b1c9c894705623a76e9aa5c477753a625b2b705a473ef67d9af6fce57ad78e582bfcc0d0fa019441a77f5ff0dae520dfc40ca91c200e16034a7bf12a31ea65d2a72ccd78595f4873b414035d3ce43c440bb7caf5f6bfbcf7df55b18c5cb859f17c43a1f18e2a8ac5a798fd4f11f8fb89b439010f9372e613902a602046a2b646046bebd1688625d2c6f739f4a13d98236ae9c5fca1fb085c4b78f544ed1aabe6ebfae97759360bf0db2eb095313b041bec3ada471169bd75dbf1bfbe655afdbaee8966280bfe116389651ab6c7a0c2762d5b47a9c057e4f257191b2e232f1fa05e16c97046b6ddfd3f9729aaa7874daff9fce0f23f3d6b44ec159db2112af06f3af7048aaab1622ead2edaca68c62d4c8def48c79c505aef3363c8a6f69d9382f76c6c972225aa51e7d5221776810842de33a032ecbeeee75017705ead8a5a4617f4a934099959fc5a043ddbda7fbb7138a7f9904514d7f7b5c6cb0164e5aed6ecae37a996dac2e6fcd3c36cd457470b0f605e5c0b6b60d52e6f3955b6cf21ee2e6eb43f2e8fc1ef371ba8853e31ec2411fb9fb4a076b3d528845265d0540549600109ed7a4c9f749b75c82e4520ffa82aba81ac2c0546db8c13473f94df00112873d4080b5652daf356bd213b906e59ea3d3a2512f9ef9ae0a26a92be8070d4c681e43ef21deef4d132e6eb1b970d77f98dd7d4de809dbd60a83d20b638f744eaac4868b50d8ab6c63f01e96f9b5a2b45a3dec6fdfb5bc7195c9f7f5e7bb9d73f664ed4a73a82e9ed9261fad07a219a3133279d20a0b86d63cb9594893502ff1bd2271e068079bd3b597dc77f35ceeccdc8d7979c18b03421f3607b62a58e15a1bb0cc43c2abb3cb677d141d43aefaf668bb23f4dc727abc43e2c032258a940fd03dedb99da5a7ea09f43a8b15db8da7e8279d924fe86f763c14f7a7ffe7d29c922e652bf940d79eaf2514e7121ec6855f0ea04d578f641b0910871ad9135f59d799534ada449c8e342586fad7398768593074b97686e7cd5f984303ba396d5c32000b1daae6491dd86a5b29d78a76658a496ed11eb6ed870b81a6782a5c926e7742566a8ebfec2c967a466b8153d24c60f4e3c7d13e4779f26596b27e24b4198ce2d352c0dfcbb6ff36205b5cd81a29dd89f954370f9cd7240526895f35ade225eedac9db322ad360c309c7885faff40a65f0fa6a32252a4c0110ce72158cf7603af499a260e1649fd141868ed0451851a90864ce14b3ec92066bf8f44aac002d594bea5a37ee68352e184570593ac3de4a11982f2bf7fd8b1719410098b369b4d9f23609ac274449533fa32145bdd435c9750da22abc79eb36bb617ac1cecae3466529ac6e1524ac5f4166cacf2741c02402a0336cf7a2280f54dc6612aa9b15cc807e1cc0affeadc2dd4363e6e67b7fa568cfebe2d61df4501681422797befd50a13561bc9a4c501de922d557f22fefebca109d63d7799463cff5771fdb2688c6951b10d4e4adaa400696d82bba273caf7248112989f78fd04851b020e0a317acb3bcf766d5c7d95bd464cde7572e6a1b978f382c8dfb8790e1c27e01e4db23535d8918901f194b43f822fa4fdf358adfca8e8143a7707850114a1f937571535eaa7069c2bddd80397f2be8ea4049e4079056f6f20011fc5da03766ef98563e5f8419fba32f228b387bbb89edd8076bb3eea1e19a91761dd925e3dadc60b16f02da9ce84756ff34b8e5d483d8ceb476d0b2ef07e1f05578619ef78a576e61eb2ad557aa7943b03546a276f27f8bf0fa30978a0c05d0a852b90ea6d17502d4dd052deed97a9ca47c9bd7a987a25427d75ea6634dd2c5394b2113c2bc2373a57f5ca49339999d19817377b854a935c9ab53f3af8a07bc2091cc74ac60096d3259fbc04a68d3bcb903d1a2237f0398596858d22de07f8fb84192e796694d90127c3353150c059d8334f1ed5fd49cd11c05200735d0e6fd3949e24f2119aad25b2a11922a36e6a29a6f844e2bbee9917cc45947a92610eb19cd41605dc46c667a871735f67d26fbe7c6f670254888332fdce19b10754a249f7c386da9628d9d4256241be1c7308487d8aca85ba93e6ecb7f7a7cb9d77d1d11906915f83354fe89c794a02b6f32f6f7561c60f29cab1a622472321a5962890cf5783b9ab60ff0058359bdcdbc268be76af5eebd5fdc8a096635e5f24d5e4b4cdc263e90a1c3f391d80376f5b63a4d3453096f762a7d1d589455f959fc75f37ae18d6ea24b93b0d1f24efb394762ac3559a86a858ac45c5ef9adbd3b9eba5610fe6dad440a0ab201f61bc4b8b8eb253c8859057ea1943f82576174dcf33c2ea54b6c785805e78208f7853a926586d8f6afbc81bf4a89ef36ee44f3c6de2bb776abae356ece87566d51ed249c02eb76cd9c83b4d122c3dff4ff45262276514cc44a187637cae66f20e5e17ced86e70393eff3352902298a1caa4674880dd299cbf6badc5c9fcb7c73858bd8cfce81bc3a1b13d92ad701ccd61be88c6559d8427ff07551482f25d8ef13493f35f54d40f3a61673bea6c505e4652fe888d57cfc43f88e9c7f8c38344e551a9b102e07bba8b1adfd15b77f976ef5d0fd321416b5204a90add8b397f891ec9f7ba324609f6c151e463a13cd7913d14be5560e8d4c52d8d1225d6cbc329d1763fb1c26cd6ceb548ca7bf21c55276024c0f7a1aaa012005abf91b9bfc591bb022073600b247600b6f4950f92b5ba11cba432d392fe7eec151d938e6bd5e77da32e9ea77debc3019aa98369fff62b629ca87c3b3bff4e3882f167669085af3495c198fba39f8467c8f4fa0f72e403458d93976e3ca05d2a02501fc3b6c8f431deba36e2b91943a5d3826b4c7b60de894db8b70f43ed562d3632ab4f8e22797df220ced93e4a1b735f36eaa0eca6c26318a2c7c8cef120f22a81cceeeb8f110dc64367d08c7ff77a98775e26a45caabadfc0af37fa9b9f5a05fe6006110fdbf361f729ba47aa98a174d82fc02bd59e93e0e3b6b97743b448bb521830c9123d2ee7bde2ed5f3b5e4ff3d82062402bcb3528123d85a29099f31d895072e2225a5ff56f784a4a0248c716c44c216da8192da4dc6d39c2146b88fe8b0a14c4c5f377ea32186a4dc0d4b08a6be648dd8d5862f852bc628518050180d636df9f5d3bdedbce966e992047ed4634f15f36fd4d022f7a36633d4d9fcccdba8875e0a9892bbac28c682d46a70c5565e5bbc401b31c3cb26817fd824df1b291eae2f4ffb31b7c8125bf40bb2e3cf7ea89c93e2cc41031bd4cc843c6b40b9c6977cec941d1db09128f9a2e3a4c455bb87c3c3d1934c3781cdf16cc1c6958ff9b929020b8255cda121c9c2a9d98cdcd5dadb90a60290466435d3f2f6936c54cdd044465bfbf6fd86868d18238d0f3b31a8df94d7cf77efcd7c4e9480bf0d0a18e400db299390f0aea1f65c244ae599261040359294d54df213a1b28a7d989f1c8ce262111093607bbd1df9f650e9eb47824ec6030bc696db32b7c7af6c7bdb77206ab989d911e88eab04f4aebcf467f74adbfec7e3c3f80ab971408de17ec8995583b68a28a90fb10fdc018e7b7e52bde460815c2029a083d58c903134ef1bc4e8eb3cb98bc516bda4b227adcd2d912ee7368bde81e4cdec05e426c18955a38368fa2638bb89e6e33e269405055a6557e56bcbc3f632fdccaed721321c2b7f5729c6b6d755a12584899a542fa9b2940e30932102a0ffa31b45a51febb9a040c375678e4d7f726c10800cafd7cc3ad6c1abf9140acd1f940e616ef2bb772893e5fae04e86f58c7c01bffd63f50441d35a73585b8b2896c5851b7b071cf674e343016984681565b9f125bb848f8c8ae53510e3e1a80a335a9fa549df6dc845813224194f8c1abb2337e3e6f8d3fd3b633f358d1f48a16c7bad0fc943c1af152d9c3361c9373ba39d6b9720803158d28e2d83a27d3e2d9cd3570ba3d3b9b4ab5fa28be38b8d0c41b1cfcbd78220c943b23f676246ced0debc1abeb379b3adc33929f3f2a36a9bc9e0f60391d80554801a6cdf34c619f2a280020047fd162fa4818c107eafb4fe14c80ae3930781ab0db97db0808f0b0006a0aa6cf32d6561e65d299ae13a50e37e39e0f08b2f53c68adb953430827530db9d9bd5fbbc549937ea517d5d07ae147f6fabcfc6945fa3f3178ebf2f8b7fc5f03a98c53665da97fedee688ce906f00bed244aa5033fb85b9c8fa03ac473fa1daa47a89c317f29272dc40d94e63c6f4069d6eb5e20fee01b9098b497d20f51877e02316909089078d35bf27ef489ad6a87d05651030f4a6b5246a8d7a5bc09021ffd7a73bf7e37afd348abb6f771b02522ff418d10f9fbe18dfcef285b9305359ff0cefcb0c91fde6e1b27cc8b74e2f5976b4ebb0627e275b552b099f59f64bc6cc794cabe697dcc585bb8c7996232574d788daf3df86505fccb653534cb50217b64a53f2f1c17b691e2d12c3a80eba1a20630b7db80134ea7fbf6a83beac3b67d8303266263b305a71f835116bd8f9b37e073b41716da53ae47153f71a6c10aa0875aeb3caf4391ca34af288e3dfb1c9416bececf52e5ad87c296ddc9873dbbfbd2c43ed0bcd3ea068b430911d3bc2241be1c723234dce6402f07bdc8c3b82420d4d9002ea8548600f20c18a27fdbf04ab419c049a04eca20a3c99032691ea789c583d773c7c3bb6e92fb9e22b7c67619e8c581647d0f4a744474cb013b05b3746547e0d6925561686800d6f68a1082c5a6209cde0aba86d4808980231b00fa6b6135d69394d7921299e85dfaa8555259048f24bd435a0b0bbb837bfbab33492f609fde61ae1ff03881c4ce42701e3b996ba66d01fc0dbdecf272283a89f7ab49c65036b73f787837e1b126987d3fbbb029d9f018827dc1303d8a630da5de97e7ffbde07d295d717227c5b6a46912d4f9abb7b2caf17b78a72d377db750cd227a70455d8ac3b6b57f124cc34581ec75cd480d0548585d4423bf716af1965e721b121aa2d7cb9f519183b11a03d2029c6fb4ac6aef9cd94a115693c23a1c8f89914ecda477abf9b9404a82a747313a446017eb9506e9873a948ea27af8b40ba40f71ad5c6b6c9465c93f977478c2e0f905d717728ff195347888d1fdf0ad070040e27c3a16f4f8612edeab73b6e43bc3f46c12f491391e708223c677f5b0048eb3b844f31ed46ef60e8e3689fc1f947a4c2db799d6e86846ff4b080ce221091d0579f87e3c34e3f6c2e3307376bdf472ef76f09c07bfd73c42554de7ba281af0a5d138dc8c13f0e7cd935bcdf91a57597cb5f119cc31c960b25c9c2c7f9f9476359be88d8fa7ba66d5bbafbf09a23e3b8072a37a8f33a6bdcb55f5fa7e790c838aa9877c5fee23f4988e1b2cd6bcb631ffb437b8df73cd92f1bc4856a9755ef66aed6c0f78311d16f9d4db1837cc3664e0648a2b2aa92fd0912864130997614decc409615c68ea836327ebdc853daabddec1d274a2cfc05f4926fe96cc46eb38e9348ed88225942fd6d9ef2408ab928f1edc29b7cc37d61589625c26c4f0b946e7b000cbe3d5933435fba1fb4ef1832253743c693853e0fd632aebfa8f21cfb70cd370e9a6f98768ac0d1fb14837e4e9701e4299844258b094689c5fef4d5f43cb96c0db998b04091ae8985af012fbcaee0b3a7650a0866585af7be4649c8202712d3cc9cb09be6bafb6873f5a8895908fbdd5d7a01f407c9d8c2e6865dd906f503b950fec21d04d097d117dd26926bb4fbbd5052a25e878d58366dcfb220d5f9439657b6836a75bce256f74fb1dd6d793b3e9684d1ffa6c67da7decb2f12bef96fd2d20e28c528eda495a407ac0b75736cfb421f9db9e369d2c4c537c510b7b1bddec5329fc8dfb0156c0dcac01bc34e117855c7fbd243abb1efa698e99561d9c5114f6d3aa3a530fdd0c9c1d1b7085c6780962cec216fcd6d578e60055b4025b30b548904faa6e5ad0b877143f29d9e5f3a5f4f655519439eb79f9b595654f6db8a25b526383267708b7b6e623495d933be33e5fde3875007bd2552690308b3e1911d058711158730b04347fca05ccdafeb079a66c2a6754c45244ec7639db425323096fe5ab03fe2354500c5fe30610832696f489790c3ab4c15ce6b03eb0d18a02b91d6d306c6096b4ce74c2156d50db8709b9e30474faefc0684f98b88ac4e565ce4de1cc9d3c37c6fd5d8798a7b41268ce55f3b254f9093ad6edbae41648be12cb7d17ef43931219bd9f4b86ba9234ee654fdf378ace32bf5672d46f9d42c95dd9474a595865c74ce56dd7d6f95690c10908e580c1313a871cc75c130ca539f28161b60e2e295368d2dd80ead1fa84942287fbf65e4573769f316144e60ff6600e03f8eb453fd952145b62584389d66d78f791a8de3e41b520f6a9eba13d59a6f8b1f194d486cbbf42b62ea7294465197c8a101b6e2db05107774f36c7c7524469dff2e841afd9c9bead0338fc902998eead56293616b20e0e353fd5a2fcffdb00ca58ccebb9a75812627d511a217d3a3bf0a86dd5bcc23a0b4dfb887e01d87e05e8721c2ead650131d37d5566d41bc1ec016ea8a78187ae0b9fdfeab903cdddff2dbe4cff33094b02591ae20bb35caefc570380b8586ffbce98803ef372ff5a2357212513f482c7e516504c355fdf296c60022bd9af2eb4624d0bfd4dcd74db66090cd001fdc10e0e26fdf98bea58890e0df8107bf31d3a96ccf6bb126009e9c93feda0ac8986e4c2b966d663a998d7be2d19026ba4841054a315b7adf1762199ed85751ab3aaabc5d1150de52519ad89d3f551ff1c65c3283682950c121efa83a2b0deaa7f362b74aa6bcea9d608b9b36260711237b3ff253a7289b2eee3d8e8ca3e2fe45c145988c95cac22f52d290bf7c8a4662623c144cf3504a7091d97872ac0b6905a9eb67708a2a64568c04a558b8cca5a955899ce8e07f5f59acb4fefcf727e033e5c231d18fbc487d56ed1c38b2065d5eb1dada61d54ff56d567c28c36fa247896f90e4f97c5ea99f815d4f57eb8d723faa467d526cb837c7dcba59a5fdd9a5544c27b72341d2c519d2ef9e4b2795fde1bd368a371e948f6809910623aa8b89a009ed0853990c0e2f7fec9f70575a7a0417ee0077c170b174965844bd101961cb44db1c2ce5de2e9e33337c945304eb861d26bcd9c2d2f9640f25a19ca20789cf41d9d82bda2b40e79d72fd6cfefb45ea002de6a6d7cf42b4e898b5f9edbf19341e078ac725a1141dd0ec993435e4f07da0d6970b44ebd38b9e2e4efa2226d0e56414df6ce8e45eacf792b8f519a623dd7a70dde741e784ce854935a0c0a0135ff02ed414b9538027068c46ce51dfc4adaf3a2923ecc6d93aaf8144394319afdbd38ee2ba4b3ca7c1bbb4282cdefac2a91cb7b04aaf1e44cfb2849b2b3df3aa5fc3ed896f03e7040f2c9dd1bd343c071e99b9de4750fce2b366c7ca8b3706d77c72311674be44bff52e356a49999e7bbb53f05748e8a241c0cfec5e1b1908561eb873400fbf2b3c0af8c993fc4c09b31d77f08c431f3d6390249f9a03043180e75c69a182fb776dc00e3312c3adb6a7be4e8972f9d1282f41577a7d034405abf4466ab1ec1a806828795033d45c565d37b8c0de83c9045d81f8afbc69e7a4b684b7d639c62435a65c3da134fe995cede73c1588772cb709be01c1d6252ba2824f60062c3a9efcd60ac95c0608b567483bc8073b539323781ec30b2c958892378680d5506a02036d2dd49ebeca7d261bb9bc1b8e3f91a602b938c3aac5794bc531a8528b0bd17c32fb674ea5439b9d0a6dcbbdf9db44b87196be5a2dcf1a2ca8bc5e646265738bd48f950c9b3777f017cd836e32686f45dd1cb0d663b65ef3f59e2656016bcbe1477d15e04b5db5b820deedfdc65a1430b5370b1d6febe770353dec556b4e2486752c98ee85f8bec880408d7119d1b437a08e5da9fce2298e04f8ee7f3b749a868163e553d31b811471d77f2aa08a902f96eaffae974db1c131279645838470647d60501459962b4dc9ea9811decef2bf66a9937fd2d3798851a923d854cc4cfe1fef3522ffb26dfa610e5ed93cb35b304ebd42d4b379d12d0333aed7a7233fc412785c610cb93be73a3877fc72bf3493b3239bc402b9714a8eacad65c8f2417ec59722b6abaf7004503662b4bd8c0d223c6ceeb7769948b553b2ea023ff15289066004057fc0f7ba1be0f686a8fb1d87e19465e5b6c9ceb30a741dace7fb3e40c39e0db200c877b7987e6140c6e046b0fd3956153c33a4558b75e728b03f4f1ab29113a11c2ad72f2b6c318bde3166ff7041eeb5d188cf6b787de49954d337794f0dacbd2f216d9953094ecde23ff71b343f3f642ca7f85ad172aabb1f253850e171108934baa4c30e7e08d083d549f7f2d6f9fe458f72947bf7014743798fc020c59a67a9ba00e56a5cb2c52289c5a3ef2908d1cab8c782b8715785142621d2199f599fdcb025300cf4456297dc9221de3af322c01f2ed6798ad12f62ded822e2adbddbcfdc9c138a72ac8cc9997d079043cd80d23f45c2b72d42a3cb13fdec990f675269ccc9038b394ce736eb926f2af255ab556bedf2d5f54e48dc0775e54c8e13a56cd72a02accfcdbb988f6a9792439100ab0fdac8f50a61f901ec43cfa2e6a55ccec5287d7bfb0b3d76812e1cf877185f82461a6e48cd190bc7e3cfb44efa5e593f132f1468ff7e0cc236c35c2c81837b8d9e9cdeadea34736081edf35af77b7ded139d0f9665726e39993d3bd7268075389580033c7d291f1de33be53e033109820427141495ba3315b854f814e492ffaf95b827db58891d31b02105e7e0d8db7cab63218655829800324af354372be1dc04ca359d3b8908360f5806d4da8f86172da7a366f7e2934b1e166d3642ab779018684ce1511d0aa3278f2260cb78936c3bb228639c6ab84d038867a3441d070c0b9ca525a8ffe112ba48a125960efbdd8bb07db48bafad43a7f12fd814bb8c3d6124077b316aeeafb6963b710079dc367a4a60fbe54f29975ce78fba94fd9fa249a6f603b1ed57d5ebcf1468c383d08e94ba98f2f6e303fd2280b82947938c3242b23710fe9b944a0c437806974ccdf7ff01785b95006258406affd5437df789da70dae49ebc58ce80ecaf73649fd9793a4735bd20d26add2a49579b644f82f1ed8e70d32495cdc30584d3a03b7c698ae27a0056c30dff888ba135178aaba241085e2bf31b4bbcf4e53bfe4dcc1d5da234f51a6798ad6599fcb341a7f6b11fb4e353d8cb3b9e5febbc6107b090d19a2681cf7f45d4ea560dfea7f723ab4d4b2869b654321720bbd59798c20477b352145dbafcb901d7ea65ba3a936763b0440ff708531ca93e0c0b195f2bd8027b5746edc0d1f4a8466d64afc01330baa1a1f17e09d5e8b62bc413452524cea5cc1cc1f3cfc90823df5a8111666b50f2b1007871fb284e86e267460930ed5d38bc96afde1b3ee2830a05aa55e78cd7b02042ad8f95fa70b273a27bd496c310d9a9605c81a9236d11a51aeed4ba8a964237796133f8f1f40f3001e2b53bdb73bed87ba01d3251b401bacdf397aa5e91d52a603184709d5f89dfc38d938a6a9e8b0632d03d9c52e9aea221425d973bfea6fedfe29d5eac76a4a37d9217e02b0c4ed730b0b5a778cb5ee22b7780a7fcd05f70d76fb8471d67e4bf3ad18c3791efa87be879ade453881a6944ef9ea9fae22c4a45710fcf8b01237b297589636da181b0509c1c5dd3a17340461c83693c7c8f2072bbb283dfca95af4373d6bf316efb6ee3fa023ecf05264c592851eee9c1053bba506c13c30c588063242feb34a79f18c4d243fce0a0344dcc97cb5a9fba6a10179aa858f6641df50279f7c8c6449e6e346374885ca70e285ea35a6ad973e2c7cf0757d86054262d84d92380cffbd28baa9ea96d34ad5be6d70fddd27b9cc1c5d9daa8a3e4d1fa7d62bdc201c62d028e58d7e07614330cc9f07e4572bbdf353c5a8840647a2d7fac10559e5724199af12fb899a79c7b81c9e75bdf80426362643ea4208400a1c8841477f8491b142d8e5efd60286f1b32f5aa969fc8e015f83b632c1f75a51231597ac532771b97f88b038d998f76a8da41f111d9470522ea56f3e43d7108464d53d04f032afda8e78df5112a2aaba20702a9fe9cbbe96843fcda11f127adfe04d44c3ef49a22a394d0e929894d70740676bc7def72605cbd4d52a5fe530b348443e0e1c920cb22b402b6d4b6e349faf15572eb6db2464fe9c29574bcaa03d5c5cc5ae0cf58808374fd67dee9ed4ad3c5d286b81b76a03f4c61524af2579c36186b232d99c39b25ee077cdb55fe4841ee2c346f03209754b48db237f83bb94eb8ebcaf415666d95918c362dae823dc28b513acce1908fb98adae83fe5803fbbd9f32fe6c4103bb5454d96c276767bd9477b6561a3876cbbd9edd138f8b436afb2197298c63da6ed7b6b899d9b155677afbf8ae28810ee5b3db0acd17d07440ff27d886d2af09905ee3b28099b33b91a34221543e764e912e5931d36af7205b954b3e0d5c5a48ff46169b88cfae129d6c2f3ce72e9315ad809ecb283a46307224fe059c338c47ead6127d478f27b97b4e4039415c13b0e595f70979a900f204fda16bfd920b2ca47a8e6d9a8a7d2b9564f02d7ae258e70067f8802a121b231f28d2b67ce7a74d2fbbd923c8f4c065b323944497326014f29eaaf0bb8f2f05195dd2ae294033dda09775c9951eeff5523dd9952edcca5c912c0cd122c95ccdea47e1845734cdbbeb1a1a1acb722edc6ef594e3e387000b728a93a5829ebbd870344d3b0db439954bc24e7bac7c03b5b77661ad27306339a0cbce98cd9488c5ddbe4f0f5e1f9c62788228c56873924dc4a591fcae3d9367d7baa1bed1cb8bf171c48c3f0478bf99ed0ccc465ffca2d20f58932eb150b8af1c2a641348484871246536e5429e2e4a5ee5e5077b551684c0c8b30be68fd2331d7e7 +# +# Params = SHAKE256_W16_H20 +# Msg = +# PrivateKey = 0c00000ccb3d052e7469df40eb34dc2e168d4a475f9c8c74290eba1027fa06e51651541f1a785f946f8814fc03c3b7a8c5768fce5765b07e88dcb87032deecd2427597a7c8bd7c9f265da396a752c9ad95fed5406002db54e13ab0712d236a901a7e51a4f39ba335597ecd4a6230636a9199eb750b58c6898ccda9c92a25d98c5f9ece00000000000002fed0e50bb9360f841b7d7f1453d0c31142501fe08bf8899851aa0370a29d5b5589f505b7d1d1acebfe5a800a5bdda8172433b5ed25f81e8efb7b162ebdd60986bd2f1dd44d045b66a7872e90e6109ddffe0e98dd15d25f99e948c522748fcd23734987d3be62e383e416b44cc352c08c6e26e65cdef46d55f1caacc0c7ff493de3da +# Signature = 000000000002fed0dce9bf7c5939707fe23d157338ff42898e0b284cf0bda5ce0fc9f32a74dc8f2a690ef1027d449cbb85901f922aa71c79b897da00ec227120ce6b40e9d05f4ed0febc37f95e5156ed1c2555f8b75daff7caf87a90bfc9953dd8eac8610be473afcbc5e42a14dbb6f7e1cf2edfb50b2b2bd617c4291cad0ce03268ed14a19ded4272ea4db5a0915086bc95a14a8074689e9742a3e3a5c101c32ec78a2ba7438eafe8e0b3907987e57c1916e736236741e3adf2606d6ef4868e741b966ca84c95761504bd0145de589bb8471609d0cc04e2f95ed79719a0597ad302043815f0b302c372d651875363ee502703b500f0fca8e1b64ab85349fa2726746593917ae0bea7e017932e5936695c944c8e913b3ac11f59319b084ece00c386c5f0429c47fbd8937c70d6b1b0af618811fb4fa5158e2be6266ad0ddf8eee1cf5527943363d47302ecf15ef0d5fa7874feda68d33d1afc30bb574ca97a603dba43aa6a0dd79859da1afe75795bfe13708da8de7b98637e0b35c2e9b2d43a3b4fe739bbd15e24c0be1e638f16945469bad8dcd6df4aba48e78d6cd23fdedb09a05fad5a6e45c3cc47897f86243cce5beb7db9cf99c156d371657fc15eb48d320bc78515f55bf8e38b9d71b09dfa6958edae7951cd1ac28f46d7166e289cfe6571f03ec0f83d999d26a2d4099279c9855d71992fda2cb6f0867883abf465a2fb3e592a34377e204aded50cbd3a96331c0638b7c76e02b86491c70c9ebddc40e0ad4309c2246f872afbcc0a32f77b0d241e282025f68c8113a8320aede3e74e144d2683b0ab8bd384e8e019e3fd3b76a374cecdac3417b8a2d52941984cd45550b0829f041e78cce000b7e2ae8c0d8e1811d7c2575c70306cb1ecea3b4312a6d716636e800e75ab8bf76aa7f7dc14cb64af2dd043a18ba938eda609db9978c53278d59f3d7d143eed9b38176e97e1eb74b22f64a3f99864ff9c0a9a0109ed2bd753766254f2339a6b1dfa100b76bca2ce7de085956583906d84dfb50e50d06625df224ceb3e7aaf3aa7b3c7c18e0c6f0efabd56c4707b344061f93c8656c34ea38da8b298aac9c2e9b6b87cb0fbc3bddf8de2687d94f17e09a491c7e469dc390cfb8bb4d362d1b84dd36476167b5836cb128d4294aae456d00919b9790c39b7981cc9e108fa2e528f467f9797ca167e8925ca2833cd46b47ce24f930718d166fb931a05961d879c4e7e3e5b88449444b5ea465c887eb89520ab592697dd60a58c2d35612f0fb10d4436feb861b4bfa194ddcbf227504fd7db971dc80419badef7eccb7b8112e97d40206295d1dc88939ba557241635843eff8fe098617855b2e8e23a98b61732e56f3bce8969f5b35838a5e2c7442fefa27920431fef177c312855bbbf16cd9da3a53bb0da99773a961c7c1509bb4ed01b0e6d4dac7d2af1a3c441c12720ca100b6aa5d0d2a3744587eb50b3a78c38797b80a21bd3906264a3bd34a97c5260ad97605e663dac55cbcd3d64403ebec321e14a6f5d8348a296a68e8b08aacff0e09a60e8861b8f1e6df2d21215b9624571b6538505bdbc893dc01fca013e8f76d8408dc005571726c5b4f2519af6a47ae18ee02036f075b3e88d84e2176bb6cc88f6e306c9004eca6ea0cceac1abe77c1d49e66e599f89560f00d38f5c602035bd4c42225923a36d903f007141b1bc906cff6dab8306689e50e9d27420173f11868bf535e38844ef263ca9cbe97c659b44427f144e4dcef1cfe874d5a3bc346393b5f98a63a4164780eee42e3ea965a278be81b817500a4b1c9bfff3d772bcf2c010b16c4ad66a345434af621f488e68dd859d2826baaf5f3d36c49d5649eeb2386c6ba70cc97e4b5cd9f19e37ae81f6f7ecde08731bd4c89fb219822302d739747c6f313e4bf99fefad97661b9006907f6efd1971d39f061600370630faa53e19a7f2fda402787da7561fbd06cb2403495f751f1b69594f063a2661c4d664f6fd664e2e97ab314b4420d6f3d6fd3603a57b11cb8eddaf52b4be09f895ff462e088bd451c284738d7f3c88a064cf660d0ea278f7753939edf30e521ebc709c01fad53fc93a6d94a10b2c22e5b7c9002844fe08eac67848b347e1d9df0f856bc9a01263ade9c7ac35f68a0e3dc241bc14df34969d510468e5241ae16ab12824286f1d36a87653330e060612528097302940b3819e7075c890af0e6b16ab91784bcdf5761c36b0c2e1f7082ec16b5151468446e253693d46d89b1a341c9ed7e282a89a3f589ab2a420369622bd26fb38fc216073f4b4893108fa85736ccfa4fb735da69f6d951487f651344740d4d607c7243651ca034f30731dbf20025f4833f1c3100aba0921fc627aedb2c1ea6c61861c20ac2ffe1aedc72038e11868de9ac3793f336e9f0795e0b2521520eb17e9d84e1a78c7f8923b4e1dd4e3b103663ff9ab283ef704e82fa1c827b58646fcaeaf0b015cd521f9dd4f96a39600f27de997f53e7e74e7d3c990e246916efc00bf325aa59a0e0ccfb328f3e846ee0c71c3c900041a2ee967c7b7c5a0203695d8069cc193c7e1020d1029db8ca2ede1772015a8da368a5b5135cfc2d2da9a13dc29344c7c808e7cc8f38871dddb8bd5a1f218f3aad6fe499f383914c2126732a1f23f390a79f2e6a84c9ec9ccbcb01f014c9f0e11791ef6be79b8fa8472027677a0ce5e9d0fdb6f928f94c1c18ebf71e7c20c953419ee9b8ac4d2e6d376491ab372f61b0e6f2cd7548d81cca0854a5243f0d23a29ae4cd5abc1cf42f788b9ffaaa427b6886c23fa107bbb8bb9e51fa0705fbb69c98aac98b2066c312ea26e17f8e127f45a2dabe569a6582afa1a040d8d2509c1c4f8d6f37c00a936fb3f0838387f2c0d849dce74de474de5553018c8d9c6781954c14e52826db8a4cde9a6ccffbbb7436d7ac7e78d36ef9747edd9587f308cd4fa4accb0d25f7ec916b4d49b29da1a8864bf9f491e2ba36ea7a45e878b58545a7b0e1ab5308075d799fbfa991c4acfe869ef4ff2fbb00ac8a6b028d19afca281824f4fdb0105afe428603f5a4999e79e599503588709f166c11f56c32aa36e47305325c528436102eef8c67e57b2f9799531994f7eec7a7355d24bba4c2411dae4a3220b07603c7e62fbe248f4897cc484da41f6e833ac6501bff9b94499c0b883071ae0751661d832cf543f333924aebdd9ead479a7cab76b8a27e14248c8afdf353f0371e65e95626cf20e30e313148fd9fb3af4a04c2a17bec809e8b6e56a979053cae30a70e9b5d1ec2b4094e9024deea20bab5ddf328663edf776de75161d2c24e992436b2a324a4d956e9d613cf34141217ceb2851ef1be8adab8160b9bcfe28a06a42d1403c4eea1643950d7eda8284f4973a355c0c2247d4a0280ae72efcc6410ab286b29e7f7136f14fc17486c27320eead362de3d3114042be587c9f428d82fa66ecfafde9a1ed33498759b206ade9f106545c191ef1086524a9617b371f38068f5235f42e8debf4262626999574a92f0e55f18c9e84fa16820cd8cd48c638d4775c050bf9d95ea41b0c07ed4703d4bc33520b9d6a8cc42b5cd9c1400cb07c958b5aae2d76f8ab64ffe19e21829f41c6c71a9bf6a5245b7a96577a785488446ba8f0a66a80ae2ae8a0e63594a72873e9ce4b00f4bf8196ab01cfef7560673b1c591cc2c64cfb1fbc083ee10845e281ad83c9fbe0633cfe39c4923232ffcacc874b5fb3d75ea42671f290ad019a0964808a03b5938d96cbbd505b6a0aeb04bf507ee3894a251dd4aec430834a2eb4b589fc986a3439845157fda93b2d8314c5bb18747372a48af77cff171aa4df60c603b7fe0f6992f7c91ab518f1c26b661757f9126deaeb68316b3e4de097d42c592cdf79c69f247db55e909d0280f59ef0153c4255dbb51eff4fb2f722c7415858c21c4309c54df8cc09abcdfface5cd27aead79c46167f814907eb1c853e9c9905a7a7b99a69eda03863c8e2f2c71507dbbb69584d51b72b668dc57ad5983e8795ead0cfa2ca16c9b037a07f079d09739a2a86d59a786156cf8e2341964899dcce4535322b2f817c7a304aab41fd27c834ecc6835a3dd21d024e7345339875bd3d396cc09cfa7e413fff97afb40c119ffe546026821fc0b217b78793f722bbecd2134f560597a114ad004a8366245e081d649b37b27c621f0c03e66ceb80727683bd479a8c672b514c63d89a7028961a12520b084d091712c1e14672a9e61fc93874aaf36de54b30c3cb42a30df7df4d213afa30e89f773d434ef2d9f4b5fc613058c82bf3c51c5b7bea14198a27cd4ea18d0f8c1453fbe55e7eaa3e15965cba696ca92368041bdb95296975cc4e2e2844358fe20e513a3357363330854f2b3904d9492abc4f9717496d711dca06e55c9ff1c543613e445a503d126fa029bdbc947a753e8c4c83f24a6005f21e92600de2b052e5d9d0cb5958e28fdb2b36aabdccf5aea93f3377849029b9061b3f4bedfca39953f49d61501e2f7af0477662fb94b3788d0e92f590c9db89e73bb1d580685c2228094f48877699f40816e611d816226a7926d3c4f9e0d077c2b3fb4dd676d81f0e3e6148440d6b5b07bce94392f4ae526fa9b7405e34a517945be84d1baea0986007e9e74bd60d07765ca33220ead79beabb629446181cff9065f1ee76286c3b11dde05211492151c6495196f69ac2d6b59b85a5d8e11e5cf911f4d25cccef2d2dd9faa276f51faf30512821c23e36eb89652b7de94d1b544aa972273d74d074ad153b1ff903907920012fbdfd071cd1ac47b95b51bfa928484cbdf6e7dbfe0127ce50ace7b96388a12a7503f8cb3100de6aabeb2a5382a6f7470b1fe38010094ed7ba98ab39f5ffdbd168ecebad25f086726197aad1a25f4cb715e016a8c9ba151fb4e877ccc1bd82bfc9576fcc98149239ccbb64188c80689f21c780fa67c3b43ee52e6569eb38821c7cdc2743979c592cf58550a9d2ca91845cfa46c36ede131801cb3ec87525cb278faa5ef742557d5d83ba9dfcd7ff561edf9ba9c827362949d45af1c342b918809d181cccc5f51f11173bb89fac444e066575d076b38ed374ff572f4576639ee1617b0bb0804709ab50602eed0dc5eb7b71019926441a84bf7794d9cf58807b6253b7f8ac36768b5cf675a69250ab44978260c4f33c6ef5c9747e74647704cd504df9b5126c5316ea1e7440d7693ff7bd4104cebb02dcddae6503650275cd6d6637ba6ed31a99b8bb827cbd20152d93a09cd532c614e894af94337546944f028fc9fc169432ac209b66b541a5f03091e3576f7d106df88fda20fbbc6e430473ed84b486740e0163022c453dcf93f49195dee29c81ea0d0a857807f495c42b6fc3e65cf39e36107cf84cbe4c2a5996934c371adbb6c97603a70e7882991036e3fa28fe6401b2685628e783ecb363233985435f539dadc56d2bf92745338fab070f7e03a40959eeb18f9fe93bdca7d01f8241f1a152ad4bee2c1391a596a80fad6b35f7ba2150521d0c43b9ee5e64ccd59d923b6e10c4d47d70830693765b2b1fa8e2ce371a82f6312d99efb837a935b520436dea4c217c00f9e0225c72d5d3806bb5d5cce539d9dd7d983cabdef2b96ee76cc6486b47b3629bc07e095eba9b73c8cf4681e676b9bbff8455904c49e54e6ca50e60296598b1304932dec4d5b45f182a5b8c7ef644f6a8cea8177f2562047db93f87b6c46dc3b15a2036d35a1118120c70b3853b57d02a143d103a141fab43a5068513526eb5ccd5498723e16fd96e14719092f74565d72159075ec2dcd6ef68da380b5a25cdb3535c92aa254a3a4fe184f9ae553377f5b81ad55c3360f42191b6f5824de73e5d0707650fa637fe5079bf0e603e8dd1b8a8fa230485b001018c232be46cce2396dd77b61c5dfdd2734867867a95cb4f96bce2c2d0be3e6d4ffc77bf03211d9b4e8c4898863c87bc36d3739cb033cc798ee68cfed13e6acf490757bef1cbefe79359cc9a438ec05ff5af76fe55d7c526948f5a40548ff77bce1a7724f16dabc98e93fe11578cfbbb7dbf98c408d2d7f12d5a5aede983f4c820add4644ea8aeb6f9f3215a54da092b9043e2e99dc8a830b90bdefee24dbd5ed213ec66c36ba7c8ac9cd4125e48f6d110c36ffea1999b22a7b0424106b164a313c048d2333ef89737a6e2cfd9029178fc4dd7d4ed8fe9a8c1bfe69f5e3b307ba0c50ae0b8de97b5638c8a3449ae087825f1d3bae025b2b441c7952a2d42df3282451cc26d88e224aef7cfda0e816e6c38bdacbc328394b75363b72fa749c8c0e0b28136453a9cd6812bba967381b8cc6e9b28d51ffc4f4795e14d37822fd97355a11019678a5b96cc2e99902b4d75568fe69ae4808d77be5a77f18351a4d2eee52749ca3ecee5ff28fd57c5786a641b0e25689bee1b902394d353a1a9e324c839b5c9eef606cae5ed14d41361bb94efb51fef11659f23b2fb7114b4e38e5c55ff99cf4d00a315a8528cacba16084bc381415bdcf87590a986cac6a04af50e5e7de098dca9b12cebedca671e82907807e23a67c25488f85b4b58275ff5f0e084f3582ce7f780cf699d5273efb41fc67ef7778621c0c6d0635c3d1ccc266a5a0b5ac5e212741e3ad9aedc4246a875eac0dce620f8a04d34e1841eede4ef9fc7b2e25790c6a120910384d5f7491b22492ac8e09676128b600e1eade226d7a09f76f856c327bb9ace4f297868cb2311f916ed8b9ce53be53919b1ace81558a24c0b86465085b7f220ed3a4a6943e97547848074ef71258f307e7e2909e65fd960cda337cc2cf7df453002bc78a9e58ef1b5fe05082b8a7c0ecbde8ac8488f7063a2300f0f428e5cc57fdbc23c869c61e0868c0410cb0044f4cdaeb4cb8794833cddfe1a3d6ad69405687bd3ef3139bc1954cab24aac1bf62aa21ebaf50faa1bb575ec7cd2aa4f4c80c140a2a2cd745c5edf122aa7ce3a88da76c62bc7a1c10145a4263109ed3b41d64e3cd6d1d1b8163f530b9fc2c951adfa0f0ea8dc2d5f42c7c74591b903c47052099871b8305d001aa50738231bf6fbc318511143bd5c3474af25094bb9da0297880a895b5cb189086d03619f32360f35726b70269aed2101aabea0324544f2d355804e46479e338ecc24aea0f749c4c0cf9e5caf849c309a277663d4e818e212d6a6bf1ca5f3ee00615bdf87b4acdefca69ea0357d396ed7eee6285f4da2bea3b2a3fb3d7af8e902d39bf0fdf2f9e90fac836e5c14b3c03329cd9c4b3328b211159c4563759e500ef37b7f67db42e0a89eae6c6742cb0d1b321bf3450a6ec0315fc0f2840283d597dda13b1fa41de78a318e3500c0f892674d06c0472107d513806665eb5a2d622fa2c63bf12ed818716bb2f852b76ce8c20bb9642c850e07c6790056d39abee8351df2c9a5406dd2ba3ae61c2b35ade189303c632d818035fda2a475a80b77ba2fe5d00d925b3a26a03b5850ae5ebe52447674fc86564ae47574422717811dc88259a4dc87d641b9500bccde6c525b44980c3bb3c9d495ec3aae9f83b4c47e502dbb57f014fbff9b4c6cb9a3e748f8f03aaf5bd2ae4d89a55ba5c6935da005e35a56ed5259c8cdf50e77951d667c4adb54eaa4edad61686d14dae806b296fc679e0c0f50a8a561428efbf384a3c20586da296a7c6b4c4a7b3725517995eb8d5dfc6740009a39c946937f0e99002323a70677e127732c270b4ae3d5ca419e74db48a6e0824e31c8175aff89b7a5ce9fcfab49ef58135babbaf36940915e9aff9c2d250386ee7a5069aee6cd8218bae235f310b616ca8be3db970af083a3ce5ff0d86867a49add5737f751c1dbc6e6a74e9c79512f8a801e46cef7a0e6b5a870f0fade3bf50abe56f5ffb01c27fde0af3bbff18f1cceba11f39e3c23428565243e485e52d0e3743536fb9c33b20bfb6d66c0aef169833ebc060606bd44e5602a9b1cf8f5fde3af3097f78438516b3911731f6fa67dcb245ce27970a968b61761b405623e65b121bf52de561951dcf3d4f964d0e7dadadc5c193bd657396effe000daaee49ebcf13d30a630dd8e9a4eaf8abc35b6dddf7692bcbb4d33e4dd98600686367a3b95b2836cd70da8ca10fb0d70a12acbc1550bd072313e5bcca1755d3357965d04efef38ef7313ffd9a34ab35278e44dfa3b74db94b2236aa0e1358fcb6cfb700ccc0119b347c55d53666c88bcb8dcbb710931bf26a6774821ec3e98140f099fecddb79e39b62f4a7937773f673f5b43512390261f79af40e22357817927c52f326a27b1963b300684bf12dad58ef23a8a04633eb8917e165ccb584b3bba00ac229e73acd93626d1fec31aea4cc724127d8743c7349f7637c9594344698bc7fa027a45fce06485cfb67cc153a5756223c1840429447477b048e07fef083a217169df710fbc403b5281a8b7d44f7226c59bf4f371000e8baaec52acfe971c2f588aa61d80a84027fc15a791c0a33ab2a874fa697ba8818c997548d468796a42a5228806d143c54eae14fb138c2c7725522e94f0b6e77a743853d102ff5e731eec5d395942216de5e91582bb8a2c7963e9bcfec37e0903c067363b726685358ef037551700d7612aa79bfdb99c0744bca3255182795de472307dd3a82b643237e8e2ce2ef030f8fc9627c84df0f1bdca9d64a462d2aab55f6bf21c9925bc11ae652246be3a464a5bdc14f2ab600609ea2d49dd7d5707cd84084424d6ea103c9700ab73d5a1199847f8ba7ae0e191c94ef18a48938e27a6c0619f5eb137e39e475322bfb582d2f1d1ae17ae8ac3a1a74e615f3fcd43e9686528d352656e555cfc7c185323d0f81484d406b7edf541142cb7e38c31b02ab47561d13d8ed5be69e671e9df940fbe9bc16f510d4453af4e6ea562b125c74a0621b484f66c7e4185d4cafed42f292a966a6f016753e7de836108b3a519de4ed3eda1488823428260d89d77f6fa40b0ae65b5820ddcd35c640a53f1e60323586d1f5932296b49208674bcac62a6bedfbb9af2a09e38d92af1331cb526a41a4b1a4c10cfc07f04abdcc701cb6ed77d332654f4ef19f8a4040cb3e67a4025328eb94584f4446825c7c913358fe22b8fc02bb30a14776ea6dde16d200157c1fa934441752c59f21652b0d6b3d19728b3fd595fc6466af28dc70cbce92906d419327a03e498abd038627c05028ace3e5dedc76a7742d2d7a1af6c5e41941ea47b2248d3f21a87dff91fce282792fa605ebfdc93d3c08fc4dc570c620abbc55f8c2bbc955706155981dc4aece6e7bf1bb56189e008bc8c92529353fb19dea3134146eb4c9f45a4a8d74aebe245513f56af9a315dc148336c981e8a47287ba3226698f3ebd02f07da22c3f680874fd1912fc837572771f410d3622a9ecae377760b2587fa011771c7f63cb1f5633aad4514fc64964b52be396a98e289185c713757bff637fcbab2abfbecbb1eba2762c429c408e94f8c51ea37d3ea4d74732178d39c83667a6dfc71fb93533f44bbc85d00d766db3fcd8bb83d8432740719c57abeea977c23f63151b5923f59246e08cb484874f6af89d2114b7f3bb86d5435f440a1488f100fcef0b66d32160b5bddd56db6281dd96456b27543b5b3a817583ddcfd5173d21ee6d7ad3fe55cfe8d8985543c503338e7fc6462ee9b3cc1b83233f9fd9454ba127b771743e76650a5b864846ab653ff61a8fa45b11afd7b445daafc9046655de30f5e2e512bad6a157204483a26e897c5d64ccbe886082f5f82c4af39403aec71373fddf92446a881fd4f631e39e069db6c87db36be8060589dca765a5ec1c236cd088e679ecf898d6cce2c6c99570897a6dcab93059023e89c3033a3c2c9d4b680259310884218c848deb8d7795246a58d1bbaa7c69341e1391419295894a007cb1a28db5472195d08a4231ddaaaa935e081c35b42beba308d29500e0ddfada3d50dac51d7db66a0100fa2ff00b381c2ffd3e0ad524f084a405bb11d41f476e9a6ebe1679e3da39ad200ce25826de710ff1b28d4e472a023f6f0025cef3bcdbe1fc00fe0348f352cdc97bba26169507af9604531e9164ed701400fa0fe9c1fee90187d78bc8829a1a0b71a7ee6c4f1f5784777756bc9d7187c148c3b459bff255c768267a978351283b4ec2c71fefa7a97e9865194b85f928f82efbea290ee411d9401bca6814204d6de194abb6d590266b478adbad7ebf7ec69e9dbdd84acb46e357e23de4b7c48cccbbdb1ac68f438ae0ddf2d37f5572e9e2d61f10d35fabddf4b49c08b1e17233da0138bfbb5339e69319b7d6e0a2c192d26aca9d026c56fbdf9b73c525291ea2e3643fab9f803c28a52df280ad7d994ddc0545aed4efac0ba6a84102b32fbf3fe50ddc4b493206027843377ee867577354fbb3e46f33994d7153561d853546c6aa3dcf7669d2801d2d35bc8a3c447b384cb2256dccd29ad4453356d004637825d697160dc0ab05ca4825593e2c48daf2540b9aaf46c30e1ee3ba72449e939d8ef1a741ed197d63535517677cab489e069fadbed5341c16911ce3c9736647d6a13620de01ae908f721f2c4d6d1c23e6970fb4ebd3cf6ceb88fd813725675f310ca5914755753ee923f5338bc8c3e4849c59ca30c4b7e73df218c409a8ed434c1c250f08d525886982b0f71d860309ddbc83deed5c2465ea6607a6619f1e33c98f1f9bf4837e14d8f9d2b0747a6158a14482dd65f130ec5130664952938ba40b40ef3289790c227959708cbe3cea3ac4cd6bca70174558653a665b04e5c4ae167b914f909be16608ba55f36c8726ac92cb8a3fd9e001225f43c16761b1e6e56f9c5be522cd233826745bc03f090e3a453b4fbcc7b4139bbabc917cef6352b92637fc86a6741658d471ff234396f83f3bb0c219de6125c1241a5a88cfb3a1c874b08f6ea003659b2ee14317bb2538b92f4fab18320d7fe03630433e367f6b64aa36744a24ea306b347bde7620151053660bd99ffab338633a0298f19dc0d7ca7cf17def9017e483b32ccde48fd998a34548421ed544919cb610c78639c32135bebaf0853eac825f1efe6dfbca285450a8979fde21fc3cf564f1394a0b2e18937647d1168e938d77e1cd29bd8cf1433c906c280fe61794253a9c363060e173f6dec8848202817bffcc4cbc851a38d9bf66bfe29da1f2cdd44ed64b1a64e0a8989220da18a32ef04fcbafe1a1cf196c2ef233f9c15d5ef3146f9cdb1df4f4f566b75da4308ccb6ba594955e48714e20960a0a8418d8053fc7fadbeabeef9aebe97ad76dea60f867457676b60d2058cd9ea58934d38d823cf3bb3c1dd8e053655c4d8cbab0400bf7e9a5df2c06c9977e2e7f41a3369a353d2dbd8d2da88b17c7a716b11225bc372e848680a7d4e0a70596073b3c9803cd9a6e2e306ce5cc2937674fc2833914fccf3e45fa7e7b331f9307883d112868346bc2192b5dac5323013030bc2ed64d5b93e8ff61263af97deacf4ac00ae2b5962c56386ab9e170ab77fa2f88a2ad9948da1eda5fcb2806ef49e17cf22a97c18c68935b8a9cf0f6d68359c51873bd28f664d935a43eac727323386788a86bf51bc89290825b67da7dd604cc893491456ba3ab1ff6642c5d5ae5c896ec1f8fbc38b3141fb9b76500087abec5d4acad7d5660828524a8de26562ca15b2f3a9edc7246a7abb716a99e4ee67795c595d8c429aafaff7c4df1dc2b891acbb7b3e4ee3c4bf7e8835a23b9ea4c9d918b074d097a07929e5cbe134b9a7bd5121a02e9c01bbe4d153271d29002bbdf35ca0801eeedc315aa8504b86888ac2f381932f6e1c5b5e17823f5193d9cd969d421a6b58065f2cdc494ba281710d94d4f7a101e628e59da66150daa3caae49a3fe3bb0f8d5940e1451b1dcaaa1facfe4f0c9efee9605799b3b4b64aabde442553d5f13ba02d25469c714b3be46f013fad09c80d82298d9ff97e3391ec9fe4faee239cfab9593263821ce85c57183eb65702eebd087e063243d0e6d620c7bb7ec65ca9381b0bebab22d59eae9d3b8068faacf7e82b01e62d1281894f05682a6037d99050064b7ec3dd0d87b97378dde3c4063f9a72db50395d3447dca20bf7c0c4cb28a80a365551b1921e747365ed3cd1609b1c419b9893359085b8cba2262b347563c6de5b10c6cd72070e74a6e25fce35959f1364a97e23c54e2c2971d9ff35f1fdd6d4de95ea004bbf8ea43d256448368158d0d0df7c3b0ddba63079ccdcee5ee49680eed658b9caa2f8d544e3c35f49a99e313b7f9b3fe51530fece44b78ecea0288865d2b04741a913dd6fa137df2d03c34899244795b71776deb91e290eabdeecea92f0dc2ca7126a4a203653f568f03c810b3442684ed3e8797149051c072d0046f2dc8d26d53379eb21c9cd6843d3041ef82e0e1227ad9916874608b9af06ae0fb4f973d07732866fd20d3de8e8a988e2d307542939516abdc507bd6557da69e59825da70b9e90a47581b965f506686febf8b37f3374c17d838fccb38c4d4c970485bfbae7c6879fbbaf2e2a08a6bc08413884b5dd31cba686d8fd1b1218e56d8b07a70f2de06970736b03d830d0435a47d3f425913bedd66a5dd1ff6dc9d8b41123737b6c90578a7da9aa55e171b86855695ba67bc80682e42b1ff9f4ce6921c6769a9b82dd0085cf39fa13422eb69e21da789c18808ef7768fa3096f9deb64fa0c049abecd149062e5f833599dd2513bbcb6cee263b26dbee22ab5ddad8449bd34df0f9327032ecaa20050ea9ae4bb4ab40f4357b579fd5276220119a8ffbe82b6bef10cf7118b5daca399dae84de792d18e749c56b148086ab07c53f71b5fdd335e94915fd5c713d95024d7cc04bfb562765e8e42d0c524503471b3609f20b500a72b7ca050fcdcbca0283b4ee67a9be5dbac761d9bed47238eacb3a3447c604488457f7f7fbcbc164ae80d968c18ea939f098cff3879d8bf6470e1de722b25b1205d473bb0a0da271fd08e67cb9ea9fc6354ea421cb9a510b241293373c2ec7ef33dcdba9737c73d40b374fe752198638425776d25205ff14e6dc8ac9c2bb144efc38ba17aa35a1e2e7388e4fcad7541f2d06afa4a1f1db0a3536a23dc4289e194596881582ec63bfce9bf6c02da124f5d26bb10e7e8d0865c309ae02129560e5cfd112b53e345c343e42f1b67c92ba057e6146b128a6dc546c103864cc16fae2237318f4fc3b05dce04789e0a23848ee539ec1e624265eff32129942ef308739f5623b51805d9f06d0bec29c4ab0f9ec7493e15d20912e4f27060815d30951fa8157239b49ea44adaf9009d4537f9e78451df8b1f623c59a5471d52823c70b0b5c0ec189809476b713adab94b32d6c2f1483c615c9267e1a7b4d0c444493acb9edaa89a07b80f06351e7d70ed4932720f7f4803559b4b515629569d2a8438a0408dd481413567e000403c43f729d481761965974b773769eafd4160785c33991caa33aaac6e743d4d98a1e389c8f5f5649d23c3a9a3f76fc7a874c73cddbfdd3bf80bacca823695fdc54a8465ced3ef1ecff61870379bdc4b76fb615c59afabad20f89e489e5499f95cd5dfdd5c4b19faa55e004a53b73744b0053a26bf82b2f99702e9acc3f86514f3aff1506e93acaaec6c6cfb80f4316d831094ce0e88637b519da7429a849937ac057da25f895f1a0cba2498dd5e444b4b48b190e95b3466e49af3ff67d21a506b3a7356aea011c072455edc38ba2975056b6b2d75834c9bddafecf0f7c5e8bd3c13d7a6ff1793b4a43a923bb9440bbd21e416192834d39e181e7767cf042a81202 +# +# Params = SHAKE256_W16_H20 +# Msg = a84ac56687bde5e2d8382fd88e343a128dcc899a02ce38126675fe2a3bfd6c2ad8adf8d092ed6f7951e042f8fc60a366e191c44f3fd3d77c8dd23505273cbac651a48ff067f90af5d467c4ac525872c4140e82358591a1daf8a7bf6716a6fea003d128ae6cf80a30bc06f6057702f97133de52648641a4f8dde73ca365bdcfc6c4bc3bdec3258b61f23105ebb52ca189c7ba30fc24f0752c66c00331c28e53aa16219a85c90658c615e20ce175028b6fc01dc0aa1ae9d92f5f8fb4212c6e4e0dea138c2cfa3f79495188eda3c2405e66b410c19617e4b5a2651e086b834182a0821b5794a7c417d7084a876fc7618c96172eeb972a5f323a924b6f0530daa8898f9907fcaad6ed374590d38fbc65de46f26bd8aa70bcb59b0119bfac482a1c10b415 +# PrivateKey = 0c00000c08ed4fcb39756b1b23574e91438371d5aea4bd0a8c477839150c0aa256acae45776f6d03167efd384ba4f85d96b7a08dc75fa0ffee21b09f884b9246426a9fbf7a5b7ac777bb9bb91e5b8a62c962f040c148fcd431d0d9ba8f9941bf7e72a04e6e9717fa02db10a94abcb260c45df9874088f7e84f494745b30ae0df1c7205fd000000000002767374e0200977d4765ae140562c49feaedba4f312d7b25249592539ddaa0d2da235d38922314932f22103372ab72b10061a36c2b6a57b26ea6f0a5a98702345d2109c83f7cb52cc7c685156a8fe0010d360b220d9ca61ad30837049a0c05620c891739b85de6c3bcfb10006d740e3932f7253de58f8500bd943f8c2f5da7edd9f60 +# Signature = 00000000000276735b16e63b60a8a948cae2535e9eee904b6ebfa32a0ed1927bf17fc6c8927befca38530bf0d6aaddee3f2a73ac90a66d511417beb9c7a2e517ed199d2dbdaa58b7ce4766ca72d82f2ea794397f348312117d36996392da64a73c97711a9989633c18d93477fd21c1831cb23d42284d84780063024a3edbf3bc6efabd5462223d6f8b77be37829b8252a06f741447dfaa29f4bea860931320dff36075e6668c5c785dc1d673e2f7b234173f9c214d79dbc94a2b35fe0d456523f343da4be73b246bef35962d33f7536ab008a8961a76735182913a5862931c513166f8104bc71473991a86a47e8a6bacfc2b3b17a94a9a57ad1d60583653c20c7b46c6f10c698ce5c81f8a7cfb9d5c79f4096777ced453830024126d2146d3e6a78e8a3f67d6ad35668eee32f4ceb6a966962afccad68ecf1288354176dd9bff2e4607127ab0e55101eaf5e52bd0c431d29ed8ff9f4be2e6cffb84e5c812835d336e201604372e478198508ba319b71949c18f05e4b334ce0f0f36907b36b7996ceca70df5bf387b22748a0322f38cb988a3d50831817931af173c619e913177aba8b6f4def9ec04abe36e30daa9ee1ebf699212b3ed9835025bd1ec1f944fa21889f8ee1928324a4096719aab22df2231715ab7d7cbbc5edfefd60e508c33f94b6cf781c029ef6cbc839b04de3d6e873a0b748e46329fc560da1ef1fcea53351bd11c0a3b610e61f71bef213f5ce9ca88d73aea7670ce6f16981aae5d5ed84125116b71bfe7feafc647017201adfeade3cbbef15d08328e2a2ddde09b8470fca282ca4a665349dc2816497e34812de3ee62534cd19de0e17a80b3df762a4b774785c4d07b40ae4b2b27d5a8df57cc9d49deac70c6e23a6bfc2de57587052d7fc65b0a5ff8eee960cc01e7e150a04d76a5006b7e4ca7c91ff6e50ce8fabf53f921c340ef1cd145c529e3c8538038eba971b425858c46a622c9143b45eb76edf61b6c7e65f65d1adf830803eae5af4d4577c7f31384050655c11938b587c084a4ca5671d199f2418b93f85b44a12f43b39a8e2d8c15ab7041ae16dd14d61069ad513b79347a62e5ca7f04992a2caf0413bcd944149db0c370d066b9ccb90b8035468c0269a8db9c7883f5b6c675e093ed7561835add0acbd0b50c901d8b9d075b9024243fd23338c7a3f36d4d5ea43c227b03ac36adbc53715274ac29acf42da1e63bfeebb11b82eeba361803895e09342dea63a0d2ad5d5214212de1728051a561e0bb2d1caea99b6cf03de32b92b882990edff94397fafff6de8639bce60218382e7688659cd95035545378d26ab5765295b3ce2e8c71b32d42d7b71cc7bf032144701661b2a50a9a868e156c83df93fea140444cd1c9152cab3321793719d0bb133e672951588dda5b5964613ea4151de1c9c72bc4568ff618e927efc9b88d6bf580bfe6b23ceb5a5b05cb536075d0f7ccc4fdfe4ed030f4cefbf144562f07aa1b73f4ba07ba11ec9857d560e19cd2556515cf8e9b9a621b61fd91d37a942a47e51f3a510613bfdf7c0124e55d3f14b22c091f6bf374aae95ad42d85ceb80701a5f52c7462f9e9ee2be2c8c51009b0afc8fed2a4fb958b931b4ce9d3bda0cfaa187622841e8ec54c00186e85a7a1780e086d79cd1abec4ea0ebc29de6272fb5414369350c3210f751daee61bf03c57f79ac94b5cc56f15aeab73374e8690309f64b468e3f2bf63a58cd14b961c2c4a06b9b0c0dc1c927e82818c1f0206fa55ac96a3cabdd2e634d3771304137e394badae1cd373f5ec1397cc0eac0840bee9c1f33f2abc13f6d1f933fd3d4c9c8f93c8bb0ce0b8a63489a53ab27e46afee98355de341fba15a214e20d8f462a6d07d847703aeae83555ad6c0eeba0fb75e47866e6a0daa59ae98d276bf4451e90260f42f69af30fe430e4a8703df9f6fd2112adc13836cd454fb72679303cb191ff128457e378e22d8532fa9a39aaede07bcc54cc5cb9459d70041209a9e9faf14b852341842bc8d6f8d9d7f8c1759166364b24b7bcc0ba79a4139bda0ddd892a37a5d829d93337b2c3e6dadaaef491533311a960ea12e9d77cc70b39f0e77bd64b955ef8c6b6a907d40fc7d1912ec579898a81fcf7c4adf21b3fcebccecc39660a06f03d4ee63554fe44cdf90f4373d4560e90bf3cf3dc749a8bfb5540f7a42621ff819369f471e09c916ae3f3d32a2d0895ca9f3f7aba5fe51f019a89d3e9a260cca83e12f3fd9c09762518257d79808528e09d529d60b5147fcec2bbba438cb97ad5a94fbb9ac95c54b2760afe88fd333a903761e9849baea39c38d4b8a2bd7a60feec562b19ab672359386e0be05019da6c38d2a7e0c7b7c763bd61c1fe615d72f6e55be0c906f6348bd606a77877fb601d5fcb9746bdb93a81efc9ead59b494eb3f77e7e76fb54cc755eac6ae417de77e798d091a995ec11b60df9c2e7ae85d2f3ab03d36f34c0d07438a40d45432c7de2c818a63c57f62df7121897efcaea0d6f6500b03bcc9c7a18d6a0507b3dafd2c8fcb96f02aefdc32b2c49e72c4466ede0d11a805736616eb04bccd4c56659e8332accaffc8b12df2647df4ab3830c0f4a11d7a0d8d73b0aba218477446ee730fb615fea63e91ef0e45d38ac26179de4d64a68fda2a5226be14094ee9eb64406cd50f5d4fbcefcd14a61bfc95240a56b664312ba3f1129ce8ac0ce0026312cd271c9d427f37493e4fca278ad2dd7cefc96460c1a0dfbf341c1053ad66e6ee83388e7606254a81c95c616be4bccfd397af5f8024489a94c1ec56088eb9c63a115b15f0c44e9fa5cac9c8b83d81005ffdcb9452facb7f026a6f52141b546f6b1f6611ea85ab08560c05fe62e3a0ae100f13b144d2542b93067409622dba48291137639678b9516e483ce53559ca97f25670e105bbb7c16ab295b829b047fd1d0ba1025294c85ada7d10ab330b4729f0bb57dcbf4ab7b97a61873947ce2b7bb4999116658b9bea3e8a7513588c5e09b6b26a13880ee6c7f7daef629d9267fbd78115821e7eeaf1d5d7100a343619715180e85b1464c2b7abcd8ae2871aabc6876ac2fd20d41784a0db725251d5644b13fb83c4d7e5119cbda3675021eabe8720be284726ee54acde4eab45495f7b054a8689742475c1dbcfa8651e929f4f23e017a6934110a6e219f8c0c1873eb317a32a8cb39a5644372008b3f0e14f72e8ac797343837eee50281c25ca9859722a6cf5df92e1ef37b9e9f115a79e7b5b1daf142eb65c5085aaa8669622aed619b8fa56736762eb46a0f32c3df3659cbea57a867c31c3dc942712aba6a05a1a4ac5bf03be0555cd4698a5d94814ac585150e8d2d5f137e0c4d99729061c4ad8e7fadc48281d66f56e90ceb059c1dcfe7ca9379446dc5bcb1f57b6d129fefb8b6b6af239618c1cf19425eb91a653857093ad0e651b039e0a3c912e2118fb4ccf96f5a78d6eeb6b3143fc37158723e134a5d966e50ffa7b847a244dcaf20796eb572516c2b455ff1af25ad3b85225168d4fa990162c691fe394da5724e56f4334592c4420a1bf6246a44b7756072b5828ae39c0f92383be6dc57ea17e2cd6a436f66d7c66a1310aef3b20c9b187ae42956db69c7c34a11d72a11e72dd58b2fe85e690f4d5b42dfc935fad7452c6fc54560b0673c00b1aa529d259ea5d0b495fcda36469ee99529dccaa286cfe3933144eea10a531e08459fc3cb20b97826cce0ca633d1d1d7dac634fd0bdd5f72db0e134c3b181c1638d12194b636edc9d783a7c6815c1fa7e0746fcdc32bbf023059be4298a462907c7966908dc5e7b819ee75352dff9b749800261bfcb381039413fb98ba4ab718b42db3e331451f3974c581c160e414c6c0e73809e24ac24d64a53360e5493964ecc26df02d7ae24509e72580b3191c5438455b21908781dd1c748b8860eb4a614ac5b679fc5690307d16079ef9fbefef359b495d31c89c2d97036a00575452db70427022c8956028ae172b09f391e26819efa8f4d1157314c182aa8ff24e1784b0b6199209239e6dfd32d886fd4446231b386e17831a1a0e5cb411afc924838fa87cd4115b1e16dcce6bbef1e4c5474d31845026659b1991e863feb1f8e065777bf2dc5c09c4ed9dbc7ad35c24da7c8878e7c84321b012b6b9301fd4f9f1e7cdeaecc859e3031a5751eea165e5c591b9cef68ccabe8f387bf4b45203a7526afaf90de78442f256528ce388d0bd5ca18ccbea526d9087220f3a8dcdf0a3f0c8288babace9d6a2e5ff79b196e821e61e943e24c75efc44e8f18534567ef126eb66350b820c1284ae7843503f8d39cb5ba1167ae6ef59700131ccd535f09ac1b9fbb7922bf3439ad6c43e346032f88a1eeec3a007d342a6debee379428b527d55d4fa507fce1b240c1cceff3a1a10f75eebe68d2c8f71251d3e2a4d8e12397a5058f24c641477bfd4f390a6e2d4f71d732e0e0ddf2bcde4760dc7b65a8d1916767661a32f7f3b7115891a91fda4af08c1fb7a01e488ac658400efa1750f950213917f93cf4ff15a5a24230b2ff6086939741af3841b8ac14e996698d3739712b73a50b27144db47c468c1111721e16bc57904e3eef77e48644ed06fd997faba9a8082d467bfbba37c74206e7d38984c0a05e2eb0ba0172b87ac47a152f8514684b538de88870b2465428c299e582a7f8f1caa727419db194def4687e874818a10c898d9ac58cdcd9779d83d14ba01b94ad965ae0734ac2fb7209b20d74eb45aa1646e98684a0334692ccefb061cd547d79f56e07a6e0a202e810a7762653419bed58a1af3d31843e21e8025be7d9c4c4b5fbd98a8512462734d4fe8ca75ec2094e4838422d07efaee91ab13b56f7baa7933f7f3a08bc3a3ce4e64b2c44d51096267120ccc15a472050967586ba4a3382ba6f531fdd03f665630ac4f5e0f8c08d2c572a1b2da9f70e607bb93db608f340fe393363dbbc74c0599be9085436f9b9525ca67fdab71f8eac2ba7839f804e123978e511f70954102fbdd74cd323e669b85ec37f5bbc327ec588cf787e6eb3ebeaa6a07e25c0512d6cfba26a491b92b1c2c95335a53501bc59c8d54e1c2c63b17ab490e0da471bdf214799317c735b1d91f13cacb07d62f1dacd5b1a9174d12a73cd1ec55747bf08d1494de4fc3442389b91159946bfeaa938df652419dbd9ce20c227176c7c4c668ebaa9fb4344b2357ce9aabddc67adb5431182edca9404d8f7b0d024b228fb17ce33e0a691ff6d96bdd95921e48936e93dfbda0679f1e4ec758a02d82a6cf83d7d134e84dfae77fefea3b8ab89c70a3e51b579fcaf3677853e250757b0a7f85f8f87318a2763ad368910e55121cef2b7dd96e9676375c349a42878e14ccc93ee4071336a0014a3802d379a47edc60b16949994674ed71f34fd520e99b1282d300dc58886c57c412807e80930532b722eb69833849c5a22c8fb7b0c65995bfbd809923b57321ec7098a9499c92e5abd9eecefc0babff6e3fb02bcf156be5ab0baaa842ec6de1fc5c6a6f086c56bca3a591f8d4767248719f9cf95fe0fafcbe5b04279dfa9105853de889d34455add9355f9bc52d47227b2575a91b60bedb34722df7310cc7b16c17be19c4acf3846c2fc5e50b3b5f133e4b8e349c34eb9da3ed4aed4a979ee8b055d646c324fc98f4cafb635dd9fd72ffbca24b7d8e1b4fc45d3582569c8f34e169cfc736b698536e25813f956aa25f53c6d63896f2d87219f0f89c8b4df342f6ab60794dfcd989d65edfbbf3240e3eb71ebb7789dda3e9c6194e24733787e2c1609d8f771c42e488c57c3a9001ba472b26da3fb44ab2779f56a6a29d410bcb90ec8d62c3e33ecea81ceaa7a436165ed3a1de679cb8ecc728b3d459c38b430c8b3d624990879d52cd5c57c64b4dbe544d0f7d04c819ae905391e1d38579507536e5031bde2c2caad42d256b5ad64c2fa2191ae3fad5656cd9a60bcd725df2ff9ca1371439a8f4c2e0fa33883eda7c988cb5e219aea0fc444155331fa0bd6c3de77a7e716d03bc5b5580abcdabb54321de2f3a6d3079fae99ac5b1ee1dbe6d374f9aa3788ca5dd37fb27158a1ab93040f4b5833bbba3aad51b98fd5dda129fd6bb01fdb2743709ba5f5546d63f073d04159e35f019c5a56edc5bed94cd93c4918e3bfebdb4c2e7c7285f3606d1246d77f2bb9499d9c6e5680bf18228b0741821091566dcc53f80cd268912501b55279cb6b5cbcc8951ab5a66a587770da7acf75a3a9e77d680a17b0d977b2487f1ee5e84c30acc3915d0cf11880cb607ede7c60e70d65aa9c2c55e564163a117b9333698fa6a1da63746dcca6e33ed567a6f3fb89507ab85da0afd68ca33da2cdb1daeaf1383d18a65db4ecfa5ff56266b80166a796cf5f10a4065b796213f9a7f5cfd8720b3e1d9922bebff81e9803cd96b0783c7d9ee5540193266f1653271fa71b9a874c1df031b1f7fd2e9116d7dc81dfabd09cc6d63390638bf63873cae32f7f09317e4e4033dd0c4fbb3edfd023d7403c51240cf0c0bc6c55a227b9b2c014471c8b737486b0973fd8cc5ac36b12285ee680cd9258d1444f68cde4be1c63aee41a54b1a6b136e09571011e9ce8aef70e859f8f5f680f17df5d179870afade4be27df2e30fb809df3c494f6cb02f5cd24a30092dd37b12b39c2217a006a87880d889d74774365155919364eece568884cc49471b40d179c6718c1e7a318f86c5c77d194de9f2283c1ffa90727ae9aaa63e4e249ae5fe4cfa575e5060c9328dfe7b43a2bc6808773ad75b9b03526aa01e136e0a487429e50038893c94216a12825f15dfe51636ea338a0c0c1f950769971d3289c7d64207e054e3751674367467de4d12f6b2258efa0066c5348d4b34547e06007d5df5bbf2da9fcd518ae64d48e1d199034403f9e5ebce4bf3ba70c66177dc0c90cbd55081b056134054487ae9c58b40b76905b57f26d8fa3cd9c81e82ada64eca315aa732235dd55f7dc75ab5e3e33b691dc28e50102aa34b8f9be56a032a64cd6cabb91bd4aa59bea4875df8cb57486b08329000047bd078d8860566420dbeabea47d771c66a3784a148ca521b4fc1b3c95ce5726498cdc12b1c5eeb7239e53476da71f20ebdff8b74e16489daca48930cabf76da099ab74258fa624af8b19151c9d9f9b49bbc11495b51bf1d05929bcd941707f7cd14e9a6ba65c39ed1d64ec94469f245f94777b531733733507015e2fc718ebe455bfd609e1a37ece4e09d217778b95b794296a6c0f42a5456d1204b9b0bc447e8787649a71d276f91fe00d2aa526992cddaf87c064dca16e7d660eab82c15f9814b87c4448ef069fd33e3206bdea0d538945ef0d494d18c8e8942a5b27121a64dbd9964ee516024ff921fb206197ef1b7a48c41098f609ec92acf98af52ecd91c95ca61314c4f4be6e797b1800cf200a315d538ddc4b26d157d9e71fc5c0fc25fcce2ef4a6a81262d42c5195e87f5c3eff74559ead6a51a9209d0fead7c7ab9f69528cbebdcefa35ad152453599e75b14bc0255b3ad2109cf8304daad733c5b98fac72beb52a8d435c37fcb12125f8f876d65d9b515ee30cd71a6cbe39f165ec2486d85593142fe0a8f5aea551d3161f40a2cfac84c72b0f091090224f32291ca47ed6ea52c3c820bb899ce87bc7a7e51b2e7463c1ab6d5ac4aabd599665543c189ac6893a1e924be1e80f8fdd1aaae50e2a357a01318aa09c02e18d964f02c2e2b5dad16ed4827d31be65dc6b91a186199fb2ef50e4351e995f3e5239668ec35729226ec8b3e642859e2ef4531cb4ff1266f32ff567d7e8f76484abd690368c01c2676b828ed8a3fb61eb0a17faa0a2f36e5d82fb1fb76ea06c02dcb8e03593856a6f0add1307eedc7f4c6bca5f6f1fcd53ffa9e8950f0031418242947d39803bd3876662493f9b46e58be4c7823ea4450b2e4e3fe0d3635e4126cd4e9ad816f758707cdecdb4826f69b05a26743c782d0cbe56385f05bc78d2cbe13ba95531e13cfd9c9dda0ff7b006fb7eb196eac51ce14d828ec95f9f4ebe7803d638c6e5e74b334dbb3db4497c48cbf2733a67c49fb1e7f8adb009749c2069bf401fc4dd86e132379dda130e7eab83856620c20079f6d7ecb66d52dfc824f9eaa6dc75c6e01f20fbf87e8101c4a436e77e9198cda7a88aaaf6fc161b8dcf7579b957d7f4822015e941108ca5560a3433a85e6b22262eddfce8965480ee3f282b94b18104f6e356096cb0a8cbf1471f7754a91bf8ba537acb3755e71e380667d8c3bd81ee0a570c2ee4524032f15b43dddf6b49d307719f7c23826dc38a19cc8249f35c51214a3223d0eac85b70a8fbd73f86e112d3dacf3eb75a7af324f93ad366abd8b3e774fc96962ea9dd1cb6b57cb9cd94139b03864a0237a2a73121019de828185b9e7356ee046530193543e0a0faa2af7d543c904bdb07b38d9173d385c705a331a316b19f8deeb9169b21e86f01279cad6dadc2c4c177aed58f86164796f854f7d0f6e6e8a7308a98500003341e9616094c05b78be99623d7b394bc1f1ed3cfb7960a14bbde3826a5440a198f5f70b198705daff651d33cb876b037a2cf244dd8fe9d4763ae57e42f7b94589ea7fe457fa7d29abeddd5d27a7abacab76f17ba1e9b64da4585213dfa27ccc0527e8c07a036b8bc9abf9599b00acb4cc1a22f331400ceb5f7f712c0935f76fccaa2db057519648be2973629da7a324b6a10ac8b236cb4ffabc76fdf600ee4b6863bf54a5253d73faafbb976af34c0e6090526abebecfdb5c1dbc161ae4e98f368dbc627ddab93b90d35a8d4a59facc0e95d18decb16095b035f6e9f12eec7a7d28961a8ea2f630b13e49058338417e2312bb2599dc8c37e6b6bbdff86e6c804cca20d14516460b3ad7c5a31fb6e3ae9d8938aff57cc5ca3fe652b95147224b1838838b0e0349cffaf3bc15aad1acab1b3bb0d49b4b9a3301cd3b7c07154f1a1d6da6e2056860c6903c9e7e1ebbdc0f5d8c2d44812b2034ff9b629b29d80d78b5667072a409f44dd5c5f143b3df8303944bdba98426ce5e2dbdb09eb0658ad406f24a8c73d2f83dd0d4fc617873148fda077284e4fcce5a45004063793f662e147e33297c2abf9dbdabff8c58ba9c1b3672e3aada5228fbd853e30ef69bf994da6f3159be7ab6c50e13b2f179164ae8c74e9b38264fcf0e4735a59267e6358da7b525ec8e0ac1e91b440af86b5668d7cee9611d4847db66c5df15199910e5a18d1f8d0571a0cd9a252eb739dbd67b19b894eafc2327c1b967ee5907c9c634cbe6f86b83b5bb96032979fa998b1a0f0b3a3f3d15e18f2d0a50b14c520c162566bcf9f538d0e2a8fecc3e4a565ff41daaf6170c37f6aa7de37be69b7e3f7a6000b7e44716d2c14765450d5097f8761d9153be8d4dff9ac156be9e2626400f0045a431a9ed989362d01cf9a51d49a5ed4c2319e5104c53fc10f3004376bfc30c49f5144059636bf4b17b2924d357692c14a6560a19228207ab6ed5277261a55fb2e92e01b547737a6384f0bccd6a29fb6b2b5e19020c5979d171376a80a09cf2e273b84552d604dafbb51fed4b9373df671ccc57bf86832cfba7a82ed6d626e2e85c20800bff8c26e5bf1f3248b0a33dbf692fed167990602d2d4c2fb35396e1087617fb1d3e7fb6aa574ec66a89abf3f498a0ebfc444dbfbcb734f17adbbfcdf9741c19267ec5c950df49380a2bc499ca25fc583acf5d753418fe3e049a93e78494e4a412fadfeb04a7aa8382f104e5d271f9f6a28bc6eb770c8a3ec2c768ee0f66c9e67a3bfdc54d6bd54565cd66ac54fef1e6d54d36805c36d67a68bb43d3fab0d345ebc9b772a8267e572d8d155a0f83421f86d0db277e118172fc54fe0f505da9de4f3845c2125a7d8c4faff6705a1e3d9926c66e92bf6d76ac58895868b534f38c1642e19303804320369f3affb12e3a274f7f5dfc8bdb983932bbbfef90950b134ab8aa2623de2a3c15ca61848e79b2451258fc968b0c9c076ad459a619ea4b8d7172b9a48f83c7d7dcbfb9ae4dcb564d5bfb4cf5c6b23a62e6ddc48e897d20bcfce6a9a5f1b9364e0f6c10b790ff4ae0753e247eab92e46aaaeb6d6e63625ecde07f1ec2a5d34d3f3509856ba5df42164b58038cc964de8c3eb7f7d7b14b70fb3ee15d09e175127e36c3a7e0bc4a710ae27753cc6b10657d608f2f60c4380939c8e444ff7f8a728415484d72995d8b2c195fd036bbde8c86b290096d1834bd2eb5a809a30974c1020c7985e6734d098dd3166306b3f3dc001fb8415b7417be581b0ac507d3aae749d6b66d26be7eb296056f5569d6c7e64238b860a09741e018b3814cf00f4d828ef4446769e06c046160ee187154ca53bc335c9c53daef47a4faadb0e1962fa7bd228bdc37f5c4a800099adc583a582b261fdd320c56bf263343e52f21b2a4dd2e92a44d91c1469966a0b02feda9e3aa65ab08b0335841cbb6619db7fcf9efd599eef9ff2b2d619cb13b818ceec59208b21ac83d6dcfc2137da326b165e9964462ad3c219cabab3953d30c3a150318e46c07d30c25fc4e7e19db17070f85ccd0190172c52f9114d184a9ef4a194462ba32ec2a78909668f151b5bc975877cb5f03e3dccc48270d060e4da4392c3cee49cd0dd092075a65baf4c21afa823ece978347b4f57bea680438cb78f4831aade32b21c3b36befad1364ee0376d1ea76f043cf57673d61ec913855da9503faa5df98f9c610d75746cff7de7171fe2d8cd118a7d02c28fb234faf0a6f4847d6aedd8ee496c0fda093995cf7d8809f73c27268f6c1a32eef16143cf9e3336c493577f93801043567d22df747994817c30b2a1f875f09bc18a1f12b423fde70d5a660f161b5022d3586a6b5e2f59d7b8c8152fb42aff0ceeb04ad807b46203478ac94184eb863b91fb55869cdab36e4c556c112a8495c200092ec9a70a216146960dd6aec4da8d88edf9332650e05a0de84de2ca2e17290fe7a01099da8388def9366d91766bbd62f2ab997c1fd0f25562fd5625dceda036588b6734f11948aaf9355d3207b7f59830e8050a55bef6af48777539972f5e049f08d750252d8bfae9557656216a5cc183fc9df428389e340844ea918f588963a95254244187a25ebf22fd0405913f559972e51413b38792875ef4c2e758074055998c6c44a51d24ed6aa71ed7186ee5cf2b9901c31c74a1f7d1fd63bb35682fc1a4f9b7605e87de27f33873e8addd7c8d8c1dcd778735f1715147092e127f5d80ffde38b6c0512eef5f8f86f60ef0a726a5272d5d9ef07c1293c422245da3e626fe00d0d27302fbfd0e435d35683c4eaf2cf686edf7acadb6ebb00a6f856e87f64daa886bfc90cc209d84ca88a28cb4ac836ba989d04acd058f5c5c1ed6d70f50f524d8532bb25a1772366f4b4df2b0d02d45cff002d02bf855943899399b806787a20b96dc40196bc296dd15b5d2deb50c4c49f0bff61b5ce938f601a65057ba74554d6eacf7db29fd449cd58b1b8d0ff3ff7cb17211215c38ceb3f3955109ca169640dac342ad3f0848ad989b113fed77164562a78edac7d5c0c57206c520e3434b19571bdbd42f9086a6e23a41c78f6ce636804733440720766d92637b443a0f9eda384f28defc5e7d1d0bc3b7a3c0bedea59d1b937baa21a990779aa9f21c4a6877a2723b3643d1162b5472121a4aca885e0d3cd842535138ad90c616594e6e994d9549ae82028ed06b54e759169d9662eb9af910ab9d91db034dc78ac8d3496202b6a8d8bb3cc3b0c269da1d1628ea6b4df756363774050562ef4ca2770d9f8b86c5b2d4b76e19eefe95fc21c0599af086e559d622eb3ad1229929d3394e9a17261435936a1314bf976a57c5b211c66e90ce3e8cad1cb728e645818cd9739aebeda1cd9caebdfe2e6614a52fa848ca7ce7e7e1e529e65c9d93e6f8f4cb2df4d305652a04f39064cee90cc13b3aecffa806ad0352b321d45dab22236e93241df56539edcb2554dca850040e8cf0794c4298619ba51084578cf8e631345d8aafe4160844135b56a5bdaea6e84166da96191419ed03382498cb88e323533f103f4041885672500263291c1a5803c5b4ee073c6b683860d45fa3e3c89f74c860fa35445688cd9f79959182b5d606097d9c8ca2ede6d5152b8b1ef2ac0728c6b8ca237efcc21316d1b146d77d4412398d07a65fc588838bc165d2932e906d37187dc67a6f43b773ba395deedfc63424e2ae53bc24dc70ec5df26d2f3264e4bb8470df09acbfdb5904346ac4b7196526883db7304322b6889afdecabc37a8ea981145b944ab7e06ffe964975a8a15a21fb40ac97f027f756cfe118aa4ac5952bedd182a0e3ec286807242900de0f97a02f0dc6dbccb11ee49a84f756f4283e2d47ce9a4d772042f44fa43f9acef004bdfe2c0c5eaaac045dfacbd9e345f89eabaa5811670aa7453f7cc9b226f879f05047bc58915616b2f53ba6a9a3f9a590dbc15e3329b0eb3dd2cb2d1d957125b22ab9cc0ca0ecba9ea33488f663393000408175ffa57f27f08eab98717e0be1a875411eea867630de6461b5d7c80510be8b58c57264f107ce83af6d1c965e41fe04dbd384d0bff066265e1c0d1a0527919b12272bf2c17a92f82ab8d2c67c17e0d5f4d98b62bb5c1c1e63d2ba23445f89d332b4eb5b83400daa9fba51f64ccce6dd52285cb089b56b06d0aeb32be1c25828d8878004429aa04717a0bb0ea8a66577c1a64848ff7fd5d44fee5f50433a8fa149d4cd22cbd7161829f6d1258e0f002b2485942ecdfc872a04052c77ee6f1c94942da5cee29079138637d1e48c9e661dfbaf047c59db3a1bff01a0c03bae59878f4f67aff6003bf77e591877fd2c45f927dd455a27a02d29696fe485b842f5645fe5f7a657b6e7cf9a382c8f6b6aae7c36a40a44296948a4ea476992c17c75cfcac03d1864f85b615976d54a4d90549bc1dd03eed551d60d12e7c6abe12898260da7fecadf4d92e14e30bbeed69f9ea0804d75fca57f651ff52af2bf62cf47c519fbf4b0095c0a3d5b3d881b016026800a658217ef60918123f64fcbba1f0740d9ee446f0e495e27d4c35f5dbc7280ea326e2df7b2295fc9b3cf9322f7017ddc8de3ccacb0b8dc2dabc4ac299c2d596fd7d89aad18138f5289933927930586b2498be053211c2265e99d00e4d2cfd1b0c3d6fd416211376d6842062c5c6a7ac72f9fbe81f275ff563573ce117ad57113949ff23de5239ae20083d7d7695b90951ca14fbea3ff93b35c4ce382fe958171d1d64d7f081f1c6d5dbb19cb74e721b76796531206d0f6f458310cbf7554822972a99d3e787c6877f5785260b47671a268233bca2692ab94abda8eb78a3345bb0bf92b5144c38076849a262bea6ccbd72ff905078d2e6546e64d78ce897ba8cf53edd75f36b0401a0f56adfb0ade6ba3b02c4ffe3ffaabdea339aa3956ba1eb1569cae64abd97193e39d1477827ea6d6e301c456e8b0411f75da3f6b51e87f91c88bce41ba5df1fcd070ab3f7bb91d07f4fd6ae2dcab9a51cf259e4075acc61de002a4cf9c876a82d8dea2ef96c5fff12145c09fad993a6534b7bf8e46487bdceb7bfabfc969f8130b1d680e84d5f969170ff9d9378fef746623862101e38ecd61c5e503bc8729bbda6670f54f3e228a626287968facc1268a67a26f12b253c18b2b557ba07cd4f708b99744267497641799dbe1cf6b4a7c4298b0e908989c6724b4c111b34b999cb868227243d76c6f52d301b253721ab644fdd4a28233630435d3b0e2a066845ed4 + diff --git a/src/tests/data/pubkey/xmss_verify.vec b/src/tests/data/pubkey/xmss_verify.vec index 52fdd9b99..edb5632c4 100644 --- a/src/tests/data/pubkey/xmss_verify.vec +++ b/src/tests/data/pubkey/xmss_verify.vec @@ -133,3 +133,63 @@ Msg = a2d4a1d63934c13b4bddfbb7cc62968274c785cffbae18bd66fdbd78fc19c0eb3603c6e2ab PublicKey = 060000069688212fb7e7d9e42aca5d52a9d060c5d48b1f0e2de8ec0846e9296de363de9986862f3f77128cfc130bb64c4ab672a1ea6bc4689d2a359751bde229cddbc072f6e20bed39db09b035f7f07f485203a2268e3d93c182004a4e6921b9012bf03676c960096880d5403785ece425544a4c82ce31cdd3bf13f33365d40954350d47 Signature = 00000000000738c44491e36400fe9924d725856503409142c67333dcbd1246c64441b9970ecd617db6882bd3d583464e4be49b7f129753838c037dabf32ef2798597db5759f8b6334f64dc4558a8cd914c1953dfc529feba9d531748e4045f22f39748950956d42c805117e54d6a67492f4d252572c06c5ee1d715e7e644cdd6e432602cb94d8a67b4af676f08e2cbc35c0d56440d070f034e34c3f6fab77fc936254ff818b05805a2eed14f93a438103876ed99a60daeee9e700877c8827b2093bda243163f070c7383b9c416c9556fc48f213b35cfe776152c9644a90f1c7bc0757c8ae457724daaab835f4d5a42e5820ec95b8d722e92ac16776fbe99cd063f9bd83e475c7a3310dc0595019e906e9ce43d13bc02df24bed5c2e7ca751cf332d00cd2a87d6bbb0a966a21759eb85bb70e71df0e1a7759e01294fdbc2fe3dbc722eecb56596ab888fcdc4d199e431629e6eb91bf92a79291bce6a9b7a11e3c8b521bf9fedf856386e7ce7d11bb6b2e6a7abfb68b7cf781dc65d5dae603a73fcbbabe66014da3bf8f9646d5b6eaf25f157eb06ac3b94557951d3dba156a8c93b23012611655fcfbf97f41edb83e68954f4d57f69b30051b364d9b3d9a6f0a5257e1fc9c40052524cad36f66e3e372afe0e972c6caefcba42c5db780b9bab48f31e0b7f4d21d9dd359e14c0d8a73dc7bb1908fcb2b551976dbce5f03ac3625b14ad0c83b68dc53e91b3d661e0fe6d70d50f7a7cad51f76f27bbd8ff2ab5cdcb6bbed8cec406e7b0dcc1798347463ac6e6c375beb003c0b4fcbc229d4f784e657253aab55e8a4006458bcf796162f9bb9b03d1cd8baba2d8cceef8b6758c42f8c7185c461da99e9fa5746063a1463cd6800762cdbadfbc0ad990caa6ab8897b18fe063e7b8cbab5b4968090011690ab0284274f0bc4375f6583df669fd03d38d8b2e3b954a5b36d9eec4084381f169c3ab5a43f245cafd3bdae2fadd6f56891f07103f6523533d9e6fa29ae77831ead3adf5f3520ffaad3c9bdf3a3952e1bbf9537c0a9d9eea0de758fcf92d4e362003d7f473bd633dfaaa95e6135b031f1185b01d9c4e8a62283258fe2024bcabf3439dcca884a846670686e2ffbfc57db83a286737da41452032355cb9ab5540c7dd4ed847997720060999ba85ec7b408f0fffd63f3a43bc29fab0168aaece68c23be80e65e8d1ce2c9d0ea5bb52eab7bf6b0ddc34cf22b5c4e7f1963391cfe3b9bd878210344fdb3873101013409733fd79cb54c4ee3f27d236aaada01c8111e781f38f046b55e74ef4a0f8d222d0c86b1ba20ccc5af96de39f9ce3de7da10f1defb36d5d775f7d2a957a5edcc40fed8beb67a4208d36bc388ef89ef4fecfa6c2ad9a3875ca3693b74535c47b36016d6ca42efbc9f2dfc53672c723194430c569bb5e5457a077f52f45512dcbeb842fd58c4446d6c768b975a970fbe86c07f3fb6537a9fa667ee7612cb82c4aafd88856a61c6393e7c21694546456e1d93a9b7803d563708d0d46d0e778990abd73115536f28eed31c4c45604c13ba581d0d7ca3b6e8c99fe914a497bdb4750cb4265d642b578d428ff5e720f83923f3507453a8cb2f51d72e261ce393994a990caf4bc5e52747297038cac331b51e86ba29b792be4cd15d787d521e8d08558cbd9f4e877924e19719c4404c94fd5311e6ec168534be7b9e4dcf613bc607a9d921e30a5cd1cb7396af6d32e632649f08015701578b28a26c912eb689721b463f23bf092f167534b9590f87463bc68bb9f61016d9588f7cc55f219a0db42d0bc44e73cc8f97c5a6c328b3d24a8de8c6c71840b3cdd849f07482e2ea7c3be30094e2ec9d86125a2d4a275098ab086eb2043464b4ad8a542cb6740466bf0010d5775aa72c657f828ad26bc98f81d11da0a2a5a0aa742b7a13248e2eecb22263eabac484bea6a0ba079320adfe29643e7bb6dcca928c68c328c74a136431ef4f56ad85900813df410eabebb0c19b252475b1da8d85e8b02db2b3d34e6b07a99d0e636662f4ce34bba65ff75a3748d0526d74f72f48e077062fec8a77b92b19090d772c1f036a0129fea4cd29c257fbcbad9d347fcaff9957843b354d2eec2bad5932d39aacdef576af74879a1d0dd7661e353a20fb5799338ebad718c9a656164940ead4ffc9ed3f9e9d8cf1597aa29f3a26bb757f6cd67fdfb8db6aee4eda7b8b757c025138351a05c4ea6f0539e7f15de2e1cb76b500b8d5d3433e2616b5cfb697823e9af5918bee3b4eb7d2557cbdd640941c4e168411ef53742c24779892ecc4df540c2d4decd8d72223677ea606c0ab06e148bd7a51bb318c72d475e7629c8a13dcad4071f1652fe2cca9365b22e4ddc6c9cac83c78ca200d067e88fb0f84c91332032dfe770951b7cbfd4d1b7922494163c751379db65be9528e1293c0fca9313d4df010f763d1e473ecb3e2ee553aa9d81941b0605fd0e05bf2ac9e557f7b6badd3c392d32a7c31621bc7b4207812393382e8809b70c6ea2829a9d359d59b40e3fb0650bc58e4e89cab91eeb9c53903781db54d63a73fae3c85d8a5fd74dea90939dd6ae7234fe2f632730a8adaf6f7afc9cd922e76ecf60a74f7371150b39ef826cb3f27a9611d3987a127baa99778b0d5c4a7b86350488f857a27bc99836084f5140984f617745216b1fd9bc5eba707bb33de8e81130fcad4f52b2a0b46e499a5ec3bf2c1411dc7701add3f4a33837a5c5d8467744344deb21b2267fff47ccd9feba8a4cc13cf4316da3d4802e3023f45f51ebd69888e9f8d3319fb8aba7d5b6f12580fb3f422895c6537fe373e11e1a558a0db6ca94cc079c640d2421c5a461969957b33a3efe2e4e950c92fee37c4b41e64cec5c4a0e580d7dc3b0ff9a4a0442c3f3edf021c77973c39fc349a1e7bdc3da14203c02c5e39ba8938c195d40cf25286d7c0d79bf8ce71b1d2324d663d985c0f8684a5190c556e0046060a1d65de3447f6819cfc2b34bdfcb91204c00eee8d21b5e821593a9f2e3089c5e8b34671e4a224a2a522009f7280579246cd67bc5903aaed3157407df3be99f51d522ac178896df9d71688631533c14e34f63f75a8a0c367b07526011331d7feb85669542572988a4dc4a4ba188c5ed70287ee1f7ce3a60f5e351a2b4b4c2e03c975e6a8b578873eb55b7f74fc79091170c8f6a19d7f7081537a9211b2ac1f7ba44e57f6da828c0ce6c2ec3804076103e52e4a19dfee346c9e4494d5b9fcb032715eababf40610001ea2a6f64dd9c328e48e3e3ef5b0866db8cbcfea0a082369cf22256efa7222073dbd55f1fb7998de5bf600291efdc2051696b67a64f0643bbd96231e294fc4e3b53d3c9905956772f977a4e57f0e0f4995707125c1534957145844dc67ab46c558f9b2c95b677ca39c1b525d1668f1e9ec16be0a24db8eb9f7aff148d623e572aa12d3e05303a323d252877f892eef691710a12ca265d36d84df29bf54883841c1c79db9c9f5b8b75b3b389172f7d41d864b7f4b84965073528b0c806e2559a7772b741ddb12fa4f6843dcfdbca9cde24a2ebbf9c080d7ad304f9ae9f969a6015ce6689b6dd803bcb0146de770d5072b01f5cfeefefb5dfd5890388f4923387b120a9b7dafa31dc4ea2ee766561801c567599f66006e1dd3be484a3ccaac0420e58ef2a79d113afb36ccb1bba4f60cb66077074d5779556b15fbfffdf31864674ed87d176f06b2e5b47d799bb66338ebc63503899b3b9de6ce2b940aabe108e99e6c2c791a6c173a67c5478ba8e66b154d27c7dacfb28c08cff93ad9327ebda62950ddecc400f4043615f0fe1fdf0c534cb018198e0ccd91835db0e8c9dd4c3d23393760160ed209deee0acc617d392358cf0a991a9504486ddc75ab974a377bb251b806665f04172fa9fbc4edbac67a59bbc8799f7584e962ab9f3d32795a977f76233913d50a6cb5c091d1952913550bfbbc60e314d542b2875a98678eaf257614b592349420b8c6d5421bb9ea987a7c4b6d8753e67861c9e37ceb0cf7476e8400c7db437ac23a70659d70d69e1e7cf44fedb14b052d2eab6a312ae7716eb5bcc4fd4be48fd5ad91ef09fa7fcbf95b9387c8d65636de22fed0f40ba1167fdd633ec98ae2d2072e56cf554dded88f4dcb0d0171b4d14334ca56aae324fe5b52562f67716086ade1d1275d2f64b109cace4dfa87b871860a3c1f1effbea16e54427db21894982fa6a33646de4850db1050248dc8d60142e1ef442fdfa99527a4987ef8d3e637570fd8474a90aa49fa3f1129468c8ef2d06d0835fab08f48c58fd3da767f3f34a8ff99a9c0a8b236198ad0b62dc09164dc8d6cbb2a865e205fe7a4cfbfe23cdfddbf69e3208cbea18df5a6a148f4f0e4dc6743285f8efe6fca51c2fdef3eac848ae9c5721382c1a30d6895646583fc54757e765663ec803db49cb2193345d60c2c47d06a57818605dd156a7130bbda4f59c53cc53b31aea18e277d287e892bdde69114107ccb8429daa7bc7ad4e9ebaa24651bd94df2c94c0bb881ae16bf6a3dbc22f4ec2ae1d520eb00ae90de7fabda00d69d7a8935b7330aea763a1f3f9eb5642c374a0936c9ca14c6945a90610baec9ab0a0101efe0c7530a02c1a6c818d966acbada4ea904e225f72df436515b36d90fda40d11e4b1563bc5933242ac5f3dd6fd33e49eb4568af7b1b3cb3661453f888b7b2821d1b4544cfa7468626a73bdca3ed32754668e1e1552eaa4562e2f528f2a242a5f84af9d47284eb09b71f04298cad0dcb1edba9916cd2ba14e3e616838ac7810cb4373251458e5888ee90dad1ef0a0377dfd323a5a718dfd0c3ca9b9e37c3b9f44dbf0827e360e8cafc290b52bb29ad4e637b2032d2daed05d8c0cd443fab3dde1e4828bf16a2d9ee2d76f8b1c3e3199d8b14ce6e3d4f80ae55d41111d82fd8fe74ba6aa77a0531e0ee3a2abda911e7a4b6f1e25f2c1f703860e445707107a6e361f8d5561a375642d4929d81b04ca47647f4b2a60218149dcb3e17e9d144d9c13a85e5929285d0c0db3f76607ec48456e06fc3b0763c4f6e4dfe4c7336bcd0aefedf5a1b563375684ac746bec0ee15ceb334833124e3fd4702882ca3b596c64f80475b308db3ae0d51e1202c042e46506f9c1812e7823571fac00d866df5c5933ebb33fc005b7d0c28437eb1f3fa504e6219911bf43d0d97a2cedcaed57c93697010093512bfe7251884892f5b2688b7f303471feeddcd85959059bdcc85236e9b07976a3f6e2adbe55e12736530ba533f7fc7267bdc9feef905f326a844e911b43c702514f862a8bde93a2df4642926b26f6856a60b6e844c0d73e65be70d3c1ff99e4bdf3440c8275fde413bdb8b39a6585a266ff7ddcfc73f5b9cd6ff2af97d086dff603ebce9274e7349f720306ee2d3375a56e675888db957282b7676bd7cdacfbcf10e7ce9b7c90f0c1db5da030497d649ba237244626e29f9cfef35bd8b67428aff32a5231a9af68fbbfd884aeb13cafd310bcec008c6327429193d88e34a04fadd0812ec9c4448cf1608bb450a72b72fbc07b5b128249bfc93ddced873053c6b2b73953f2474cf20be2c4089954394c756441642039f5eecccedb298ec038dc464fee37d8543a69c6c1f4a05d8fb7d9aa73d55ebf2defc49d17768789d83c65b2157a184af5099b3ee2850d85af469489bfea4b9783bf424e82068d3c86b7b815b69a1f5ad876d71c73d75eec4f80b7da7001e6e556fb9074531312d699540e53ddbba35c867af2e426c0ff0c05e842ab82ff81488b7a049ab3c1053cc519d7e07490190ecddbbde03cfc92f47210f5a8ffef4fbea5925cfb55e3c269634031454d096f8f47dcd6645a22c146022cc8a4a205addae8fc0eb15e40ef48341c8d07ba9b7efbc9a34e1fbdf8e795274c85465326852cec7b376ba80c70115b0bbdc73d6ad4dfa2de72506a7432f0a376d1e8f90048b6b0c6db33c2d7742badd314177333e907581ff647e895a2a26c253b5a8f593b7a46fcba588987dd51037886b8f331a416c1ec8b0bbe9434bc1f5d21a227a4908045c369bccc6379325b3c2f6de63e1959c5482f7de9df0c7aca11c8c4d46fa37e397434eea4099b2731f3c83736718ae7ff97aad60d5c394d3e9980b56d231e7e6713a302712384263d607a53d6ad2fc8c588108836f1807c242a22d72e9fcbb553cefa3851efd55e36ecbb90f56e668e8b7a69a1027556889e6e1d27927f394e74bd8434eb93b598ce582f764893016c8e5338dc4c0712ffc1962150a162aafeaf00759a1f58e1810f41f00fd795426c201d48de7c65b6252993a830cc8a415c8088453bdc5b522f54e261d55d74374d79f6eeb99a2554276f3dbd4981ac66cc65aae8fc3193acd465d340743111955d6d3c28ecfca50214e46d5e6ad1169dd0a25cecff8acacf463ec2904087ca767dc039256a553db5d616d9bc71e8e423ba74548fe137f6a37bb125cdafdabbca9b9521e257534badfbaec0ad27b71bff7e6d6ace688940e852fa1c9e06bf4df97ac6973efef5196f408ca869048e10797c0d1ac3ad80ffe1e55a28a63547bb22d795a0e44f51553bdd18e65057f6477605b2c69dad5407bf981543998fa752eeb730363f1557f7a21cff41aa443e5d0651a218f9bcead617e1d5fad59e16c549f4a882ff2509b6b66d6f71bba6c303995b1100d53ada607e39c17d926f6bb04526d90075a84b977707f6979d4f3f3ee1dad0f76e9ea375f4ccff2e3de37abb8edc5a32641e5bb04c964511ccfc9590bf302193186be958b362574e0c69c28df9dc7dde2992e259482932c701556080dcdeee605a82813cef6e3740eca6a6c1d64d12f74e52fef5c77015ad97c61e4a080a5019f2536b0964692de3b05bd4194c0c04bf72c300ff207d247ec806b56caecb7268f9441cd867fc28ff28cfce075e0aff71f3e4aa2d14bf6c2675700eb3f907981f667369c6ab76c851f726c3f91cc3fa0732753579ae223ef8e43007ed4282ba84814bfcc8647334197caf04ae8a0aa3e922000e104354c92e8aa08b5533c0ccb40e1dd2e8150109f631b83f26ad78dd04315a0cfbac1b3bfa5f08bcd0e18af93a18381ff2654d9f02f162986c9b2fef5ce66222e66c045533fc9e268ca0b29577dd82629342d99172006b05d76170a8fc0fe63936d62557f1fe95d7da11bbbdfc5f841b8ca7e255910f430f6a41e9fb451328cc852468d1601f18f3664c6bddafde7af60d034bea692c65aee997ad8e50006851d10110e768f39759b05839656f204b0616538caac1350edc0c8d7de9ae787386095c8ad227fb5d80617bbe4c4f9b941b2742d1a8c264bf59f284c026f8d056b8bd0b1e5c39f380304bae699d441244d8f452e6b99b142a1635c52e54a8e536eb5b97443a818485f442e93c2ab34bfafc99b3c752de30688e6634e5a35b904e718a63895c5daeeb74a878f1211d609c4bd7e36cbfe91095e3d897363a7a5d977eab0095c57daaf199978379e41585c333ef862c6dd818c9b74678210dafa07f12ffba5b8db878d8250c294aee52de9d5ac505156715b5e8e2b0e66c42acba5080eb2911a22887d87aad7680205dbf884e38d02251df8bc97a13b102af2b88b3a1dbb1238ec32d1725a4e91044298d13cca295d9d5cbcaa3392e0eecbb4acaf957e228156761016f330c0405baf198e809ce600319bca48227e9084129fb7d170ccd60d8c641fc51fa0d1d78e054e819a947c463a1ee7c65f671ce381155e098d7bfaab3108db331deec5402712597f2abc6e7298a4a5f4855cf15ee55820eceb2380894e58f08bf1af795e40727c09b25979d7e290a02354638fcac8da08cf50a831066fbc1745d95d43bc9f63b8d8abf6a7c1495b7e7761a586e22b875ef4fd0cbee41b01f10cdb9102ceaf8cd45cd2ee44944c592226f0257d515a78e4ea330859b7cce3d9c02a15d058162b9ec790bfee4f2b9c6debf625c2109dbc5db5cc49577533fcf90da8c360fd5a9bb5ed14a6b3c18f10463fd96dcbbf8588c342b6ab86f1ae68f5d381bec8bb8ecf243862aa753bcdbb66b994019c63b89358779b41f444ddae7084135a903b4d50ae74b4d20b80889cd6cfd6930d621da52258dfbbc292e0925f80cd28caf6daa88c0e0f3cc202e511bc1fa151aa8743069057de5b52757ad9a74f74b9ebc660da6766ed5b9a4f965beffcec54825172b900539f40666d38344dd853052ef9852a9c412e04b5ba78dfe2fb8f0e2876279069641d2c0ecd4bf018acd27af3a973969bdba7b3b50086c405491972ef3eaa4dd5a7785ccfc662c0a90dae52959d51cb32e81c904a0a93ab330b43514c8898616d03b08cf71c4bf47ef3c83bed8b21bb754e552447dc5012b87e19211d303ae4c6544ac9b9abe388009bd1caf3024583a4d12fb137f7e3b5a3d0ccbfdb27d3f24bfd6461f820cbab1f5c9e1f4898d0d5e2831282a308fc87e06801deca485757071ddf110111dabf668786d33b381b69a435ff48366cf9ac475119e32f07eddfbfe03d8e7a21353eccc41671c61f03d520a6016b7dfd7e8f5f13e11d2335b904e02259c8ca10ad4a99d8c7566211cd393ed6297317eb598b76793a525c44caa103c52a8e4f10a02bda486610864fc2d0e89120e6fa04f3f1a0762cf1eea3fded4ebc910e853c2525d36cdf5594395c04dd2ab41896a2301ebf050cba075256349879d24896c65c37ccb2051ba7aa89f7706ff4fb80a0def2e1ac06dfe7db36517efcc24d9e0b6e29ef1333edb8e313fc19fd8459231e70a56712dc2ba93c55feecd1007815ec6f7d611790e07b840da856363d267297b80d7e3cc7ac868500277de4d9bdd3f6d05e73007ef2cd8d3bededba82a2321293f353c0b3b5f6bf5dc42362427b753887204b4bffe4180e02cd589c2632de7c8674ecea823ff3b9132f5eaee97290da783e263db29b0277d99522f337422eaf9fe8caf50a44d929201f7d9a946c60917e3a33e9da4a70c9bb917c14c5634ead83d994f4c7e4980937c1679264b400f8afc0b5285c7335b6d75f1a1d7bbac17154d75b71890d077e18e85bda6e571ee2f2966f37be071e55bbab2df69125008e1d9c9cf7a6848effec9161c36689a0fccc83612df4e738e9c9edb6545ef389398d8d6e51710b2dbbc4dcc6f07baeada16ea2ecdb24eb74b6b074670a437cca3ca07464a694849234e76c3042d9a3159c33df3cc5c710253753143fe0a10b2c22b3aa46f88a3028fa9c50563f32c0216eed0670552ce466bb1d4ca5feea43622878838f443c539763a89b757245e45af692f35bf9b0bcdae4fd4df783db48d4db8324b3de94064b9594fee3760669d54dc62793e10489e321d79847a2e116dbb13281c9c0974f6f4d74580ef67ec7f2d9b1be99996d410185e37f4fe66927e121c7eb5284044f69e7306bad4ce9d09fb5202ad7c7fe85c76f0a3e91276ec6ba5ec2dbafe06b01fe30c061df36d7aeeadb9f8dea42b0f6b80afc6b6b5469df8dcac8ac313dfa66c904909caf4a9f1f77a41816a14ef1bf08bf27a1bba44debb5295e7ddeff19446379a4819eb46eee94c8e8839402118d7373142b960417ff567516da015e29bf165f5317a6785c5fb9d4dc2f1dd60c51070aef1f0c1ec3c5b429d8acac84d0a1de739ac1cd90c73c732ffab10c7a42e7a9cd9c05cf250637c185363eb0618cf640dd6aff90f610be026226b8b2c4b1ab8f15a95aaa9a2b440e2134d271ef6e34057c8c979bc565c889e9a0feb064ccf7e7d56958ce6b6e76b3d89e0da1059eb545ec636fde232acf3d6977982d2b53b32e8ae4776df25d064aa20aba297d10f15c3f2554d3b080b3c53c3aeffd61a29fe80d9b5f0dd03617aab6d0593cb7b0b1302a67bfe88c28e6c68ab3ddb66025dbb152d6356577e441819f56be6f89d9fe3dc12c4afee48dc249c2ee58e055c782169cfc5631891af320869dcec05b7d4f2aff2719a0248282b6b1b83fb3d13a9311000e6dce747368168f4e516a4d5155496c9193b8f3bb2f9d603696b50127f62c8e28413f0af66b5a83ca81c80468ce89e0de53f1de0eb3d823056df7c1c28083f1f8309c626eae193c5200969f0d091a589b58b93d2592b60140950c7083f61303ad8bfaa4b2f05bffe7e878a7ebcca46b36c492f3a51506a47b6a41353d31a3edd611e863c03eec1905b0be1796cf3ac3e380fed00fc1a9b9489973b0ca813496639ec8c137ef0cacaed286c96fdfec27ef222f57bf7072c447477dea0a24cd3acf783b4b3816e4e81049118351d317e437292aae78a2cf0439b5ce5537e66b8ab233e6dc0b8fb1018850dbd224e56805397f3e51fc5e42c3ab1c8d78dbd5ad68b01153570d5decd486186b1da43ce075380d5dc13b8ad6c0e8a459728409068c413f5b65d4877fbabf542225a33f966d29b1cd0e076805f64f939407434a9884aad488e9a1bf4919cdbb5f2b92b331bfc30c04f9ee5455c746ee4d4293f4d02fa7327892bad806eb97216240363114626ca1f97bf9e0a47844ab09eb41138d7ae5d89ccf947d106e3469d203f24228a746b75cf85d8aec19e074f82993aef4256f4d5033e4a6adae5b353df870dc87d874f1d0b8ee268551447f39016cb53dd25f6b8594ce1a73f2dca5963791b0d60b61f4abe714f8b87500f19561ff571e92e30f77a294c47b258a4a97c48744ff38b08ab9f7032506a323d3f206465a7778f488db05528aa01739c431c9bfa57627c5ed4261c37091bef7139ea268cb71a26b7249d08dfcf1de57393c9c3423919e63af16b64e0be681453dfcad1a7c0a57ab42c8368b7d474d211a5254e090bbf7e8551a83adb4fa71cf7184a5948ccfe676b25ca1f868e167795e3159f3358f8a7e139528c7300d3896b028126c6f9ffd0907dc1377fa571c258c53508fbb2e75c439e118b4dfaa68ec9d4b9ab43e5703aa250eeda636e74ea6ec3e85fa375032ffa3cb268944ee459c9a96aae278d87a326371c2a4d6cc84c577e868ed8c571dd06c41ef19b13b9241c0f2ae677308544815e97f0e95ed23e72efb44bedc3a7c7fc6a2368b873b9ca8ea9d4ee06e5d1328b1fdf60bdff342bbccd970d2a73d56cf5c9c2904da806d3b5649830bc026a8b42c314d2e6fd76a0543df91ac028c37ff4c3f836dc4c926f463e7ca576b86e78c379b835343adf1b85f44972fc7f0b65abedb593927848777e6fad5986c16f1215198188b32f9207651c2056206e3a0ceef1c4779b24406b3c83a6efddab7ec5a9eca874377dd103ae6ace4baa8692af1951bdb11c8b936047c0f8c3fac5392408df7d25f1c7f30f82bbc353fc2b3bcc1a089fc3d62d0fc32fff905da12e9eba01d9bf5c250d3bc34e6e3233c5de0e244dd89c5b929633430d70ed898975ef7b3f7c0c8b17ce6ba2697324c54da293e73ff52bc98ea160d8af22152bac12e06ed75fb98ddaa3aae1de63c335c62da5219277b8c39166fb0d496af9d156167c52d4317b723a9b75392da51db59a0722e24e249c89a5c5ac3bddd9d110ada80ed53444a3cacef0b07f71bcbf229747a47c2f38ebcd6ee8446e6fb18c0319740b9b8a1e08bd422a24fcdee141b6f33c3df5f23cc6020a6bcdee64bebe621496131d886a87affcf1d07fb187abe8288bf8479305166c4e1c14f10ff25d54b02b0ea2a920a84d0fd1f3580e6d87b4a4af06cc2c30543928f83900d437cdd2696a0760c08338688ca6f3168c4d21261fe9f53e7c39a269017612b0dcaf0a987da45a64d36aeada20674eff24e33085a9810080a8bb7dd07c7af8d2167556640b48e4607bf0879fccda3b3b06c298bfec7da73015897d437eb5d7f7c987dfef27cf9044520e169ed9ad6ad8d7bfadd0bedaf55a86e0cf87515d930b4c4d2a3ee919007c58e7df65813bee6c2f511658e37a6589fca7f333c835c3d9de7c856659490472020d26c4bd8e471861ece3244bad1156648ed4dd4aed0b7d55b021e94dc644fb9c1d79aabc4f39c2a855e791ba3d24b3035e06f458ac156b8e40ac716b9a392be4d7905545a4d7945d6dd8b3f6ac55a51f0ec9b508226118a2338ca6c25015efb418cd673655e2dd9d25df1482f01aaf9132c110dfd9a77364d78f118105d4b72086a303a318159985ff3a457594a96a0dfda2f58f5cc6cb76ab4354adbfb6be20973b8f9ae37c68a9ba59463c53793d92093e660ad6209a3a6a81f7d43105ed261b791fbb178889661ea81935561f89553dd57b57fd1213a3ae5baad10a58cf4d7331ba5ba306512e3919d92bb765701d340c036334320910013d3210cc55ca527c07490eac1fe84e6484abd26cc9ee47a510d2c2baec4e4e5bbe7a4842f38c8b9988b92dcab3bdba530039fc1ee32cab6cd412e2545a74aa5cc977aafdda5110d612ab87260cb768f3d8ade07bd84f5c5a26aa11e88d6ec9acba6750c44aab993b754c93083c13dcfbd4f4576bcc543201e96c6a3201f9f15df2180370b4a407458fdb2d5a9c0ca58df6b6867dc0bd561150bb93eb7d931bd41af294330933d132a3a1d5c4fa2dee434dbf3da9e09c593b768348a9b5bf078d2cefbd652c4275bb46f13902421acee1a429bbe2d77a67a99d71c7e246a7f5002b92d6c60c5a8fac45d974ff3078aa12a1e3d06ee88ca6f06169bb67b05db5bfecb2db3622cc717732e616be800ae2b0f647ab4365264a39471f7e353e68f43ab5eac5d9c73d2233e2dd238903c3c7d14d03bdd25a7faf6fcd1deaf94c760a4535979f3174bfb124e7f69b41cbe4ac97c2990e6e2fac123afc0a29be310b6368ad4ce48a711162376c48857acd2c68a50c5fe0d0443438ff3e3153564e5242e3ee33ac31d03bd8670ca537d135434cbbccdbb5a090aa535db8395f8c753fdee0f40420c762901f0d1627ce82814cae9fc98a1caabd7e233ca02dfe426406a0d795bc84316dc5741bc7110601d6a840a3514ffe601254c62d06c6d0e2bfdf84c4f86bce4fe170bf452c35dad3f0d019ed244298be53c634205ba8373cf1716c6b4150af05eda5979cbb5a213fd2a1aeed34ef301592571154ef2e549534769424af7da598ca584754cfbb47fe6f03dd7cb425ef8f6174baa6fdc9704f6fc4ebb40468572b3612ad96c80c7755567b95a5a4b9f749f1fbdf076e704b98188170a9d81bdb7ea5a8f13159d438a14a1f36fab61c4478ada54bd2b2f3fbd99089ac8390356d2fbf73d9dd91ddec9cb66e2f975384f4d32e39c66ee87f1252d931d2b1073ce1c7d73422049e1f53e6fc6991bdafe3740e6b58c01dd1934d6addc07b02a4fa811522f76f7a3743ba9f6ac2c3af7963a8f175403a9e7a4200c20eb4852ee1c88a2b575167eba7d0f6d2e084c20a6f27d326229dd05f9b33b3b241495b65e9274f428dfcc43b91140f9fa3920df9acc4e4c002bc739e731ed4c2619c14f8e68b8fee2a22400af31aa37ee4b073c22d48b0b2e9d96baa94eb3ca0082e90fecfdc8c9424a561fbc4f68cda33cff7802b20f21ba2028586bedb9fde64060881b1f8bd9f390dd31165053aa0e3f1035b3bc85e50e3e7abd5aed2d7fc4e0ce774a29290c3453c0184ffeb270e88794049705e5b7375606a1503cf0fd62e7021c33bcb06b1a9749016adce83dc88251bbe2fd5b3a73423817e017e9807ba75fd93aa88239f30e0bc73f4fc1d45065b5d55896df4290e5d608cb2cd7b6a3cfb159d2ed532380ad2d6ac8b74d98f7eb9bc5b2e292c82b2903ba533544759fac6c66500fb48c9be4bb373f470807e7c574a18ea333d974097a71ea +Params = SHAKE128_W16_H10 +Msg = +PublicKey = 07000007eb07406fd6427977dd5a919dadaefc9942d787341c230dbdebde21873f76c6a538373235c146ee79856aa81051f25d3928b53381c7f35e5e000dac25190327b1 +Signature = 00000000000000de84829a0976b760ef0992fe93693b0443fb6bbc1d72d3adbd98beedf5a533e40398dc72c9777b8fa784d6a985886d6cf0b2aa3ce524cb06b5f780be568ec827cf4bf2958ddabcb96630cffb31f1f9bfae66c8e90d7582744d3e62fc1cb2f10c534ad350ecfd250acc7bd122975cca13adb85c3ff2333f17144c52c086b39034f019f4a6f4986ae01eb325feebf14b8bdef572646e42b10dcc97b203a6be64890cb6fd5bf7dcb956f06e9345fb340d3535916af61f9c128e8c06b965ba880b659d9328b0260734954f515192138aa52ebf2388d2d53804a5d1f5da118d50dbdb2193f58dac49c9ca32ff4d3e9c2d97f7dafc8c392c60735111a9d1e66e01b05b2406eaf90d9ba41f4ac5236de39132551ab4835f39648fbb4966b462d570619cb65d7f6b4e5c489018ea3ee4d33c9a3514b214e8692ccc8a64c3f9e60bf4aeee1d811ffad44082a225ab8e7e391079903013ea742da9721d1cc28fb95896421eaf5251d1a0b1af2c1cf3d9e64c7dcd22c07de0fb0c854ee66eeab774f8f3dafdbadafbb7048a01b8cf4fd4782ff94f764463242862564e02477d51d2087cc5479bc8472c03cd59cab9dd5174eb28bb86da4281c9b864457d09fb60876b4855ebf0d1f65577770d78eb70603b44cf42b81a0dfa0175279db944fdda0937b6477198d1ba81370b2a03176ac3cec4368cee60548cc32314bc8254af9000c8d1e6964553338af62248815ca6772cd4081afebc6adffff5d05fde948b5c8dbd04ff153fe0218a1191431e8083cb4a67e89d71a608d0921a160cecb508ce03532c84beb8de3f8816e769f771910754342bb306db478d6f1e4f85648dbccad0b0923ae6e51068f53d7602490f4f384915b8aaf50c6e5e790512314962ac76950e73b79f84bf9a219411732fcd38c57a9999cf7e3517844967f5ef24dffd1617015014cee8fb0ef0b2d10a6fa795ceb0f411880116b485bb2bd388d2ab6a5a84c37ae35bc85d37589392268b817e3b22d5b80499fe09e509799a03bfbdf400778d30c79fb53729be53763246029803c75fba9f48c47b0603d4f2f3b797de93b622353cd6db4231fbd3ca4ae955e12f1b808fbf430a95e25668f1a3ba3b5c5d05481b2d9d5bb324194aac7a23baecd018de624cb699b6778bec5dd8763f5f8fb18ea7f94149be7f4a7879ee9dffc8e519a2a6df0143775e672f5cb8d6cd53dc33e3dbc71230fef724ec7e83c50801cd53f6f9e2ac0f6a04068f47dc0c6a247b805bf9f261c49e9837cce9cd663baa7fca7fc9ead955d325e1c4e821b116518de060af8f9efd10ff52e27116c4c6ea15f2bbbbac748c39a540d5362db7ac3dd2100940b2e3f4c6683967478ec507f4be63d667d3896d4d7a9cd0779d6f4849e698e40b1e2593f6c041f3b603bfd8f5b82bde1c029ea94b1e679aec64ea00e00f75b880a367abf9571b36d7dea0706c54a7617b1be8b2b57e3e28a853cd198de8ed7abeae34478f8c4299d60b46cb8feecf455bdd5018e1e8387ca0179e80d397ba14b2fca03f6623022e59d016499e482cb21e846a1a356e98361ca99d8c407f47067ee3f1089fbf0d1bee188f8946896edfb50ef838b0f5da8b8370645807b770e90da52beafd5a78a3ed9fbbbc1c1186aace0f1667c3d5eafc76656131b4bee811e77dcd717cbab971ea9eb2a78c6ed42658bb9c0cdc7d5bc181f79a4c2927aaeb8b6d0ac98a9d74842ebdf06658a44bda7d6a9675607e209a95481bc9ec1f6a9fac1674964828bc45b2b89e6b0e94a07714a1aef1a55872ce0c3f83015376938df5dd19e7088afe80cb0f81dc3cdc98aeac767fb11c7df566e3f85b1c38972b076a4a3409012e681266ae5066c36fb9f9600ef026eb222c2eb813a80ceb0b01976a193f87c7845b93a2175ed3def8d2de6e940545d8a3f811099b4134cd8c220853c1133e5c61faabd152884d994e6ee5cb3ef2bfc1116d9dcc639c28959737963f34a229a41b8bd5ed24417f3efad8ee7765b1673a34df57e43914087cba418ad4d62aabe334841b3a92aade830405df1c9b4df407e9034ddb96b1702a44c178a04c31acd39a2a1dbd5f948e8b989209250a29da1c04e3eb72503a26666b3005cafea095c7b4609ac8b332e60d1c9465007bbbdbe409cdabd8eafb6d212fa7197e92a3021a8b0a53d786a8ea97d5330c31aab666461c2e7d96ee9a73a68788ab1d446b56a92da314d33ef8c23d2327cc912e9944d1b76dbfcb6a45726489cfc40f4f0e4edea8eaffc6d3543537d111fda061748c7acf6d2a54e978c1089d671b69b2bf171770da7a2454ec51e650ed6a8eebe671a913be36fb3258679bae1c330caf2a05a6bd9a0732235d57af3c1f046b57e426eefa316c4268e1d8ebc6fb6e83a272aa3289a5411650b32c0585fb950e6988032d64de968280206afd192f7299ce08fe5773dbf5957c165b514c504a81cadec9317071948d2b5c4eb1c5c66953c8bc070ec75248fdd65c0f1fe2b6889d043868d7ce85f26202777af1702856e947f6b0b44e2438b7453f92fc9054e953f4a239d012121888849a30b5533642ca3701daa1b5cdd309860b14a2cb898dde649ee10bc085c600d2d7ca9e2f8788ca6a5d108526508b8ccb82b06f4f0bb8c614520c3d9adec39b4281038b815477855956dd45be13efdd309844949f322574b2dff9efd7ca0686592870b08700b2adaefb2498ce9a70de0bfc738fb40bc5ad04430edcbbfc8f02e6c262a5e7da01d2011d1b0e26e45a53c10150ca2f1eafa5ecc4355f94dcd06b0a9683689cea23df8820dedb57271ec4760046f996ab87d7fb26a9e1a3438e1b981e550438cfd7412fb127b8a5d3fea87d6201372034cf602c70038b72ed3ff7f5d4a581a1368f0f08bd9ef7a94b42e9e39cc75aea12560e300997539ad04e3ada4c7d40f6bbfca2bc649cd11e7e5efbd0585f481133546ff2ec04711a9c9314c508ef5abac421aedbeb3f95bd1ec10539ad4a448b1b14facffc92adf072dce420421df3bf9451448408bbd2681c18ed01c78b99a37425e43eb91c41422fa8961c739f89401e6ff1a8bfd2ef0c98c275785645aa21ed2a300c4f9cd7135fa6db1af2c5f6c1248d4d87baf73ddf1128e98e0fd4de2024df715d27d9205444dc916758823e039f31f8835f7248d5ed04a21e11be98f824ecf571355db28b7b3ee4bee91f81576860704aef7e3cb0e6afc4d4b09c11b6b003b41ae0185b9210713c5a9c9ca05648a0e30e9cfa6ed2567ba454b7892141dbfbb606aebd9564adeafd5eddb277c8e8883e9296c7425246c5c61468d29b4476f89ccc63c5e4225bc65f3ad0c410cb1a74728dafdc39777b53ed9a779a5342f5f6df0f843be093142fde29a23ddc8a4e4a50e006b34af8eb1a5c8488e033057f37ca96f7767fbdd65437312872f60754507b82ae629d35eefabf6d7b53b8db0deacdd568841b1372cc07845eed3036316b0ea59987ae25993ff1091e132cc2fe44185eac6b0118bf4f9d3bda47bfea95372377e1b4 + +Params = SHAKE128_W16_H10 +Msg = a2a50241278f92c8ad617c84331ea21c60e92afcf0e48a714ebb75d0120a9d8dd0556840e3acca6c9a86451a0d5be95c2a25ba8331e8ad9d842a1440e90509ffca5ae64ce06a8f5b65dd852b69e8b88735022f520da3e29d99dbab904646d8bf58d3344048f279aeb1669f3277f0ebbbfac2267c2b9ac8b989695974adcb35eff3aedb675eb76339cca31d6a975a2bcb9b37d4e9d89631543df3c970b141c039059a8a7e648c814403cb7c3ab0051c051d1973c8738e6b6539f676b8af827bb3f33ff12bf0b063bded6591818100f70cd396ae573280acfa713675d233c6fd0d2289b7d2f1de03363414bff3f6f4042275b7baf15e3996f75a61b22a583666e0341143560554ba15d889cfd9a589c0b7dd7865a3ae70e40dfa0e0fe35887d2951740728f874caad076fd0b0e8ca4e98b3a02aeffac91a906e3282bf7c5956c96d242aa1135f897a4059c5c85aefedebd17955b8189df68dbc7997ac06c9af18f993fe44e438cdcf2543018028ac893a362c1dd47e155dac60f90050c03031aa8eebb8479c4007fea897e272b049b451183cd9eba34a451c0e1ae3432185ac0b4 +PublicKey = 07000007843b9e633148cb60f2d1a1e61781fafadc60ec779ab380cb5786103d1df5ffc06295d661c824c288844dfdf149f6f0e2578472ca14f920332a45ec6d2351c789 +Signature = 000000000000013ec7ac6768468ecbcc6e97f798b87c2f7c293de4f01671a417bad924274d81b8f809b1b1c6f9135fd261451c2d107b18a330bd8830e7dbbb95ec6ee84806e414297f5421d17207dcfeaf51f0ff571bb2d53d3f2d943167b8b0f8747e1bab2720421633a36edb43e7689fc54278c814ed6d2597f00706c811c9dee96205df8504e08ef6faf3a2b407f5903c1bcbd01ebb53979db58c8ce9cdc01192879bc555b2f4d6d512b2003b59ffaf0272d93e4f2ca935bb3d4d8d1354119b7b78f7fa706ae09b3ab31fa7c60baeacfed0490a37977a78e2619b7c65d643704c1dba3c4fad4e069fc4e09054c9ab5b8699b4702c5a5ca223db6bc5385337d375bb98fddeca4f7911f7094a04804b00b7adf64701a7126de09dc5c1cb388d170e69d656cb87b54c56b3ea5052333cce09262571dfd28c119074a05c29b392a53945d210f12f82b3b41cf8725f95ff66f0cb3976c58d5a63314cb6ebb47a484d4c9bfce983d4cb38964e33636318547a76f06dbb7d1e81585305c2b02e5fd05432789a622ac48fad9b2b51b82796ddcbd11ead95880d2d121a5f8f197345b5deffde18157322748791e9efc37a4e5fb692878ccaaa454a78c0a9c0957859be5e235865d0e1093c711f14515578dd05f1ece412bf9fc3c1b6497109dfb80d7e2b6a72223ae63fa046790ccc5bdf29ad42f6fae5100b3e5065d2e006986bb3ae386d6618f7840f4322dca4931786d44525db4f05143855e00d19df2f64f00277a0c68f7ffd2039e95da1f299bca91691a823796e5d31625f91d971517ca7173d83bd529a812466e5d6a7c952cb5b474663738a3b6ca45b9e8dba2a9fca7dcd43f452eaab5cb2f70b6cd773430e4ad47b4ed35ffd25857979f581d6b686d06c68d67355364cfa5941c9eb38eb3a4fc0d62da574765c0223cdf284c9d92000f812755fa0ab8c45fc0c8bf4c851b75c4a37261a313846d0c440a44c0d107018e4a40cb7dcff02bdf56c110a2a89d7fb6bad20959ad4f58065c8192331e6e53ad29bb953e6fd1544ab589e87d1e9fc65d7f74df42585d6eaa7b9e189b638c09684eeaf92cc55eb62cb3d1b839a7e82bc1b2a70e9be6ab2a8b54c6af9017494357f5c2699f83c0da7020862ad1eda0ca89e6df9d2735fdbc86ddc6668828970b7e5c41b3c29abc98708499bdfd0330618376d474d6d1a00abcb68c5b31af5cae2461e2a0cc77de4cd7d6c0e6bff57eaa68e92d5a5f3dc73cb00f05b707d8aa7b45a74836b6b31e521cb09f21e51faa422492fb532548b58b0bde2bd70b116f3cb57f10d1bc9b90b6bc2578efed3be054d83b2cd7bc5b543399a6d2f1e6136f60b14cd83ad5a1dbb95a6900e18c1cb5e4c861b8376f0274ce7d8a09772ee28d1ac9e350f43f1aa03673244799982831b8098a0913ec3fe1e8637b6d64f44014545f4ec819c9976a025eea0ec70ca951888fc327859200872a53aec05c6cb05689a5c1c5e7d4089e8725dfb35820a922b0f4c931e0afdeaa964f16871888cba2eddef045fb4686c7e68705fe2eefd915c2ce5332b07684a05c64339995a9c2a534f061eadbf304b4a960da13b0bf1214970dc7e128b413f2b5ade9f07d60050cd4fb80ec9184148321a2b4c1bdd4afd3ff0811eb3538f370a40afdba2fc0a49836f87a5b89f33d8f56682a2b7d93fc26af6334c214663297848ea1caf0545defa45384a0a40f848da8e7f00e67d45eb19907060159d8d24c193dbe181bd7a9424a2c324f667f3775ae65a38b4822fe45157bce58bb6ec053f1e62ec305f58edf65b8ba65eb699f644b939e1b8d1d793bccaa7069b540c477cfc777a060a59cfd75049ff664d29f5b5acf98a4f62333f53b4e36bc5bca9a34ba1353f339a4f616eda67cc353848bee1f05082e565a45045631f351f4ff79cb0e54d202f4c7eb200189a07f571ed1d1320177511b9bdfc78c8b193223765871838dd753869bf2f6b1fdfbd38ad22d0096d0253674e888cda4d59da85d8689ce8fa1df7091258a8d31d0f4b1ab93431df16f494ef9500bc67960ce8d7978bd01f69c28b0e399cb86da7ddcd6686c19cc0bd065ff140a7f80d6ca65c7f850433f32ba844917d29408f8976913f2051bdf248b6a5444659de8caa4186d83b4c35a5f6d27f2661f55d0bff294b1e42160cf806fe3609c977f80895648479e6cbf6ea7df90ce382e1ba75ee84189222d88931b4dd9e7b10146aeeaf3879edb88f63bd45c10ca89b5c138cbe943219be2ba031a0d19d4dc0904a313c0e0f1ba55857073d22075396b7f64ac3ab80be8c8784ede8c731b58effe553ec6c2b360cc2f58d35279b556bcc374b7fafb110f7f5c146ffacca865cb899d4cda89503c6aa89e988b5ccba02fab904dce1006919ca6d1f76dd43757015ce89fda63029f830c883b4f26b176b852560cc29796016b9575f7cbd92ac111a02b530a05291100eca3cbab7799705274b7d68d1ace37a2e369a53ae97eac8d6a8117c8b2e1092784c75cfcfe317f5b76603b174f96bfa4af30b45a1ed51b66e8e1527d30241b5c3662218634c986e1f0dbd6bf781c0493f1da0b0695272c4a6e380c7540522e1bd2fbb937783e16e9e362d6411135eba92ddb19beb2be8c3d02bc681b6be71bded538eab94e165ca4a9b1058c60bf2101b8c845e19950120868d7eb82b1f27d311713d75a081c9038dcd6111727799b10660d3938f51e6d6f712db47d43c6b352d3a1a9d38742e33bc82bbc114bdc74cf7abd6e985ee56b7ad7e031b183003ea83b06592983feb28698b130e3d4432d5323a2530cb36f0890ee0d39e39755dd88d77963b835a02517994b5150be9f9b2e6e4851fc95f62d5723da8357ec0a85dcc994363399c130f7894a551509f03069df36535ad267f70392389d368e26e58a27aceeb01581d78772fe3c18ffa75f53424405f50fd89cd2b073d9ed5ef4dd5974944478deeeb292f11e57fecbf5dc87d67abc0b72cda0aae13ebd5f63a72a5e6a4fdef06447b5c37b578662bafee3ba96dc4976b8ea15e2fc8204d18e71dc2897916ed32d7339c90a334c8fbc5923f3f9d93340493f56a4071217a1e0736f22c07e6cbf43a806965e350183a399f074a849b9d29739372295981d5e9ce2b1ee58881e86653faa4e4207da8876c4912e5e5fa239d071a3157a5b469409c0aa5f09b6e82f388d407cc53ef61d89e8c05b0a06ad218625027b1423913062c53db0ec3db27661c2590af1dee65e3f754daa02244f9c5c0b52aa6582c773a389404ad816d49cfdc8d8c46245d42273bd1ea5fcf6bdb0add91ac359d3b58142591bddef621dbce853604ed68265d1af725be14e08c1bec4a808e08c8ecd730392f97aa7211be8147966a61ce78547fe042f4ff16220693533c800fa35c544fe91d2d3bffcf8ed19a1bf29164885879a568b70ae8b5a4a5e2071e0d0de1c4c9da32cc6bd9b7624c55e0c54f2d7fe12308f20c7d4e4e2ebbfa0b22ee9b671c125cd2afca3cd6bae0dee3bb762c12140573441d9e4bec891934 + +Params = SHAKE128_W16_H16 +Msg = +PublicKey = 08000008eb5c1ced2a8acc48d44c38763d13d17930ad07691572b3a47c5592c90f8a06e4a42660ce1d5972a7e617be182e21d03e990c13f0c3105464393d5fdd958bd983 +Signature = 000000000000125a24464197533c07bfdb3997618a7ad7c7ec5a4661c56a32a68105337b5f4e496b715be5d6fee41b17a8f2df37e90404272f4be57f828951d416162b949ee89f0ae3228be7ce31fff02b305c9864742e5c8c141465b0fd651b618b40833cb2b9a5fe1dcd998d3dde37af018d185c18fee7fa9c1a97699dc3e4a662a560c61d82682d2f0a89ae6fadf8c436c32e65f11d7dd9ea0a001dbea9f07d97f8e59ed94b0482bcea699858c48c81ce2eed54eb423f5b7123d6fb01dbcd4a45a9910e362f80384a05c104cd444c3b79c50f25b8fdd21abab6087383b7e61f55370983f1962847ff4369cf5063347abedd701cf2491ed5304ac2be20b23f6bda3afd298b2d1b8615d879d0b5e71c495c8ecf1747e46b8dea29a0242473cb5c5bc0542933eaafddfde7dcc92d1ff41b1fa7062893af4b3c230d7c1cd0a05011c7695b259e8b3d229b0616979ac4bda2859a9c003838fabfcabfce3d84621e027a643692844269cd9d5499aca3c2d243025acac0c87b83ff72cbba13e5a07e7bbe0c31cd5e154aa15417a8cd95ad2b42613b3a0e74c1bb7d42af60a2cbf7ad3798d5a60115871163c7147fdf149b291b89d119c04214cd6913e00e0953c55bf094df5682bbfccdf0b1a476af094929e7a05bbce1a221286bcbf50d5f4952b6b591eb8017bbf8cfab70d200a02e9e265953f22c5086c576f9f3f5bdceb6f3b508e13411ee14e5bbe5836b19eb9d7eca74b56b6fa28b4e52d6f08345c0b7e7d27afce847598cd5cc07c3cda08b422b1cda4b617cc03b2869461f10af14162725da1d5d21831f2d769bbed8937d50f2d26822580285feb537372aac72a59839c72d2a76fa59e56dea60e5f9315ca8361e5701a64a528127a5824e2bff9eea76e3912ea83ecd5c49c1c30ded8506defb3ddabce544e57430ecf12d3c5860b9a8515d9d0c7096cc116a044cf4c2b8ed1b79962f0d5aebb56a40829119f91036c63aec99edb99aced6f3b14d96e42deed40310757bf839dd37adbc7903ff4d39e924311b89b30ec2ce3fb0816c016a4ea65a0942af004fd90ed5ad8c10213bba25cf2b4947fd93334413776133ea9b8263107632b53f1707ebf6a672558562d864ee065ce29288f0fc4825dd0d6ff57b2ab87208ed98593513ea1d0bcdea24772b61b927a2ddc72b36cdc4fb62cd8a42e5a7ed74c87aff91ee12ffd8e6abfd9d131dbe9364ff924bc3c229942066cbb651a6e02d561754fe573f4d0dbe56f85599c7e8d7b61fb03f8b30a6f4876c7e60bed3c94c353892e6875634b73e1f518fb0f02d3a9b8022d1076ff72be08e3d8be47a0e15d4477cf33616530f5abb9d034f77959727cd7a17e028c96ecdf0692fbdb3bc4b4d33403f42a0803034fbca578f05ba0751bfb37b57841ed208d2928c3ab83be8d5815bce372f57a779ff353e09458a74cb07326cc144a2e679553427b992640504e27629e42d5d56f461f5a53dd04f0d157f7b2f5ed8f1dfe82642febde172e092d40f24b2bfe409764d077426704f3a26aec5cad13227d1dddd8a397fa76378e7b0586fa9e854347c2022986fedc90c8b21cd4c7c837c42cb79172e795e08d3f760305000e2869a7e26a8609d8bc1a00e9da3534eeb28ba2ae9e48b23bbe87535ad87d114b5f48d25b42609063422db51d093bf66d261a827e1d92d9960b44a551a2c798c60a282a052e6b3a9f3168865f8ccc1e70bae61afc2308e95381dd0f60880206916fd65efbb6ca8d96375559c0811b7cd0d8e2f9032f0317e7148a1903d60922ab0fb76218fd53214a77988c8ae782e55118f73c04c7c554b12df149ebdfd454162b145231d8e92dab7d4cac77bba933f0af94e79a178f3da1a6471786407290ea357453e459857582be19e9c212c3c02e98b6c8e2d44149b569e32005882e38772155ea3e9a85967fea82759b2caca4b49838b44e4837d9441e047f6cd29131c46b27e33418641865c6bdf0495ab575724c500d8120316618da58dcede4791ced4dd4ef7d54dca21dd5373242bf918715838dff41b25d8eb203ea39842c29567ad3883bee174a2f5e3b1eafe1a363e262c4ea834590a64860efe4828907bddcfacc077aeb18d831a7aed79d75832d277508caf5d9bb52f8061a5f5303798376282084a9a94d058bc1bbd6ef59e7a7e72b2a8f503252185d71b787e38bcc6b8e4682691e1d35d322925b9ec954f0931d34406b34200256cad97fbb0b61f9ff02e9f3dd1ac926c5ab17291bd1229a50fd9910b01bc9e3c1a436ea29cdee2cb2e97dc5abc4f77a23d546912aa4d37a88e3d041730faae2cad76aec0b999580cd90934e3253c6890362d4efc6d9f22e94bba1ce853e6cac39e712a5d7777e89ae119b98eaf07fa601ca64e902d4cc3abb32c0543032b93a21fc372d355d98894e85eb0c3af24b102bb5134dfc736c43b34ad6f4bf51fd7bb1bd2f22dd3b7b6b721b62a62967e8a7324da6fc04e2dad5a22df90e0585e99ba6e80a32aa64f170896ce25160e163ef5811451a5ea293ac69f119d273608dd07855281a6277afd92f7ad522958333525973ae31620f3a9331c180082030ea5a4dd45c72944709d36117feec0d5e84fd4e6992daae3043782cc4dfa967a490e99be5b0f4fda47d0990509086b59264e29b4c8d6b0b2af6ec6e1fe82127345a205369e24df2bbf3b33802fcd5f98b532c26286d12ff6fe22c822915d7858709faf4c40b73f9cbeec75d7d64de40b5e87092d93ceb9d56fd8066e1872900dd7277043f733f8c670549de95382e0dea7c3d14841f8ab91ba1fb65246aded467420341890500e68c0c8f2c5d9f51cc1c7837832ffc0a397432f2fd2a1d8bd168d9b5cd6fa7dcdfa8422a1f170b7ffd594c441d88e18e427ed148a8127232b3a9c95bad1ec87f92d65d375c087e4d8761628111642455855f9f56dcd3bf56f77610eb0dc82a6fb287af66a0e848066e1eab783a5a48c70d91e12e8d1bb85f96b02b051b054cabbfd3f8055ffe0c4f79391a571c1ad300f65d1c3ce3b1bdc5882b74b65c1efd43e2fff5c7e649e5b259643cf05efa5510256f8faa64b1e518608a15b26e0e2be2dc4a8d4d77b899bb2c11c2abace3d2bbf5203bf6f42ba66429dc5e5c6f3ecb7cf461d83bae957880dbe952e6277be81a0a7ebd50152bfaddc6d89f8fb68309e94aefc4ae17c2ce5e2817df569f54bc573833145d602913d5124491271cccab45894765902542d3601cc315ff9ed90e01eda465dff20ce3e64df1b257da8a018daf7f716f9cad6eed91e3a31a0577189bd1ef1306fa3af59a8a24baa4941b26c6f04012015f61bbb7e9764e663f8d65bec08411e0b481cfdd7418dedd600227e81aa972964c553d90821e11282ff85dca924fb0d9f160ea72948be55fecd321586a12015f30b5d1556401c5ba0d36651a9a44feb28d4c1b946fab0b9b093825a2d746fcaaa11d95a585e4bd576df37444bac2a4d5c56934df0f66d132910875e59fa398594a062c6bd4d30515c890cefe82ef54d25c5f0e2cc7958ea3623a089f232cd3087fda9c73cf327aabc520db9b73045c6c21f0b6ee1943803c65c401e56af434bf43d0b49e50ff50adaa0502dc0f58cc05c9935d1509d59456538d06a8e937c67fe2ad972a801f1e1aab080e42b23e73b90e6625780318deabd4a05c4fff38bbe6be01fbf9b6723af26f34b06bcd165ce250d8f8b8f00919179961de5e4c03e252d0f000df8def3d44299ad5f1c8f158c9987491a524d091d47127ab11e2d9867a4eb1531eef93238db87d1b125ddd86d9ead8320 + +Params = SHAKE128_W16_H16 +Msg = a2a50241278f92c8ad617c84331ea21c60e92afcf0e48a714ebb75d0120a9d8dd0556840e3acca6c9a86451a0d5be95c2a25ba8331e8ad9d842a1440e90509ffca5ae64ce06a8f5b65dd852b69e8b88735022f520da3e29d99dbab904646d8bf58d3344048f279aeb1669f3277f0ebbbfac2267c2b9ac8b989695974adcb35eff3aedb675eb76339cca31d6a975a2bcb9b37d4e9d89631543df3c970b141c039059a8a7e648c814403cb7c3ab0051c051d1973c8738e6b6539f676b8af827bb3f33ff12bf0b063bded6591818100f70cd396ae573280acfa713675d233c6fd0d2289b7d2f1de03363414bff3f6f4042275b7baf15e3996f75a61b22a583666e0341143560554ba15d889cfd9a589c0b7dd7865a3ae70e40dfa0e0fe35887d2951740728f874caad076fd0b0e8ca4e98b3a02aeffac91a906e3282bf7c5956c96d242aa1135f897a4059c5c85aefedebd17955b8189df68dbc7997ac06c9af18f993fe44e438cdcf2543018028ac893a362c1dd47e155dac60f90050c03031aa8eebb8479c4007fea897e272b049b451183cd9eba34a451c0e1ae3432185ac0b4 +PublicKey = 08000008f99162703baf742f338a4f035fae34595dedb604723992a8369a83bcda4addb05a0568597f274a0e0de7756f92dbd28325a9c63730fc74790b2efb2c3978965c +Signature = 00000000000007acdb208ca2c5910a053e5bc2208f852338b35d12ae4d4555342badefe231cadd7f42b54fdb2cb72755ee7b321fbfda8964171547e0971b7aef0b15ecd5cc44586a6f06b8d54c3a576291bbd89b720c8bd86a740e148a3ddd0b11c66b464c99456d9621c1e74f7c160fe7e78accfbba65b94cafe95ee4c8eed18936dd1842309e277708e8341cd2e8f21974ab1e56ea38b390a791e037a48bb88bd7750180f7e0992dbee53d689481158d3e14703ed6f82e90f6c70104f870bd90f5c9a21b7405e4ca633b46f5c1ad23cead2459b071c8960ae2a181840563b43d16c90e875a85a03fdc73b467dc755c5a1904d0ee78a5f280b0ba1b716548ec86bcbd618bb2b519657ddeb147c46fac45a5ee315abf0a78e9621c502ef42869d58fb862d9ca994ce249fac7226287e7b1499cd58e98d3a48b96cdea71b4d10fe9cc47895adcc930a1bb29e1333261aa2255b3e170fabaea401aca0489ba00d97442dc1eb3e43025de80b9715d2a5e4e9f0c5e4181385644c6e604d81221a269f9cc344ebe25661be277394e417baa8b9499ffe1517cbc34fc02b82ffaa908c2f5cd9e7b1a7c4d915442db2a3ffda8ea28661788193048d1247da9a4697b1d18fd3c828c33fe181d621e83994669cc1f0774ede9beed0dec67d86a4ebcee6871f505d0fe3cdd355f1c8e39826f718b64990f67621be8df590553a4594edaf91b0768083a2ebe6107ea506b1fe976955c24f4b9d23efa80e3b43b5c8cd61a20565e343f09983c02afbdd770c17bd7bb9c2fc6d18b27b5f9d3a8dc5b9bfa553d650059444781346490b98dcf820d08a105365cba43bcdc73eec66af1c475433a72842df86e3703cc1f948d3d98b50e900d94954b5565f70f49ec7e5b014f0ae3123b4e82acf5e7dede1ba50b4fe89ab58ece7959b08718faf65e41211b76ef9c928b7f5751c192bfbbce51d6fba60dbf08f18982e0a23d6b245a1e3325adf40c14100fee397a7b27cbeb946d45fc66793c27686e0cd7f0e1c77f14d8caeaed14e991837b7510558522c83567e2d47c1973452cdea06d4a1167493a95e83b672a05ca6fed5ecdbc3d3beb557b319c08751b7a1a82b7c63cb11c5b0fb651cb10b32b1c3debe5a641e13d72e1dca0a9ae95734f396efa0385849d229d81668cfb2cebdb0c88c7c652a9bd01d701b87e7b5922cd5746a68e1326cf65aea919030e82bae569607508c91850196d232e4451d534c949aa7c51036a73875d8b185cb0b613f4fb33ea3bdfa9573df2ac53261aa3163eeec5542316dda467bd98457b5b97a2e61a97ca6b5572c3ffd22e6fb582f8d82e311af4ad932d2624f9c1b80279082ac8717f476b26c551a5f3aa497b0213bff4506a2c1d43aa852bd09dccdbd4d9abec33c7c507a672460c322f433d6ad61edcb104092175b38f497f4341ea5006098ec6e7e068b7f687f17971666361be525d077c0897b6f6dfd3c7460925764c7bc310433c5252ace61c6b3f7e189a7ec48d586fc1ddc871de0928040e77d6184a33a5d2faac550790d58feb9abdcdad0e3ba2b52b7a90082d331d35f155883961358219811deecec344eec9b653f0c2d911736fcb7d43c8477ed16646b8ad8f6093acabcc260b4aa7e931e4a9942d9be7975cebd9adb70c399c022a522ea5635a9ca251b9ae58eaf2a8bab212bd93bda8d71baabe6319069fcf742fb4b76055b5186828ef6672b576aae00524329169143f7e98d04a92ac6ddf8eee89b94555082e07c534ac492443a158a07bb23b1f52de7a8f5773ecb0281e27485ffe990db32ee487b80fcdd596b5b40c827fd0590e043267c904c4a2a1abfd1fe09ea3bd8ea0411424163c10e3c938a78e818283981e6bb89ca0368d26749f0abab8e7d78a8a66917fd2f6032347b6258faf38426edfc4b15499dca9409f8fd02d1452fc720aca58d39bcc2770d89e9a883d492383481baab96ca29ae4125afffa68d2e142ff887bf1ab0b6d7ee8fdb6de99d14e60a9a9e3fadc1005f63545ded914fd295a08cc6c297b39020bd3bad41fb16af7e6cb1e0594f5d92abd655434762516c9e2ed6230dafe98fd71d2dba4a5e99d03e59c6ebd3bdb59cd1f4c71b0b55f6560b934b903282bee65e3f01df28e846cdc0216d243e16f98fb0470f9894c75cef0b7061fe236d2431cef3069db821e84d4e30307cbe024cb99a8f9bbd62c9019f5481c1b679307078b6af6cbd5614218a66120eaa90f928df4e33e4b6209da1b116603940af8d16b4de473deb89fb6558c571907e54fb527f055a4462e270a53bcead68e222ea75f7299e47224049df371b0581d11bb2e7d5d2fda987c254cd33f771de0f949120263b855fb0830e24cc8dea891a8f3a80a957b0658ba40b44d87c3d1082503f6c7394ad6b1accebb63667737d632ab722ca30a3bd6dd9cc9871f7c5380cdaca51087e64128630bbe2f86964c57e88899976761d93629cde170a21d0e55573436518b490701589f68b3a48832583c7c7860f365b835c5a07fa45afdafcd0954585e826f9071b811033503e8bd21382787eec7ca6974ef08a28980427dbbba58f00cb6a1d7d83e507d9cadef1fa6200fa0786a80a0dfda94c5d2631330b3e8e9459e56bf0554399b58ffdcc13f51c788287a3d856bd8b6fd1692c0bf70b00b633c0297cae4c9047373e6ae1440492f751492f06c4f2eaa4a396ef3e3c6d261af455d213eaeb27b657cdf0432cfde7995c6f35578bf96971c4e423144f4feb8471074479768cfa4ce1b061ca3f3767c62f7e0a8c78861d3d5c9f3262a7f2aa6be6eb5f3677d63242e605006719e1b0f1cc6c0c0e56c9d88c551d2af4ef1a44c273edd660ba3c69e6313a132e3d37a3b300e916fd2c3f06aa8d4f4fb756102f84d96efef9b86c5d8532afd65436c3016028ff2a74f4d25a9b52a1a418923a0eb0f008dcfce01057c1b4209b25d0786b97cd558d5c033bb10929721b7e28353eb8e58b304190de72ff1eff7daf5bc921e43ac65c87512c9e4a32f99007edee0d43c713a9024f50fac0ab99ed2e558443434463935585169647aad5a7d2a7fd9fb3a98dc5c0b935e2debbbb27bffbcf10301f8897b64a1764551ce0d10260e20b35715a99264da9edab72bc20a0d1e4e47025629ca51fc599ffe2059bd64093ca8e26838b8e58a800fe698ac3dfd992b514f29e5e0334363316326f4b931c1268cb39036645e5938613847c4b981fd6795234cb254acaa22596f0d1df9c9b6e45fcab6a6d56236ff1e9a01cb94cc9f6d2fe5cf89ac3126b36a34eac3e09d5495137972cccb691f2e70be4a1b76039637fc0c5f1416c24418fa5cfe28cb34e6be8c4a1a249bb15aba9dd911f10ff57612a360c34afa3ffb5620562de640d586b2ca5e5983e878257eef9844bf7293e1999b5bea0ba46a39a105c381ce5f415526caa1252ef797bc4617bb58fac8e79f576384cfc23d41c8947d0db473f95b535847409b7a93ab9c640d6ad9491cbc3c8240075465a75c06af546f67ae8591fb5a92d798f7c2b5e045d1b1d8a3b06b683ce556c03092a93117116b74520c36b1170f4f7684b314e1b3c66969fae2571ec7bf9cfbcbb4ea983d1ae30de486235f68e542ecf06f5da8fd6d4dd80460f4be917ab2179e57bd2505d79d4b77755e9cd631b7ae493ed4f4646330b4d5b4c24204fe7faa424a4d6c317adf796ff098b32d805568254410448592e961db62ff26101e53e5fa39dd0d4e3f83e44a92a5c6de4703f99b7e6bc43e15ec957bd5264a2511cd9b1813c93a587ee5c19b1882bab7e27d19de9cca + +Params = SHAKE128_W16_H20 +Msg = +PublicKey = 09000009cfc05b12d6049d4e95bd5ac29c8f7f41bcc09a65c89bf695383560451ce52e31e7bcd7956f662181d3acd7184b66e0590c8962aeeb37665744b41a61251c5a83 +Signature = 0000000000060358da6c1e698a91559e53a858b2d18e0e71c6640a71dbbf68777ec20101afc866b02f42c269ab6ca74b05969cc8b44301d1f35f52eae96a397094b6130c3a50cdf13d76f10a1ca7b9105edce281470b8de4b41f9a5917d83cce40a09946cee0f0ddddb86ab4225c1104bde1875e39af46c7660b9789c734d00076a38cc5631b25bce5a90a2d80979573579f89d0c9b733b34611b2a09b1f91b5a6a81de3a6cb2d966e7fa3a273e497c52d92dd814565a36ebe70657972847baf6dc6fc276d24b891006acab914a5e74340f7077292bc3c32bfdf62ef8cc4d36c0ab2e20a918e68c170852fb0ea8a38e6bca1f08768ca97217de93113607bb7c56c7642e5c44f75e09b250c8936d8561bf405ac37c11cc7f63132b108176e83c09e0eb2edd76c86555b025f0ac3128405a00a70952e2262deb354a17423286f6963050e62f8daee25a050167b3bed7bc0d0f063891caea67d0566215dfb8e0410776ae611a98c519e2682d258f62bd79d8472a7e3a9cab486bb2875981e5ece135e7bf2ab2f7fb337a485b560c8852c136570b9026366b8d814e3719bd9f0b9ee978107feca9335bc85a12d6863ebcd41dd397e340f72cf4006bc250784be796d6a8299bd3ff4a1fcefd7667bac1a1a3d161708f4070bb3ec76f9456d1ac8d5d10d48394988aff68c46cbdc88bfd90c8fe5bd9ddcb661971222529d40db69a411a5605e939f8fc62cf116ca2a84c5f9531ebb25fac28000bdbc39b85c5cb1438e34b4060bf993a57c7a120cac59f00233cbb1f8eb83d64e2c8839526f41b3f5f7f4d536b8253892c4b6be6936785cec65840bf48f62fd5e0a68eaac6da547512d67e0d16ad97d9bd7a0b9ede0a7a284992e0d4455127e5321701ea56eee2ee4367a6e04e592fd1cb838a49e5e266740d6825adafc36709415b161279ea559000eb95ec5b204ba8c8ab1033612a50af64a3847a806851b1b721cd9997ee1c7c5fcf62ae1ee3864e990e4626e3689f4e85233de2f8bb2b9f275e62af1a31d708997d236b603f5b451009284d34237fad75fe5d31df139c5d4a640d2c636b55317b763e42c9eae72b4fbd851ac35b3bd6eb1920e311d67650c9f8ae45c9ab2937967c2e8aac1fd9e31867e8bf6d1227a98bbceda17884fb6d6015c5af5c1074d955416df1bcc8774c64f66f602d8729e40aa014814d8df6a6703a5bc0a3c17daeb4dbc24e63369dd70c8ec7d504f1cc4b2d75d0e74d3826163630bdff3bf28ec57a518c8694cc75582e977b674cf69649453fcb31b1151e4791d180b211c0b2a4e142a838aeca4cc61e2ecd93a0037ccab1e7d40ae76541c24d1bacfe3673f4e2a9f286f04eb1b81bba0045b718386c4c0c86d027ec6cf9ea1d871f4d850a726d61b3f0d437e8a847d6cd7281ea9b8be9131c1a460e32cdb5f5847232115e6916e7d938b3cdf4cd6e08c2fc69966f637e10735c79a09e8b1c82fe3173ce3a94911552324b01655381e5fc699a7f9761d49f8d131683c7581036c80281313a46f8ce1fdba72f57944a48d422ff196e4720add4f92560313f3f8fd562fbb14b3b3c79a8d57f3c8cb28b95f33b7eeed28d0fbf0fbf83cf881542554fcc0d41dfa432ef067b553c97d9c96e5f004fe37e5250628576d016fa3f52837e6ec988c6ac960dcf496ebe3b2cd3bcdf9ab9ae3efbe417b44baba3bcf0181fdbe8bf81934521a56f96c7b8ca0d0625f58261959d27a25e5d55ec5a490c0092bce2da3d1b8a0535e85936d39287229ce03f4b1e56e0f04f4206534960955e8306168d824dc33581eb28cffda119e2b5c048cc37540b6e2b716e12c0c59f885238206b62d8bc150f2c298461a8857e0260203886ea445bdcb80b6961b619df28de9e603ac13c625b64e29b04caf370b6f3ff039cafd05c91a4049fb0c383643c9eca8d140b1a2b037192b3160211cee772ba578559968b752a4dddf71b671ee80b0050c9f805bc3d46ec3e4828e3f8acfa832a8df17e87807ebdb76609c4597cc3837bf224ea5065d4580dd59bb0d1b07804a0f10e00ecc297c72f5f0df90c55432b6cacff38be8bf66095ce255e722a15b6cf454932218b9f96c28d5bf78341597373f3c8f84588c32a5dd5e0b3e84e5ab9b67880bcc9f5beb6e1153acfd698b10d98507a6644d540d70ced90a8bcb2f788182d8538a80a339d95640befdfdc67539196007601678258d4099d8bc7bf276e7391e000331614bf98bd4831e0d5395407cf37fab701108c28ccd981f8fb15515dc07e1c15960b978ed3cde39e9e0320eb5e6738b1645f396d4d15a58ac8a046075903f87ead2f12738379ba492bc659d3239cef36cf6da307906e82ecb1dc575f24457a304b615999fe99f940ca73ad3568e0309417b3f1e7b71335824d2a5368574bce0f6492052cb72db005dcf556e7df2b5ed2aafa649b08b122b5a279a6bf19d7dd10fcac93c01157d2cc476791a961f585bf6e7f418459c415fb3c2a9196d046192000b23997eda4d8140f2cb47f50de85d25983bc829669922bb3f292a45237cecf6edf827c9bb64ca47703870e422e74f5da471f3c1639f0a39dbd737059b96aec190b257617c8a4c90d382a9817ec462f566762b0be5ebc165c843fe02cf0e960d3111d1d8f143e720becb370bf559aab961347c72201d83134ba36f965dace34c987da634562d0ed0f58fc08c6fbfb99890cf60917e6ce387906e00f1db0878916d92f4fe11b18da4353ce355169b619a7a2dcd346ffe42a57d4bb4ce4729ce145a7445d2b0209dbc10baccc73d2e4f5e972c7de655efd26825f5c4a8584a6b16d8b1b3d51e1344c0978697cbb3abbd37a609234ef21f9f61214cc7e3c5dcfd83f30d4484ca52f061cfbc65f6b64e3e0b1d4939d7806457c54d7624e3afb63a1f7944209ddbc20b1b6592e13bcc76a86c55ecea4f0074ece524e34665d6e8018af658eaaa689c32de77b5ab74c30e65642dc3e1e2b4073e96c76e57d6d316c67231e2eeb2ec9b0c56d4295e2c323054e7cd6876448e739c662a79f2e43f3e5f92fd0e05ae40aaa0bf7778c86cdd65c941c3db996f7c76eaa1d7fc071bf16ea5f63504623372adf6b70d359528b6ca28c2bea4f4aa1ed3c2d65c5d3e2e0919b1b7301d272fb12e16c5c1efeedc4c9881aa408a24921a669f399dd396981a4540d27f899a8b7d70b5be968ab3a9f2d16a9a7d1f502099a312aa1bc39f2cce7d55af7d808204d94f787071adb68ccc387c2e1dc2011428bed1711b9ed81bf691629e532583f1b84d5631e3a85e59b70e9b0d9e22fcfe7a0a437e8e5aae93c527b59d2722fd3366d2ce4c26ea6741abdc8f2be8791cfe4a811f270b52429d4163bb02f12eb98602a23a46d65c433e2ad9709ef29096317aea7b5f3b4fbb44120aae5d31e21bd08b009d3112a448ddedb17b91250e1517925e90d4ff050348d06ee3cd6e6bcbe9200bebcd274514e9b00bbf25842643327adc7654603a3432bbe5fb7f20b94d1a96b02127b1dc2e084c12967f61192095737648d8d15db20136db5e8ef427a52983d8e51a2fe36fea426f89800c31fc5591bbb4774403b95978a1812da62b6ee5a6b92b65b097dc4a1ee3df1013aa7b868ba5a4c44f2f4aaaf39a8f96a3a879464cae45a05cb9010ea6e288764ba5c8a6a6c9d50e055c2bd98998b5fc151e2cc17384b2c5dc5d75d3720e63eca81f86baa6a3bf5c57e45c97c4f18c1078c6664284431e09c6805be61ff0efe0684f5fa6960b526f5e838cc1fc63b0fe15c4c4170b44946de18357f9242d8b4d8a4253abe43884c529a440c1a5d1fb667a0ee286e0e84689cb1b2b820153326f0d0a88b5f1aaf09b37bed792d4524e1866a19f9260d1f318c0ba96e4548712356dde787d2c60589ac1edff8f716f584ceda86317f760b364c5812c77edc3b51aa1515d4c7e66d5fb59175a5380470a71dc429c42e2583967aae8eb622d60b79a71963c4f0c865bd1be + +Params = SHAKE128_W16_H20 +Msg = a2a50241278f92c8ad617c84331ea21c60e92afcf0e48a714ebb75d0120a9d8dd0556840e3acca6c9a86451a0d5be95c2a25ba8331e8ad9d842a1440e90509ffca5ae64ce06a8f5b65dd852b69e8b88735022f520da3e29d99dbab904646d8bf58d3344048f279aeb1669f3277f0ebbbfac2267c2b9ac8b989695974adcb35eff3aedb675eb76339cca31d6a975a2bcb9b37d4e9d89631543df3c970b141c039059a8a7e648c814403cb7c3ab0051c051d1973c8738e6b6539f676b8af827bb3f33ff12bf0b063bded6591818100f70cd396ae573280acfa713675d233c6fd0d2289b7d2f1de03363414bff3f6f4042275b7baf15e3996f75a61b22a583666e0341143560554ba15d889cfd9a589c0b7dd7865a3ae70e40dfa0e0fe35887d2951740728f874caad076fd0b0e8ca4e98b3a02aeffac91a906e3282bf7c5956c96d242aa1135f897a4059c5c85aefedebd17955b8189df68dbc7997ac06c9af18f993fe44e438cdcf2543018028ac893a362c1dd47e155dac60f90050c03031aa8eebb8479c4007fea897e272b049b451183cd9eba34a451c0e1ae3432185ac0b4 +PublicKey = 09000009739e954dd6737ce9b7e71b7169afeaf1230a09892455a8e8b4149877fb3c1061ae8f7d135816276cbd8b3540f7efe80c9d91b37d0303b9c8d748576f62b391f9 +Signature = 000000000001d1f26d26aa5903013f34ee25652c4b0bbcead8c72bc5e480b9f9ffd740689d0340ef0d9b3b52d41bfb5f53a6054d63ebd9cff5a3efc4d09dcc35f56806a0b6ce490ca923578f759e8790c04fac2a99fcc57fa8dfb8e575b477dad0696cc3cc13f6e6c274cce4763ad86b102ea2a57d25fd06dd7fb3346e9b47b11203afc733ea22a0287e073636d51889a8d94736536853a9ab3d3e21921b83953aa6e931ac88907bd5783831d4154cd8aa8f639b17bc49b2775d3598f60953502e91bf0f87e607c7c81677a3debd50d9acb43b8971c288a4fb935ab3a61b16025d0a433c47d126fc156ea7ef03397dbadfba937b98af36abe868d291ec7364afff24836ca4dc40481adb0c9b80da9d55f30168e4a553df56990d19f5a783823ffa717e46cc10d2d97e2e9a9ed9926a9b81758af5aab76ee68b8777a48cd70d6793478450c53d839ce688cbbcdec81e39ff60698c8f03b68be6c0e8c4b7eee93c7bd692e0f5ab4b8f40f1e0a2fd51d59e96a53d0c856cded47d844452220d1738d18e6425ffff109ad607b1fefca857c06de47f01a4e73b3815f7af332fd8cac5739d2e87c3a13ea1f58f21c13edea8c2175f6414aa8d56915530a31fc4856e1c11ec4d8ec38b231b08f6e4b759aaf19234515560e46485730fb1cec39f4185eda8f52b0a0e558bad3ea89ca728dc279228f3b5a6807aaf598397f6fffddfb22444b6f184875e0e5748a0c1b4454e16ed0d56c46dc12d436cc52b1d2aa67e20bac07f1a778eb6ca433bce5de95ef031aeb46d2b196cbc249f6e1f0585708c3142c0930025a50ab1d6f20dbdacdfd688d87e0b93d2d3705d0a66844ce14441b571fa52b0267f8969e5173551b599f041288d014bf465f41260617f9cb48ba22c60050530d9eed172cc99f90969fb3760ef2e9cac8952fedcffe800a807695865e746451d9f94465cf0655168bee150f89a9c58160d487b9185afe720c9d6c2dc07dab62bfc60fb80dbd7717177c31141930c97485ab9b374eeec4ece18f0d88fcdc47ca8da6d82df33ac46a86c89e31b7f5e0f04c64bc88c7631b08e857b8c39a215852d7cf780243ce568657f062878132578e338969bd3fee092bcd72865c9a6cd5921ad50796dd89ac76deda9f2547c448d534fde5b90c6c412662c7e5e3c74b0853f1eaae3c060b274eea70474fa5dc1858eee6aa2e8de2448b6555e7f081ad6c0f4c82d0ce6bdabc24261b6a6ea3c808d3da1469c02650af48c12a1551977c7fc625e8a6f10e60a99f4fb46c8e31203b79241e94d1750603e5974246b067e806ea466f2c0eda1f92875e3f7fef0408c37229d2a4c0d4257e41ffb2a67c842aced6e21fbf1a937dbb7deabf150777013b0e81b3055ad3158be38e6c7c79d03dc18815fd7712205567c204f54b1fdf7ac9808359a65838056a757d05443ee6cafb23e6244e5d4026ea968ba772ecf1b16a0b6f1a6e0252a4c04eb9ffcb88aaec9ff687b8b4ef4c984d31b572b61fa4265df6b0e37e5187805ae496b9b1d0a1d62e22c31b628ae6a922ca2b0cfae097f86496cfd294f6ef704b0c94cc13195d149692ae4698e9c3d7bce35535f305dd7ab39f474eb497a1ad65865a915431b645a7fd62ccebf9aa7d0df5ca034a99a368746b8d86db8f0d3aafdb0f07ab8d59159dee81f916cd227ff3530628601ae8942be49287e6259cc701b8eb83353226fe523dfeb789dd3a4a4dd93a48e431700a7203208b6ee0984f7176f8d151f1cf79b36fe767b560b7c07fb553cdf928c940563522e04fa46bdb3cb5ac4067c0288932f674571439e570ea2eb05239289535586b7bc355c9f92c3fe4a1f5785a9ec5c1b1e1577e842dd93bebcc510c5c8f36a402f40476900b7a80f9f71bcf51a90a4d868f477d7458ccfb8902b13ba9556fdd553cced8138b5e470fa473ed0cc0e6b208111f21b48252673713c0ae86ef982fb184dca2f018a9328d2a0bd37a28ea2e73d65a2e30c4f659317348d8f7c488ff4d53b2feb71b88b228f5946015658239a64fdb93004118c0f193f12ad608ac2e245346ad9c89fe43f7316f377291c5f9d2b5476c3bcdfe76faedf3a6b8eb52e0234f09c2f285bb10259c9f4162a74ff0605fb91bd2d4dcd3f120b25ba288354f6721b479d4308354f751aea35fe4951622e9e84fafd3f5f6046c877caeaff15685a73c1e9dbfa435bf6301f2bb899f88564e1549beee24c6be52b2d89aa2710f02e6bd00260121d0c88a7dc8fc7e6b8e0740d4ddf8a325a5fa78bf95874fa22aa44006b6bfd5e84605b78ff0190a1d78d38150baaea990184dc39f29df4b3c3cfd613b3ec06a414c0f639f604da82303cfe9522a54969a6cc6278a6d10130f32a6d1ab2313a803d6986d6e849cff1b8fc997172eb57f06e18179debfe4c8c79f572fd9d56f26b35241e9bcc375a5ffee6ecf61a5d446b37b2ad964905d64a8622e8201e1a53d098269f1d7598d5c915061dc2a5870c08dbd29e01472921fc37927c0e79443384b71ed2eb8abf4d0e980749c34578984fed9fb7419896572e4f93facefd3c81081e4d10c0011340a4a5fa68f9aff536059c89ce03689759255e0e5687ea911ae065dc14c2526416d25a08e2f8c76e2bfe01b7ab932174b57b237bbed5ba768b5c5c61718f87f7040767e4fa57f8c311fe6394fbf8c73662ae4d490a1410dffc87eb6e902c311916c63e111e28ae36ed264b69e459bf6710993aaa178c8158fce5df529036d3bfb21c62c3d1a6ac350126fa9405eca2230363367dca0a1dd49667355ba434cd55131c03674f3a37f88d4210294e6dc346bf159ac2f28443d11396b4df1f2d033491e5a89baf50b12cf87caa33e51a132b91a0f60bb9d58f29d337e8213e4aa5afe0c8dd712a270a96f9cf681026c2f00c5454e0fa6bd2034c39a872b2fea98b1b822b73faba81df9d141eb13822ebdf270764aa350fdf3cd9a40a77c2e25c1e7a653dafee4c19f08adebe387afd250e0da4024c2fb4539e78f62b8deba0bffbbbef3ef09b9cc3196d51ebf00414c461f059abad380343cf5a303735520253561bb6ed2f6a8542cb64a1af0a4361653550c4b1559c80354fc761020b10e12726dc626d46bddab669f6015d83b097287f3ad7486249a00ff88cef0c2c1920839b6e0bf45b467d2fec088719b12af58065aafa997072cce3fae6c6b2d27bf9ecae46d915d3dbfced5b5906b346810ca8fd9006b4b80b2bbad9ce9a7287ec0c0de3875543471f46e08ddd8222de2a3075783e0c315f09e3f01ea6b2a155cba8a0a9bf41c816f32d9792034b1461a4e3df1331a461bd67ceb89bd8585c31c7fcb2395092bc1c81929a1baa836709f0a1480256f088fb10916203bf1caab7feccb2a72b0bda774125fc1a891b88f2cbb99b054b1670dbf81010b418a263bd170e2db3fb2bf0acef94c11831086d297de6fe4154013e07e58c36fe0c1478ef04d8e4c00df9e48ef6baff31210d014c79e021c9ec55c8c4300ee359cf01754bbf707e7af4d908e0043df9140f1107886e35df1e89c44603693bf39c6eb1ba0074db62d698751d96887e60eea12a31609bef808e8ffcfc4614c3e6622270f8bfea08cd81aa7d7e993d9eaf5ff3b039ef5681a15f9a3777fda9d0669a1e097d55e6f98ff37ac08e93c0c0036179bb60a9a9e4b644b7860daf75f248feac6c093e492665b563e277a32f1e3d20927d0380a0ee3448c22015acbd644ee6e1705393fc7b1191de5d56a076b7b7ee2060b870f6689b0e31162974a7560fe139a0e104187ee4024621726935b0b85d6f5e5e05b65c963a69cf5ec3146570452771befc72fd30ecec2eca69250805484125a58684c92dd5421b57b4130cf52785f3868f656c8ca498f3d301013be5270a634a17ba4096ed142e0ab7e1efc30f9e797636797709d7b6d7876c130899f2d8694bc6cfafd38960eabd6f690e79ad445201bdb8d4da828d0970eb0bd7bb8494a4c8 + +Params = SHAKE256_W16_H10 +Msg = +PublicKey = 0a00000ad2b53ac8ce33ed27619c2eb882647d67c1316b58d2dfbedeeeacae1e60ad45f420716dddbb242060402770ec79837988bb1e8ad03432c287a0b1338f0be46539fcd0050fd05552b9ce10cc2429665d62b3155a530199303a0b0e5bc36035e2a0cdb800d5c497985c78d30c25dc47130f142e317376a5ae0b44fcf4e8be4623d4 +Signature = 0000000000000183cd58425b3a4561a1b555ebacb7ed552f988b3dcbf63ee35b9b4aaab49255c62f87ec233218d25cdf59b7a4555dc8bdb44267228c289fee1bb0256be44aaa69963609340c93e2407f411dca5e57a12a36e3d1cc4e8cce8644e367043d8bf3793ddda1d6fed0068b8fedb218cde1eabe4a6d0bdbd8ed3150fa068e30e97a4808b3ce4c9177b756b020bbbce8271452bec8a6b5154ad68ead8dd87769ca3f8122755fde48cb02b909eac5470f8140c6099bbf41eb707185ca40fd5022e3f2770bf548be96e7867ac3593ac93f504d8e71f354d3f33d9d3fed67106b1741eacb88f82f2d1c5b57a1f4e3e7fd494bd19bdf217d5dc6f896f30ccdd0801171960747842e8a60b445cca7c5b59427a5337a37aebaab470564d3221239005e7762ad33a624ae34bcb02d56b751ca40b9abd166dc2894ba5834b0c3178fd3a5243abd500fd9dc5cf50f399611e8b20384b7b1ddd598fc52067e9f366642c739c0a20f5784d594a90d848bdf6d1194ba9e4421345b31e3ebb67f74a48a5056e6bde1faa6d0cd25082abd8aa20f58f91cda94246addc42d100928df9ca51da7990d898191c10cac241846434a54b50b6e8652e3563e128734a8ca1dbd08253bca799fcc81fcaf9f2312fe50e530e746ed4c41c861a57386b4f4b1efa2f095c665f20e30782236abd3c8c2a9a13267dde855a85754bf5dcb5c4b192ce4b4ffb60a282747fec64782bf05ae1d5cfcf834dbd5018d2d31e4094a75df11276cea006807c9fd66d0189f11fe4e9959390279fc50a699f568c70f5d40beb61d6403fe7db6b1584213748e800a0061daf2ddc36b491e745b7ea16b1059ae40d28347f7511f2faf01437b520d4a6cdf92e38d793dd84c160c1bc13c0de32e55c97948fb729256d0ed3fe24aad92c78bc2f89336cc52c4b12390ce19b0a6831c3381af6ba415ed7fa9d34d0009f5e9bb3c2a1aa1908b3cd0102930fc8571d09db3a7783da2da75215211fd7ea03e275fd83fede2e167182beab9601381ce20ed806f2de93379561b78e58802008d3c5042f2d8376f7e3bfb0573e9bf5e679cab7f67cfc5c1556aa6bdf67fb6818c3288255567c6dbd1cdf0c3159879873853408fc727ab32161dfe942b8e6d5f713ea947869eefc1166496e0c71bb75a3965ecb72454810bc67ca2ae0169ccc5092fcc6e0050c3ce33cdc10ae1cd60343c273e6703c29a339d88c34cb5eaba8dfe2c798dcd43ca34f52ba51abbd186fe6360bcfbe9ba06fdf3b2dfd3bf98c1ec08ed1af837ed528fb15a0f1337301fdea7dc43af29ee2f3e383377379d8dca37b02428fe7750d3e579bbf028b11235c0d672ca9e3ac07acbddd2f656f9f59533a9184d1f4bfc8abd4f93373f41ef92c9978d107fc9f6056bd169f0638cef9074eb6bb4801c265d7aafadc96dc9fbc843a2cff9a517bbd54fccca8eae4648bb29d0569632c38cea57ef14d5e1ff86b648637e572df679dd11804db43c707ae3e1a00c61126a4c7adb203601b14a75819f2332c8aaf1f47280c796072839476b3f09c2839234f8ce8e1c85124641f146e0ff2ee44745bdb6519124c6657e81d11eba406daff6656f64d8983ebab9a622365cc4aeed786e777ee9b91d9a333b85d5818b905c82e1f4a8bd2953880466bb8721393e224c0bf38b0745287566d89cfb91b14ac39d74133c1c5768e4db8025fd43659cd6deb22906290e203bc0df43c3877860718e3bc07e5b33adcf39a74c1d047b1463d974c56ad79c1aaff24fd44e1baca40cfa7b84ce76781e380facd8ddb8b567689225d94c26368bf31e68e39dd8d260c1548e377b85d016ba805237244f3296aed82f2f169628cda21ba653833d23c53560f9adb9c4f8e349140a713331f2af5ce401f1c77e41f171893144c123565e2426c2c91a88dc203ea9df1599ef36bd7eaa70fb48fbb4badd2bad79c9d22b75bb12cc68eea401a77f887a989ac18aa73f43b7f2800d3d37ff36c24be8107abf4ebbfae7c4cda1e916fac67c2562075b6f5f12692355526f19604da39925795a2909eb9e84929d55344db69c499e232858508cd9bb0a679ae2eba273bff60a460b4f487c15299bd44b4c26ed355f321be00b428f8ff959cbd2f39457300473fab91947774b3136576f94ae22492e65d47907b65e756a8fa72e1dc45c0ee3d4431b6f6b36e60d6fb135f3391ea2b9890c19b366fb46828b2e14a0b6ca6a9194acddc3c43e13a585f180758f8e3da3974f736403c9891e29f456ec0e8fb1881e88d7aa5bb52467b33ef7fcbff30ebd81a0c78e1e2ca582df5df7b16bad5a6a99a16f400a117d69622d85cf1ba3c7a6cbfb568e6f435a51872777f2d18f1f28f45873ad46679aa278ea1854571d584ddd385368fe78dc1d0939fe310cca2ac9bcb4e879ddfd38f1424ff994fdbfe051e41c412bd270dddbf42d3c2f3c5057080f7534edcb84414b2718cd57fab7fb9976e36726bb3c540e8881d003a04fd025ccdb46a6123cbc6961c2be3e2dc44c58a3bb4873556cf267352131eb8317b915a902a1c88b27a67ff1f4deab16c123fb70b76c2def7af4039eb3231955ac787fd71398902c64eb86c84872e4f1aaa6abff52fd62a9d28e171e137c8bc2b813595e1b08cf07145de1f0125adb1e64a369f266264736ae284df25fad957e99680a492b5692a35cb1702f44e22fe11dd4744dc802bf81aa5e1fc0513acbd94b7873e221ead94c379493486e183f07f204703167283271f2d2175e5f2f11e7d41036114fc3542d08abbda4d0fbcd920ea8813f8764d981377cd49fdf78255e6a27f8e045ad85502872bbd8ecda63229af3e7080ba7cae275bcf3f0194d1640365c7b2e49b985de0ff098a46f29f9323b39904985ceb77ec4c871c92763e8c4ade1b6842a5eeec626743818528b427bee2dcd0c7a8872cf180da5940b23ee6d4625c5c2de3bcdbab182d69996da3b2ac2ad0c51a6a7586d134ee4df49c28249991dc4357cddd43820284ca9aa8f64772218e008a0483d7694fb3aa7269495347f3868ea76c9b92058af04cfe88a095e78ef2333a1bbd2498195e1b992f5b777b7e1192809a90fc094dc9b35e2c0f15bb313810e687e3a5f2408c790dec22b9b423d8e3b2d71df7e541b2baa8e28e28985fd5644a23a46a0d9b1c76b2c93e72167e871a53942ef34ec712f344de782762acc6d736b3bfc452492eed34118d1b3e338c834cb5a01d23ca1723198493c22c0d54c303c6b18a55420b8e828eac77d025217ded1ca035d74bd0b727c15b36fa4c0c5694ba6c5f27f79a8fc4e50d47caafac76c7e73e5af4f7e6e117db30fb248cdeeaceef08c9b1ca84ce9726ead5f1c46032bb9e0c1ae7be8d6dc479e36a2a688941343630dd9f21585dc5d0d997322ce19a910598afb276d0c4bb718ff46cd7093a65ddef754e4e26a70bf9ac69d31f3dda1220b66d6afb93f711930e7e4bea37452eb4692ca05230cc243f66343eade85fd581d982131d3df02555ec479a127f55a8f90facd3546b38f7d6eacb92715830fa5c645068e6b0405df8c0abcdbe34aba4c6b90182bf46bde5d08a45612fc79a1645494be4e1fd82087d5720ef63f44652e666388dc85359865392acd0f224fb4c6fd12debe754a4c87d1ea81a6987d8abce9404e501214eebe762536fe9461d5d62f3e5dc073f48bf2e285284f05bb6ca4579e8e4c9d61e6b69d54e4e3e8f4e0759c312509728133eb46482f5404492680e7c6fdc3094a622141f7f9e305a78219c07b50ae79ad952147ca5e6c539413f18949ea221eeac7c0805456dd5b78ef83abd5d8247f5e16f6ed13ac23d258ce79644f15bcd81a4ec93dc3ca1ef7b9ed88779b65173b92985119e30eefbf3c20ca232c1ccbd8aac52701be949453e113f1c8e2c6f0ee600f05d714755a6eb52e7124515e6c3124cd61c2700ce11f927dd03407f5a811be554aede8470e0215f2de91922268a10c471f158a51c7693e3db66f57a8ad27453c61a0da009dad99e7a89c8a1eb282fa213de46cdca2d8e71513e0f728df2f6e6e6511e7274ddef704e8a5f0f163311ade5499d0c8eff4bb3531d7dce7643dbfd2cdf07c6fbacad58dfd3a3a0f566a9b9e27c5735bcd3931d6ba446e6c74e79248e2fbe9d3f52758e029c306064d8e75d0c084b27bb5cc1cff26181dc3c857d873a01bfee14690c61e6f7beaa7e4058983d1ef1912db0c4254716c5d0c96b821ec2d006c0f82c09af9ec29bb183c6ccbe34796b8264ff9c66394bd49c8d54f8c22ecc8a07a570e9b1bf28aa646b5f8783a12cd93e0e92ae6fb7441403551ff5ced3a623233c5c21150e955e817f39c818cd1c822353fb74ea5644f9de4a31af34f56ac4f2e92b912a794912a5a1ea37adc607152c6ef99e6b8f3a4322f52d82e2267f6384c3f8dede98a526833ee50af70db9dd440084363287193de8696b5532845c32e9c975b6b2518154aaaa4fc26bdae657d57ce6df594ddee3f02056f5213023752355469d1fae68a940e51840efaaf46cfeaf27214c29054c0b39dd5f80e7e5319eb4f88cd5daed672b39aa5a474469d09f815c72fc9ed1235191fb04480bbbee635b513cce6eb68f2c0ea70ca3dc40b4472d500176f7d19ecd5d1ccf65c8dc2d09cbeb3e6108e76b9c3483d33d28934000315f3ce1fcbab3573f01b496e1cccb373b53adc8e73a0ad3d47caca539c1c5ba049de4f3880b03fb3a4ae43774cdbd7417c81b244aab0204579b819e3f2b4a88e28a21b999b7308fb0089794417af90a94534c0eb2ecef77f54ebb96834aff34654d9034233d16b1e3b8c2d1204d1f87ddab1f5e31c46464c032ca7583f8f8a2858043b012aebecec418859aa5626cc05b1eb6a93d30272e5964ebe4c09dbc344cea168a3647898d27d147c4596b111dd19d9055ec35f844669ebe304a16a9cac6467c7b5470726c68c512b877c022dab1ec4b1e1bf51f9f7d86567f80d447b646b60cf46a1e93fb544efefb939c4e3a6a96c9f6261db6d69da5a925f4acb92cfc3a974248d6239bef68e19bbc469b41d336deacbfb26ea356eb524c7e1c41b3abd99551f849b099c0016d73c328bc1556d6216ec2bd17daa88887b6590015af3ef21fbe12e3bf9e1eac71735a8765ef514e13eb75d6536f8feb661b707e5673cfe87489f90d4ce68ba7f7d978398859160c46128a7bb7027932dc98dd29a944f112b634075243da787796db7e2bcceae26ea162ce18a64e900dde5aba18272828d13c49bf56b66a798c0651efcf30c9d982ed977aea081e9c279b15dc1d110c3f034ff2173b8129b5980ffc17054bbeb9bcca5d31625a4cac64972bccb7d334f7e3dd39d9d8f7abb0110bb594742dad43bb4366e21582cf4153ed21298b875bafaca790944e2ea83cdcc8c732f0b662c6d27854251efa89c2dd9fbc86e8ade3ec7920b482cd7239e8126dc193f29f97799a73f2ebcb530803b32c2d8e09e01584fa5ad547cf9313b9ab8472a36393a7541ade169ce751bfb965b064ed98d0ed0e3f0eaa2e4458841c72120bc08dec2cc7bc22f8c6f78565d3febecbb5aa352a1ae0d6e4cb57c0784e03ac4417c21d23681dd05fde009fa6f54a2f4b0be253d95bf60abbcb1977958d0a95b297e4aac18f935058d4991df72f455f34429771710e048886fbd8c7299db2cd2643452ff791e09dcf3fe4e757231fc0be8951bd9dc364778e9855bf3eedcfa20b09da1d79ceabdaee5d6a7d48842d8065ad0896398a8ffb5f3a6f89b85dc298dc96652fd3354d57eb9b32d94c983f1d2969391faef0c4dc7ea1ed6215cfa8f0a46ae58fb0f73f0cfeae683ade511d4ab0dde4414fff42dc187c78db262a40f200b9d21a0686ab28b2fa254a80cd57285d814bcba4390716db807ad3394bbfbba9eae9b0e3b3b53ce2e96a473703e6b2b9fe969b8f777f1bc0c2b076671b984fc79186409b1eb0e46385f27ae195136a19d747c9668c0f581b433c0bab014ddf87a2acb835c6d181f65725f854cf3ba69312bda5dbf16167496a6a4c8dbb05bae39e6ef7054a79dd769c02dc05a0f2d6a5b6cad0d4520a7b8dbd2e2323dc0d33b90bf14f52dd2ecfb0fd1d6a20c1d9697c90d6b1460f3a93bee434b3a2df2cdca43c9c0cd4062ae1fde32df61ada9e05df08b05f1a1223d11089a6f4cdfb0abbf0dbd71db505662cf96f3d4f27ae7c59509eb2de4dc40933db0b0d8a20f3fcda9c8ab4a89ca4b1052c81f3d29f4ff116a5ed4f43c809d766e5aa5c4fbf92ab4b7ef3c36e8f39cb4b4d2a7b7acbab8cdf9e1d48e5c277828c3d4f2b73db8d856fdecb4287f3e39dd37433057cfb5f0214380ec991cddaafef7b385137225f8743aacdce401cc69c22077c9f087d0b88a5590dfd5a07461005f0e17203df0f0e1a91ac81b3dd8ea2bc45184fe0e6a8d821423945e416eefa0bbf99b4fcb17124975d2667a10f20cc2047a641876e1f83d9a411306095f9d069cb6d742464b38efed4d27434b5e7c8ec33b7f1b1439d74044f67b9e47edb41dd72977c2c6b8cc24156e974ec1a479ac9ee9517bcc48de6541ac8ebfddbc0654511eac9229da651214c1f8fc1822534b606f9d23a86075a764ad894994652cd67d0d5d8b06026d8bf31b959307e0a61d491e75046fd96654ca35d243ae512776662c1a6188af46b59fc600c6486e028a0cf85485d1619263ea4a3e758ae4b415c0fbffd9a70ed832e5c33964b5bc3f9df2cf8b8ec4e6ce8fa1e86629fba60527872eb9c67e7fb7980ba4f3e6c40211afccf48fb44128aa44ccd00ab33c257beab2bc8839026f20e6705f45c325f10b21af19ac054b2109eec79860945226b3caa65fb68aa5cf2cfdc0afd8317c4dd5dbe3149852260dd99eec6fb2229e3013f9973a5405d298bb762a0a7210f6c20eb8fb6760472a8de54d2e0bd915acc63cffb389c178ee4687cf07ddb3bb2f42a65f2da355b0902b72a132df8990e0ac7caa8389cbbad3afc9da68e62211c0592c9dcf3eabc18f9b21a465bacec7ea2e888f73deff1fc0192a02f6f2cf19b8d880632bd2311fb89f5eb8df701be59d90f70857f6aec120d7b8fd5a3bc62446014c8175ebf5e184f0a3aba3f42453a6d692fab30bd030593bb7d9b6e930d7fbd635816b01164f2e419ac42a7a3d6a109022cadb59b99ab1c829bd2a4674d1627e4b4745e38e0d648d5332e723d95d131d4205c4211ecc583ee02c675e93c110f4b7d141683135ca244c6fd3f28e1c0af4dd32a84041ec69ef8eebd977d60af31f9ffdf2e2daf31ef94ce16918abd59f20aec432e6cb7c1e85c5702a0259a411d81ab7e645e9531d4c154788533fd9cd7b4e5d5f05508a08ab8e1ffa1d4937ec8d8e73f0177bbea025463349e6ff86a74e536401d4fe7f337b31f06242b918f2537b657cbaa48fbec971476a7c7611fce5af9a37125ef3c9bd96a089da4c8ef58319f05dd9a17cf1279a3d3e3c91a1991fd5b85fcf2a2939cbb45de8768515f9ec7e388b3a3b4b61de61abf3ddb618000250d78304452717edf8a38ab540e47a51889c4b9e58f1ff51a6d4870de306749f94d0b4cc8383cb11ab5b91236940f1660f3fb4a5125d667dd78904598f4fae48c499adb464bdce8ee13571c10cbe484b4ea4a289da23f28eac7837dbbc2dcd3c06ef0bb32a823504c01a73a281610da59632b15e41bb4874cd00d1d163b42e0d1124e7013b74b3ce91dacbc60a311722309521f24c3510b7af548af1b04e07c6304f675ca94bb20a5293cb480a011cff7a74a88ad3e63497d90982a4d6d22ca2aa0a0a87901ead31aaaa016e68fd1e316211442c28c0989ddf88223891a5697cf3919948ec24ac0d9d4e475b5966f39933b4793a41c69b137e4a6a6a1a9d0356b5f95523985a2c0eeb208cedc8c899fa641e12a424939f04f01e82d455faedcda4cd00b788f1b49e024bb8a60d58f28b668a84175339c175cd2e66c50a3463ca90adf520a814c404267c197d3ce082af4968e9c550a7a404e40c2db2904fbb36c2d2e459802a7c79ad9df87ba5dd8778d0f473f85b8c0aecf8ac586ceaa75eb646bffa74b6f7dd08cdb678246b38a2ae4b0234caa16510d80a1c4395e34f33e6a24dde2b4367f56735dcdd0d5e54673e32640d99dc4711a6cc5ad15c46f0305186211e88535039f6d15c7d83a885e8f5e22b6f8b7d087eb5a589ae2792844e4aede33c26923661223d68970d049e358be5bc2c2c649e8fdad084e8c314dd31107d0440dd4d60b7845e69a251785e0fcfd447d9b6c7609b520d9f17ae9cd8130aba8b76d88a964ddaac2314d67142fe894532109a32571ed09925c2e1f94f670f549bc6babbee8c410b1ee23f7b2a49557aba27a264b3900d9c6edc925b528bffde65492ce9f0ec0ba3a4230586c39ddb50c90634a57872d4c360ed550faf518450df0d6c23dae8ac822d775b4a66b87cacd10352a92a1fe3c11f9831606f4f90eba60674d7408d46496d8982ec2bf21c2b4cb56f90752186c77a731f16d3ea22c47e77c6cd52867c2f8b9418245a17e67b94c97e7cf05c4f8a04791ad7a27e05f3840d52fe20dc7a94586f64a81b23fc1f76a15e34c7c40d225ed990c54c0d0f2c5d270bdbc7ecb93e3dbdfd6505974be6027c7173dbb0107d5cb1e260abc83e4a28ec4778d826b00bf93cf550316aa41a532c0eb595784f570de8bbf112e1a42c396a3fd6891d8b11f80678d71b93b3026b8ffe595dd1ada739f448d4790001cb272ba920654bed7fd4c72fd732edec7ed9dbdc7c203e049bbfee4d6d9e0bca4d475fa3401ac18b1db95a42c527a9dd34fc7197fa41ab32b1b2f2bb60f59b140236965630952a2346a073e9657c8c270eda23e0632f53df045ef8b2401bfe628c2aa158eb6dd67d3f61442605b363efedccde7202850bdc24af750f152d7e751e04ca7b882ea8cf32071f7eaadaf6121bb338159f265ee7a4c57f651833a9667a9cd01de30f51a88232195d7c2f6d10ee0c9b29bd6d5c4671fe64c41b0062164896a43b2aeee4d0aef6dc97838a514f4506a41c58f2dcaba23d74f21c1758e59ab7c1c57f60f2fb91754e306979543f6c5636e8eb98fb6477700706cf277895ced8ab5f7274d1b4961511b7fe253e2c0d11e61c586535300edbba4402cbe8e24289d9bf014c20402bab1e9d5f04d6cb5c30647b88b21df80eb48046042aaa6e313fe70d596969e76fa06dbb5e1c0bbab722d500d33e7147a9d84a20e45b4fdeb919a66a48c4f28dc8d8abe9b16c0246caa20c222ba806bc536dc70744e18ba315a72d6417601a427502bb6801ac90336df5f140df20643340fd910f0e1a799cf3a1aab658d1b0c097712020a6fa5706a2015653d36b2253615f53343f80a994dc5b34181f5eccfe5d79000b2b471e09b31db444cf1b4fb8cfde0dafff4f96ad9b9f27e0f8045ce54dee1c3753488126da6346546a2ff384cf1d755604c50c255faafe0f163a778f979376ee40eefcb0dd77aedc4e47dcdf7793f453214e6c828f287597611259f8922472d4bcb5362325bf4894efb8d5c41663d2d9688909e2df274236943a6cb653b8ffbe6d0e995500bed05cbc801768d1cd1885e66c55266ab7884f84d18d1b1fee2a4e4b7ff8505b3f4de8c5a724163594f9027f19eb20f263a65973c34e0af68396e6dd21517a6b0f59bdb1ff8683c377b9e4c7b3639bb640dd7e224e75f1c51fd098762f415fe1db2007a4eb81c8e8aedfc895fdd0a392244574b3eeba50431c57c63b5828aa8aad28371026b3119621590004a988ed8072fb042d597aa98c34c102640367ed6167073c69fcb98ceaa4c460c27274613bdf904b65552d34286582de5603bed0ebc4601dd68399f26c71c2b510aa53b390f10cf867d8928a4b38a75e74db1030ba913fbecaab7bf559906fef4dbbfee002da7a9c80ca5a0ec059d42fceaf924eaacfc48ed4a6c655a931fccbc3e1ae468e3111765998eb6526cdf33ff83ee40fea31542152a7c8e3c99ccc36006788a90da8b798659a9d0d660a0625fbc5ea7d0bfdd4f81f6633603c9032ec53c35ef6f9ad685a7fd1003e0582f42aa2dae6e1cb844ea1840a386be5c9d70aa65dff76cba5e5934a60427a15ef48909260fb93187eea5311702495607eccca1ef3ff3b7c3c47a3de4ebebb48398a3ad28f69596771a5c785b65a17b65976880ae5d2991f1aa311cd0e7e19898951dcc2c8609148633af95d5a8b77946b8684c6ab2e8cf56ca6847fb5ace01348715bd6ad1bbb4201e9c83f44b3e259cb38b3e5a74e78a2edc51ce209f14cb61ff21fdbd5e4bb73fd9fb25a248c3309ab038f3dfe3a4a882f09330ea69fc38dfbe14dda510593d7cfd324dfe1780fe1606bbab43693cb3eeb0cb05f16dd58c96df0a4f7c4da5fa9bfe7f7cdd3de03102b88afc5d9cc4c21098ce874f1487fdf6cfba1a59e18bbf4973f3c9c2dacd73781d57068705be1849a6ae37d02818f365faf603fa3ee4de94958974be3d1c21a4a08fdd67552660e85d29481510b2696c7c0c8bdd3567cd40329cbc8367b7ca9da94b2c84b43baf72a730f317b787d1b1186c9665561e0dcd4aecdf7263e64dd980218a4731be0a77a98980227834655f770e8d3f26e6962bd528bdf083854e2dc60b0c9cf97446ae5c81bdf59d48f175136d01c5499db902fd21dea78fe3697f76bfe6411a8529d7be7caa2b14f303231cc039b3b61756d35e9981f5884756f50b5a017c1c1875c50e7ea5ef9df5d336ef807487c83bdf9cad677a4b8bd4ec0a26b07d0ea306d64a88cc7e3f4d049a53e828c333ffbe0c5c95e1c8989990330fb4990046ff9f8456b0cada08a8729d64b326222a07b9f9ed60b0228e8a941ddf571a13cacaf63a60b3ada502ae79759355c11feb027f35e7ecee03f6b2fb113b79c840b52032b11d88a008d2b3aaf52e7cd362515b34fc4d1507c167d475534ff83a8dee573ccb51bc523436dd6ed3e23720ed185f7da841814e02f7379fa56aea101702f03a9005a32b13365e6b6bb9726bb9e80e06077fe362b1e7b6b6af65e58206c67c2d9bc20895bf36c0d70416fe4b766e46ef646061a97a4b982d4cd72f17749ba853fcd5bcf4bb4bec3d576762fe8d28c13f1d2f1f5b920e9a1c8d3af3ebe604f356d0a30b930c5100270f8aebf8be8c874ba27b7c95421938ddeb56b2a6dedcd2c7884dd208ef8693352b657f03fcc012d6b6a89e9d962be637ddeafcc0d662e9452f20b5659aba64260ec6f7d37274c837bdd2c6452d98306347a81d10bfd40851862fb706e20821d550861a2457f4ea1e69318fd920395e469af250b0dc5c359bac1fc7ac00db269acd09adca1cd73833183f57a7a601efaa08a9a27ec713cd7ebfd0b2ea342f5fa69693233952c3177ce2a0e514f50297c768e0271ca6d782c69ceddae5ebfb20a3575221ceede0f024b59ef24a9ecdc417aa181f5da25338f94735033534b7dc21c9a7c6d74a05fbb84d0dd30f2189b046762c11f37ba7d7766e3c6a71dcd7ac14e9c8aae328c012a2efdafe93ec33f54c47c60da29a95bb9f395fa6d861c8f57c6ae80be86641d090caf45ee56627c8f8b3c58d13b17dcbe3f84e0521f90f34f4afb29e98f02283eccbe2e3f1e44d7b939c3bfe24d346894e593997966cd0b0c207689e619235d63dc1026e639b4faa8246bce483c762bb2fde589576b88850bf49d714c167158e58f9bd992f051842cdb474e859cbc854ceee821cf1e90d14a6faea2650a6446694912781d950cd124fdfad01de2b56bfb9c94ffd3c224f4c79e7cfbaa42384361679f8f9fc98a31362aab1122083b2dd479a96188fc164a62b0691deb5989d144d4bebe1358bfc049b7b3571f51896df4121fb1b179701bb9bb89f5f345dec0a1ba7cd5a90a64f5d290948202a9a552e3031b9d179b55db2a0c8f4f25c0700bfd65bde8787680990fe4a2135db8ec201affd8c018c413c7530350ca9e8f10d90946b6f8163b0573ffdbf32c675241867b900284389e17ce7f420d67ff667de2fe5a1071f3209be312fe7d7a12ac7fbb6ba7b5b0e96efe966345ff7f0664089b06efce35990888bee84ee352e798b39204dd3501472fee83a31b3c4a9870b5136c021fef0df8049ae0a97067c44ac573b054603e0abbfa36c1aee2a8a41e13e72adc89e6f60d263f740d8b3a816d0351ecc228f34dd9a96695dc0b0fc13a4cfae96faeaecb1ea7911fe1d1d80358cfa380afaf6cf9acda1fbad394592ca72810291d9e19a330dfbf2f43c1bcba244f5c3148176eb5608d351f0c3d0be183c7b82ab94b1bd23f5e6541aa3dbca0a000fb8ab1c84453e3b455f29f8bedc4b8bce2508086c560a703f710c5a67711e90371257face678ab75f9f17b7e7e7075bb1665535854f2e893d26b5ca983678abcc646316ce5310aad930e6ca68a71141fe57df5079507e5212d13bfc9f02221cfc66517568f57b14cd9a6cf180c8729dcbbaa79a102f5eee774ae7cf8cea5c4abe5f1df220c2bbf1fd7a3b56c061e28b1082d9944882ec451b2b763050fecdb39be05dd73425d58b2d318ddbbf9a8b83b2b9739b4f1e7142b1df3f6b3f4c3236c760c6c7e32667050f382752744a6dfc295d8565e20e054f0ac6ad1806403216c105d1274336318398cb55335d4d0be7dab767aacae40d8dd17e66636315b48ed1375f7ecbe0a7ed1a4acd6f05404cd43296e71a613d680707ee6c0c2c12a898355a33bdabf7d1e3b01b3256785fe89d446b1476562f90bb7c06f09eb4da4a71063439adb92aca2e235358cc898dbd28083a1466febc6ea8f0b861dab9af420f15fea0a2cbcd6ef9a4cac9a69df7b31ed8cfc81d9f0e3c89a50603ccc986f10e7a1a8 + +Params = SHAKE256_W16_H10 +Msg = a84ac56687bde5e2d8382fd88e343a128dcc899a02ce38126675fe2a3bfd6c2ad8adf8d092ed6f7951e042f8fc60a366e191c44f3fd3d77c8dd23505273cbac651a48ff067f90af5d467c4ac525872c4140e82358591a1daf8a7bf6716a6fea003d128ae6cf80a30bc06f6057702f97133de52648641a4f8dde73ca365bdcfc6c4bc3bdec3258b61f23105ebb52ca189c7ba30fc24f0752c66c00331c28e53aa16219a85c90658c615e20ce175028b6fc01dc0aa1ae9d92f5f8fb4212c6e4e0dea138c2cfa3f79495188eda3c2405e66b410c19617e4b5a2651e086b834182a0821b5794a7c417d7084a876fc7618c96172eeb972a5f323a924b6f0530daa8898f9907fcaad6ed374590d38fbc65de46f26bd8aa70bcb59b0119bfac482a1c10b415 +PublicKey = 0a00000aee0d4c904559c13a9495a2848437bdd5181f86b81ea069907d14b1c8bfdb29e103ffc674eb1b9756c22e1178c39abc1d6039c6e9837ab212c400132cbad36f8e8d9b0475156c34478db5b273c1070822883aeb07e55a235f4784f8a83bfc4a7f6ba56a9bef635c6b855469e0beb150a26403efa385db9d1bf96dc208b4c8f52f +Signature = 000000000000000662bd1a7752f2f1e2a8feef514c2a83616374d1003b1c856c7d1a865a6302e6d7875b187381e7415521c1c1a7b536197e6f79706cff35cafebb24b249580b18b7f2a24e6a0b75183ed8a1ea121702d489fa2587a5c2ebc8b6b20ec49bed0e33200ab2a05f81f334336ce9d6b622f5a31ef7ed614255a4521a6f2736c401b12e871c82217fccf37078ac85e930256c1b3b9a034d136c83db8e9cca7cf1cc81b47df6693036ddd9bfc9360e85dc49559e6fe42120cb0924bbc1a68ddf5953d64c64f0529c91070ca8feeaadb376990bc90163e2c80b587e2a86fc81c0b5e51ac6618a1f294f323d39f884e1728dd2690d01f62d2b25648198cb2380fe242da8c64b86a8598c73d1b3aa0e467eea99aea53231736f02c55b7d5061f3fc726012321b69ddc8150d56f3dbcc89958802386a4740e6ff90f2f4b17f49b0d168ab8d1f131413852bfbd3b48357ff890a378917247435fdef4239cd8654932b09bdfa9e1b300dae285870cfba2169b1ea9b7371b3670bea5affcd1dfc16bba184ed3c2bc837eafda18785d6624d2de1fb27062f57ea864fc5923ad252529bad0b307f6805467f3eb425ab152bb073e133a1eb530de0349850d047eb177cfbc6fbd5885db745e2707241b34a50485193b01ef5179a1d7df80b7d95ebbb9da74f41526a1ee85f4aff0c9509256c00a6b248190bfef4bf3303332c1e2ce44586ca106dba380138f13b098ffa0e9aebd190379f81df01b0e7569480387400d383964d2e9ddfa12b2a4b87b99f021278a65b4d6023167b3fa4cd78efba2eec6298af5d4b63cad70cadee80eeb9567919cd834eacb1f8e1992ec8647fe3226ce377e64b7564bf63af0da6742e77709ce7a43b4fed06b6eebc439070f05d324d04c9b2b80cfd9883327afb4402bb26e78782ffd6042329c2ffb96d0d50ddc03340e85365e28fb31973a39d0f237afac95163de5ee5a156296c24c3d8b6c734a543e1c52f1345978f0deaeedbec6bf314bde48335dd54b73b5bdc6bab03caa8f78c750b7fd5c1cecf9dbe7df44458030869bbe4b203b3a4daf88372b95c6a0999f969c77ab35f4c1f3a7daea1fa233fea073a73331f1e76b58cfb4feb1caaf705898b4d81e99e478a6d863d4b5bf9bc88dffec4113a1512df5cef30bae9dd7ac854dea05eb44a8b805f8e2d10d761a3227ce6003c2ed1d7ced7719b534633accb8b802e82d7cbea16ee3765f3d1bdd5c00e4b2699a0ddeda32fb36db5e3348d8d53df8309772b11ffc6eaafbac5e63d68a94c35854b5efa8346fdb1be82da632937ef90e9d6ec955fc0585616522a7e2b4890cbac550281c8841e3bdfd88f48be87e1f032ea97ee44d1f8a484cc08da3049f462511a63d93a443066533769dd640137b6af644e8097370c238e73f8e256622cad3119c9e753ff560655820f97ffe9409751d025ecced824b38a5d816c0311e93eb222f395653d663a3a31371e33c8351f14018206d8981db047eae7c04d3274764fa4dd585e0649073c167cd32e6122337548b3a54856d675b532187a2368e4bce16fc8d695db6d054e66ff6b4866966ba3b04009ef7450f7d83389484009123338966ef23aa5121f26a29f2f04f94795f7494e017ea6c3565b9af340b5898a07a15859e19cd1515960c01173c178bfa10ede9edd7ab00329fafcd06565ea9cd06debe2a6b29fdc0f13f27adcd0cd4a12e89cc9b2fea81fa0d6beac273f51c533fa8efd9e5fbdc46cc88d9e0d11a7dd9471aa7ac628bec5e4a97605b835c9303a572f23a89932ebb42d520be6040ffa172ac2ec2ba547328c485e4de174fcb2e8ec9165317f7bb58233cf811b81a3fd2b0ab6805e08e06842ca17885fbb662e7b2e202df292d2241e0c47662d269a59a2dc288ae27df45efb615528552281372920fa9a30c328fc85583a559d618d8a7f03cfe6965426b9ecdfd2ddd779129e415dd5fc1d3aabfb8cc97b75c0346e97fca93e32304a6528ee4441aa8f86f01f84dee19bfb72b3b40fa9e3be4e3a70f3d6a382344c4e04815fb69827f63e7b01253dc50e68473527c509ae587d1f6ce312dd12a99f74dcba7db3d17f53ab40495c36b7bbe94b2f05993c21afc0db5efe4851a49181350bc43bc687afef098fe1a7ed08c9b5e98ede02c3c1339fecfd79607aaaf757cf117674616370bfee9bd19eba2029e78423728b9e2ca35d321a77894b2900b63d83a405fd15e725bde59a791b0cbf6711f06d268106b17e68662ebd5062f7641d290454f17409067e868a367e210f10c87c33c7e02e7d07e553881948c7006a419e9217f390bfc41a99bc04926d0a1562d4f2a5b997260abc0fec5863c03cd3b405fd1986f919f4c97f1a6e7b2250041f5f71c50ba1e6e93155ceac7f8110b64c040b2ace79a1bfe1be656884e2a390211bee2212dba8ffb9d55d4194d6b666bc2a5795517513b82dc970840ba4c550608a96b5e72909217ce53d781b14ec8ec7f7874ef22cc1298ac23aa25e8d5f68d5e333b8cad8d713f8172a24158f46b587c47470655af8611d8eae83d505d1ffd9d860ec6fa218a762ed6a380f1b3eee4c3f4e06823158ba00ea6b199fb99a1b8a6d8b403da2544d340f734cc99163bea0f84d2acff5337d98dc4381b202b5e847db1f6cf2b99706775b4796ff730fd02a204f65d09a549c521902b34382b88759d35c6d4f5763bd72085192a4842a7eb54f2dcbd1e7f12ca7341028c65a3187194f4941d95c78b6949b3615f8225c11d41a4455c8e5494bddcd0d3dcd5ff8b5b9a3c2793b2883d12d44783c8567cc008c323a34697bdd5f83ab83c10b256b9e1dbd3dc53a37dc01d30a2c4277850fbcf17f3e8f8bd94f5604aa94227b1144352ac221de4993ad93b9568d10ccdd42d7b5af290b8dff4bf991f8dcd9c2db5f8c6f3606d0a52bfd697ec3efc79ad00ab08f84913f419efb1168f2302b573a5098e1b18f2dc4fb4ef87fa0df81ff17aab6a1088c93f0130e8156326cf676ee3a0c67cb44aee1ac2795e95f9c543180ca77c26d71adeeda7dec56d0bcd186b6ff3c281bea30c8599f862630cca66a2e21df9cfa810b1e7529785c514d70af0eb1a2894cede1ecd91cb5862ce403669a209b70d7baa290e6b4f777d361275a8203dae89dc60c87c03b116d5fcfd929402716a9b63d062cc586d6883f43d8cae2108cbe576b334b4ebf9554f76001e8553f8e78ee211bc204b3dc8c9951288f4ebe438ddb3890065ba084160de737a1b2c813bcabd3059d4f116d115ae9f821da412ff711bcab0be9f1195d0e346ecb28ac51fb1af107d54c05560e209a6a36ad8e7327575f30c3ccc233a41d68b8b235ceecaac6c898ee660655707c976f04ff36107bf1b12fc7729a57d7042c4cfb2e55210973705cf55ffbca5739f137e6c1e5b9f81b9b5b8c380aa0e92ab61df8af6209be051d64d185b20992f16fb7fd14cb6fee6715bb1b2a32f8e34be755c3a85adc0ce5323c2ef0516d7dcbcaf729dad6855144fb54d0ca77f9607021f14f6bd8476ab2d2afc9b9c80cfcf29c0840e5ee1acc76e2c256f25204968d5d85d6cec96fe964b9f60e0f0a784bdc1ead6e7c53474f3388b413c04e61ba611d5f764552bf97bad8ddf0b4867c787be5f70a18e8e8e074a7568b3a98e6bf166edf1008ba021ada564edb29ae544b4eafa85979b95d6d94930e624c9ea1c3503b5f89340f62f3020a030ecf34a4195f7ac8cba14e0f3e77610b8196ceabed21b79dfff488ea220b98a3b759f1d90af5f7af2aaf4a571abca5fb0865d3ee3f6778a82d7a7fb35440b6392a0a3909e0d29145ff594d3b7bf143fe7e935487358097e92dd176488769ffc2d6aa6589d1a59ce7dc2372464f28b7a05bbc542e57297d11dbbb0fa7b8a3b240b9cc6f018ad79abafe6681bb5ee4a04d61f61f015f28ea839c02a207f0a7ec8c0d82131368c2b715caaf070d642a104af90d0644465d7ef526ba19ea0a47536bce1b8b5459265888147cefbe7c6e91576ff09ba6bd125fe8fb0ee864672ce9b17b18711bcd51f2f6e58b05e784de5aa9055150fd5f814bece2a4eb5b90d202dee3cebb7ab47331827f54760213b5a4dcdabae4b638261cf3df6827593bc63c38feef8f8686418e3abb402ccbbdc68b86994f456c07b0ffad49c205e6052cb0b716ef0fe72bdaa964c72b8845bf28580761dd29f252b2f2b0ede01d396aedbd15d5ffe51f52664a94fc772813b363456a7fcc35f04b15aa45d881a2a40016a77d468312cd02364abd4504d161404f58dedbe9e844bfd782823c6c111a70dd56c6a34aefe2f1ae3753a4ddcc20d0e678ed925f2f5f2b339fbc5f28cf42c40e0940dac4848e95270e6264dea56e6856303879097e14aa11bbc00cd168075e5c6f4f3df294bdee00980c1f3a9e9e5ea7ecf1c9388b96e58dd3d30fe34476e385a4ea4f59478683ecd658796cbde7d95dc278b452b47a1ad307435a24638c1e404726ebd4229b4264c1e086b80497a109d94d215a24e65b374c162de08bbd8e8c7bdd75d976bbf76103b67a3019ec765e9e4bedaca8a83fbec472829ea06fa19de6328e3d83582e403c1d966c67dc117c7ef74d99f4f3aa8c13d4229e8af560f92bfcae7b3f28cfa9c04bc5753ba9d5777ab08a039f53efdb99ae1443167f2591f33daa3502651b35a192b0aff84c21f9bc551ed913f2ba8166743a7841a904c3e24d25d79b4a4322965e00df7c17bf61e19284028b5b12e188f90a8c90333f3f4e8df09383b919dfd05dab2ebf6bd56306d4a81fc688373c9fcf6088ef868dcd339510ff57839d9fdb68469f2346815e1bc8da0b066a26b3e28c2280f4af46c590fb174db226c4befff0f5fe69beb88291ff7e85bd53804f81518a95051b6f8721f47e0250a3af377204279045452b803f63d72aeb677b42a4f844f5b77edc33755bed4f2aea5f155c2efc3ddd839fcd2ab746db213c6949d1ef7a2f7db01a3578384da05df259e7a7c09cc06009ec662c51745b5678eac9dfdb9dc494c32b2a13850a0e365d26f355234e58b63ae15e3b6001aacdb92af143d5bfc4b9da8ffe5840bdb25ca9190ab18448002f39bb4752b194d221d0e6b860c07d2161d53fb6ce55d90c7e17d52c9a4cad8be432a6b111a8666bfebca8f3ac3d51db407489bc5e7dc8e146fc26c3b7b1f148064b52234b002e33075e3bb50f6e338f011b18cbbca6628399118c1b78e91e4edbdd666bdd8db431bf00c3e5f5eb50cea0fd89ef9f705b257d9558e6e779a7a57774dbea300414d1f40082574667e0912938736f0cd092caee9021b9b61dd692950ad4adf1506002096ce77fdd3f146a963852c2dc3a56f263e5e4f6402577bf7312711af8bde9689d1d21d608260702f1c8cb89b723abb425c4fb71277c8c8dfbd8c026ee20bd61a6d15f5e245f944bc0ec94a7a9df15a3fd13da07ec1d78e99913947f1453af340ee037387fce87b995690165144bacf0307ebeab51ef5d7e9d5c3a3f8a73d288a6f84c7d8245569646b3fe6840f7a3401b195186648a0d404003cab9f2dc16185ee224a1af8e5e7152cb37aa2f27fadcfb65f72c9bd8c4d60b7b72b77c9dad675d945308967e9326cd6cf5f593fe6b80e91650400de80da5b24c6ac5234a9402e55556e11010fcc17c3d5237f6d0ba2c2522f454cac148da60469b67cea27e7ef9a565d417adc302f992bcf82f8ca8ade35b791d8a6dcb4099f2406f7aa28edc98d3057560b72dfdd9001de9bc64c154c2c8cdf5968cd3d4c2aafb8034c42a3f291bac6561756149025865684d4d31d52f9f9d89fea3dc7eceb7115aefd38694b3451cb86e79f11d2cb623ac42045ab02e1356eefc86e981c3a2750e7491e02a116d8cd775bfc7e5e69cb092ea427a22004586e8dc0a154269210e84089f5b4079ff11820dab2c51113de6bcf63dd3d429fe85446108d0c3bce9c5f3b85180e7cbb329dace1d82a04f08387c12dd58f00c9fc44e452a82b7174094a98dcf9055eae7376c47283edfc769cac94470ccee98a72774eaf902ac422b8c3b8fdd79654ef6258647734c7bb1ce76faa5eb1f62e1a5d5bd88620d3d5636f25c1a1c17c9b70f39733f973138378bb4679c8423e19e5117d6672d50d7764f2b1d91bdfdddb69618fb038ff372b3eae6a7583142c3387d83f8d631a95e50e58195b8fbac6bfef57a4161158e1e5b5be2144e7e00a43da983769b6ad9a58fda2b24382857cbc5de6270ede23142ad3d2ed22e6ba277bc6691c4f37dffa3e00d3871db507276fbda9d3e15d89f2dd4f0413a2dabfef8e1b8702ac1b5f2169111a8a829bd5184cb442d8dfa8fa74b083f6b488fbca74e664fad8e9f0b0f3b76991b7f556e9843d7ba3a5a6e8170f9c6a21b5103996a3e3d8742538a918673aa4536cea16d0aeff4a6db80553cfecda1125132b7f87be19cfdd0ffd73845e40ba945ef352dad690fb944bff2bd8451d526b40fb1ab81228e28db3a077db6d732d44c574036b2c0d5ea538c8a7ba4d88de3ae05bff957a66cf00288156325b370833c07fa30c0bc4cebada22fbf157b54cec95a86018fb2b2037dda61852d7dffde6a3c2d708a13bb2cc6ef2a56cffba003f31fe21a22f4d7644124079afc2b5368f2c2afc48e6fcd0fff3f1b0597d4bd093d150c38734806605207652ac6bb49c540b0564631252869e9c0f4ed7be45887a1ee1674e3aea2bc84c59ac0f364c176ff9c5701321bc90d192d1afc4719065d7082b6e221583a7bd97f392a988f8643919c619cbe38f48e305e3174016f170c781160097be579235bb442d539ae371b5b7e5e26bd21b02aff4c18027f92b068793a15ee40b7c1dc07f6e76fe2fc254bd6f61ca701c41e14cb85856970dfb056d2effedd522111b575b0f22f8ef3e9066e6815f364f40cb4291a02cc5ac88ec20d55e5d3471f1a39029ec4f95249b48cb025d280af9604037ad56349247d544b255f11268de2516d1d22e16dfdca0b65daf5d32d4e94a862ed6d62a66f2b1bdb00a4a20eba5e968715c19d11173eb39824fb6ba2675bffe16d5a9706feccf8b7887ef49d1e793335bd2a347266f32fea6c6e926f120cbfe0385333184994b40307a4755b69ae3319da65417396a9a7d3b2733176d8d66646a202368771933d78754fec4eb2fe8b2add0ef4e9612c445fbd9aeb93279015673fb692410868c78b701a7ad0ab924a2992aabede3d4fe5f75893f8a8bca7300a27f6c890829884991038721977e18bc29e022fc044148d6ce8f3539ab887fbdb1d80da22d7c1725e5b2f3181663b7f98f91c91d16dd3faf6fe07977ee3d3b7e9bcaaaa3ae96df180c52e52a83556574f4d26fc490a7f52a89b65023e8b0759de67e1d35a754b52677c7979358520b2b3f4d6c8959ffd971da08cd714076222b2aaae569dfd2a277e30c17d0b035cdb482e52f78b184a9ae99fb8e929ac8b0fd1b127afbb0e038aaff96c27ccc84dbd6eae14d28e2871a7a0dcd63a78528226cb39a3de767195b0c10eb5cbfb122efdef6a79d496362c18a8e590a6d363478312df321b170ec8e70b954968aba4467145cfb3d605805c5b21253f931bd1b87d3ffc18c58af3119ae572def2339691c504def5d80d83dad0faaec80b60c56aa940c9e289e5d6b3e3e80a101bdba233028e08177eb7ec0a6de40cd3f53bb10ca333279886fcb47ad976d0d64d788f6a3697bda3164ac22bb524026d65b98a746daccc5da34ec53cf5f1416d242aeaabd086982fbc362c2296fd90e6b0e6563a171980afc8c4e0846edea5137c0ed5007c9b3ff3b985b248aaa2534d6bf06e85b1ff020fca9fab744ac61a4710586d94c8f7c1e411159733ca82b202e7162b6a112eb400fa8b179f84fbcebae798e4d06c3c3f57dfcdde76d07414a8420575c64dc8c2ed2257eac40f6b7cf033fa9406ce47b5fa8b3626a30f4282d9d2986cbd0eb73040f2493aab5a4840ecffee89d2ebb4ba62c7c88ef7179a15081c26bdb113e4e97af91d0dc38894c6bd51c8ab39739eb07ace4946fbc6a5225c2d2a4a40c3d37930d8e831f1e35e87ea27952a6af6d186d21f2b85dbca97c77f171edad5fed76459142e2afd1e238ecd6ce734075354bc6c3677434cc4907bbc2756de4b1715bd64c4f7097928142c64f4b88710cbae41cebaead35fb432144f389e016370258829bb517b9651090035b8bf6a3dfea8e07aa1915c0917b9d26a45f0c8c287e621ff5d65febc46930fde41ed8368d339b160bacebdc202d443ecf4cc4c108f1c76102e0fc700be96e29457ed1f4bcacfbdbfaf291fed9d311a63e25362823161f4d9c2f57cbcf24694ddd73b202d427ccea264d36698431fa9e874ff5876bf3fc8683852b5723a53b5ee583afeded57f81ef89f85ce6ff18bba9c7d64aae843ae7542290788f444e5d6e9f7a12a5ee423b9d3fb509a1628e61fad5d0beeead63bdb819a3eb0f0eccfcd2e3e1af03890a2b9fdc0acc825747da095b58c1a8c5c1676f1ca69b75c1bf5274243dd0f6e74b64c55a5d0194c0f39c9e94072c62ea86735c958ac58ba79c71d1a235d114622cf830bbc761c31047f4f86959f902183b2b6505e5bc4bd45842699ac4b0a8fb53b4e918a0174b21e4781f008ceffdd8cf294f2e6e186118e82e2075353f743c2f09b3fe2ae39f8da6e83c86d4de96f02cccc74666a39f07c185b9ae592c2ac37ed18ec02875ee7045360ec07e82a02817932f18d7af12b9fb9f54d274d5637a1fc03143fb06a08d23a4e5840b54bff13eb46ce5f4d745c660b222948e5b1050e84d0d9555f1a83159d795546398f05640d411ff580b5bb28b0d6ce5ce47f0311a226dce617c5cb87bdf30e7cb8822a44fc72ce50d46b4b658e3a6ea8eefe56e481eed83a5cf8207726ebbe04f6eebc99fcf42b3c6a83441804f58432b0e5b70d10a0fa3fe33405558e3d8d68daf39aebbf4f6d8a707bbe39a84c283c35857ffe72cc10b8f348beba0741b044f4a181016d32efd84ddf85a1e8dc7e080bf6ca2fef98441d554666812a83fe13ff845edf22a24b027e819aff167ea5e895c9e87ede2b17002dc9807497724f898c4f94a8a0b4ec90e434b20a981979a6ddbb4f247c851bc8c0c115d3895e9e6c40b3ee9dcc7f4bdd7a2a564da327fcf84540aefe4c7e10295d8bb69268c4bc757c763a2bc49bcf3c0151d4a65df3ba3e6f056b582aad1ed0206af91613024494cb9a91099ffd486b5d6778beb79a671c82a41d8c79dc27b75bc63d7c04f3c387c0a094f22041f33a67bf1dcd6f8b07e2f5da81bf50e35fd7ad69772dcf5a56a45ea0a0f5f0eb24aacf5d9188dd864b04009d262da554aa8885521c4648d6a2ab6e80937d3a6cda4b19c75d57159a178fee16eb992c7fcee4a25ae6018397b07388d4145cef69fc44fca853d0ef747b9a5692c0a92e6c3b04a9d5a778afba4a9512c7ff9ed040b3c2bc7c76462ba360fe4486c00de3bfd70d3508a3e0ada49d5ea0b27d7af22d0b4c259979180d625ae97f4cc61b02f17941e526609b1bdd2ea9e7fc94d889d2f5b4f15e57370cbc909c8b80121953ad2e96aaf526f09c5f9d0cbede558f986988f4bc580923b97d785791b7cfe53b68cf315c841e75104ac784491f3caa329f3b6f455d4368e1d39aba7210145b4b01698f2c711b95c70ce3e8d55826a69b51c5cdc90bbd7612bd7b9981ccb11fb5506a54b859c53ad678fd1817d3a598a2a0d44e9b594739ec2937b845dc166934d0f9be6914b8c959d9bd8704dfd00f2c9680b4be2f557b5cbcea75d99c9fddc7e540c0a219a558b28394cbfcd01fcd2aa915b3ce8213bd5a00693b742da144a4f0d7b47dd5655e709d60e087d2a751f76b22b9ae67c5ce967aa70ac6027627b5d4d834878d0fd8b64352f0d785845678ee8476982fac37a1de865534ecb5c1739737f3e2918c046bac762182564d4dd44da5e7760dc0667e33d23219ea1f46a76a8a1ff3239297e085ad9f5246003e159745b6f94560f7d1763311b6385c9e02fdc6566ee3f095169a419551345fb47645308b88c54304a5942ed84b1cc8e0f3a24fb3d7d26e4e0877cab519e669c127180e78130dae1534bbde661dcb685f1ecd61014b9cf6f27ee398db7c9de7c461625c545adf250975dd1d710f46943415ea7ec48befa2ceb2995733057e05244c6c4e843147b6f598a0e4ffae0ce6568da75c3bcdbc30433f103ef67b486601e7203a0aca10d349142aed20b487d836278aea12860507a2aa121b2df3a522ca2374a95659bd2fe5a04c82de8aa1992b0e783e563b8b541e1c3ea5ab11d8adf57ebaf53a17e48c3bc8063ad3a23d03713b5fe4c0afdd42df490dcedb6541918337fabfa905c031cf99faebc780be6834241805d35931bed6624baf49aab8883155caed306a0580e23a6232b9b25606b8dd03bc6f03f0962d4452509d16b57a9f0d868eed296ea12a4ff4c862842a20dfe17662beb9045711c60cbcf880027cac2e594db4641770880a22027359fe52a5c7eac44fa41d019851e771b99f264b2248db8e1586d541d35caf4a28ce2958a837befb5fb24fc359710297a455e61f5f61c05a6d753e4b4d7b1c36093c0132b807024000a6f53f8b6285a2cf33668c53e1d6788103ccc9a19033a6b68c8bf1ec4b27a1a8dd3aee49aaf3bf5c37478d705c4ba8d41747e53558341b7c77feed9136619a3927a4736521b7f2fbd7b8b8aa67eff3f56b10cf1eee99f767e37adbfc8160479e532df649a8a79e0562d665cd47e094178c5aead180aeeca6198b9f8aa0329924cf79e1ec6729a71bfd62bd2f500fa46f496ca7678212b38330ab858229c628a73ce2168392cb88aade6076d6c40476447faea370d5ec1c3a7f00b6539ab56da55d8734daf8b4f632c51c9a6358741847173fb080b83acb3cf93b7d2fc0daa3135b28600808be0055f0afe6ba73dddb6b1a32c5066297533af3ef1082e3fb8e524cff3ce5e104a48f7090acb2cd5af7d13d5fe2fd06e920635f2f2fd9b5d42869fe75cf46ef77782040fe6268bf844c55b7494a48e0a67295d9fe337f1e62a7c648a5af60c809ed44fcb37a01bb5c601d86dda3b16899ebaee504ca044c115e089792aa2b555ba4ca953fa30456487e3e158e0c7d97d56a17939b909dd0dff24c6c80a5580c2da00ec8f31f990f0722885f47b14f94275dbc0ef1a17128c94648a8cbe488d847873cc20b26d7dd3dda544060a79f7672a31236a5b36f72c03ba79010d10ff285c825d8ddc88d81962579b5f3f8239e1af7ac0cccf829efb1178b86407326ddef1bd9ecbea7abb99285bc14a629e680a18375b6f2ea543e742d3789db432a9721a8a07f6f95e405037cd9ce67b2b7b51bcabca9b012f2065b833433ee9346259bea6c1059c56e3adbab8dd0a286f52d6ea17f0930057c1418ee90cb6777c512fad61aee5ccb113dd7cf3600f0d17cd6ad97a7ec7a69ade581610730d6f36782e94e09b393a3658210a198cba72c7848acbc32bee743eeebb02dd43138e88f9ff32a394f181fe588ec0dea65df3be8e3bec54a234ecedb955037a155641944e084708486a1e360de4d7b0f3280f639dfed188a7b9a5f6a05f3096a822645f9d5bc29038dc0a7b0bd65a088d87330e1790f3a93aa058ba9f737532d5400127bbe9e02044f288f4ac49202ee2386d647d96af8b086f92b87a3f193be50f96a5c1a3f0400e43976eefaed7bbe3b3b70550f93479820fbdabadd30273df220bf60429c70587be5025e9196f80a2dcd2352b235200d84d17a425eb8b6028ae5bf4f6a698d79a0aee44a8726be93e26f69e8c4268ecc97dd704ecad8f13e61861315d1c689e0e90d697f77eb74847d173f174e5cd9f0efa05969a1e3a47ac5798d43f51f3dc46bd8e7e29838acd39ba9cbd3ef0c17e43f60ac5c7e1d9633bdf26a34d3b897965278860b7f8776498ae8911474bcc037e4ea7bd4e11a9e2edbf1bcbc4b576b29f1fc01dbac0613a2358c3dcb0efe9f59f8e61a7592e79f7c382e647720137efbd96a294a1cd0946ef2fbcea7e0ea3186c0b4932fa7eb841277f299d9fa37cbbe926da749a37bac165e9b0d1be477d2c55202dcde41e1a6357d1230fb5816d56412fe0b0f0794edac5fcfc61c56e9b8fa1301721d8800d89fbfdef92a2fe4b45976c41bc5941d09e353ae0b41c541883bbc4546179b0158e7485a6913b378489d1191defe4c30f06a34c80bf32d4eaa1233c08ac9faff6486cb1609c219c51a25162927227b0444ac388420ff22110f4fc4b387193e4d2424b2d76bd87c5d384dc1f57ceebf9bd474deb7e5091120e899b25460f302a34f85b894bcc69e23a6f664ca017471f653b1c832427e7baf9eeb81f5c466d8afff2da31328c2348b0eb641a1290f0f2eb8b249406a4dbbc6b71cf2e1ef3319ecb9e8035d99fbe25b166bf19c1a4fe27a597c02b6d2c8955702ab43660a175d1515fcd963d1d91cc67ff0c44e5e05d128e91677a3da871026cf774ff3b8acb79a04d697f9e3dca3e87ed93cf86bfb17da97c21b52484da07f123407677eaa241ae215519209a1734043c0904f3f984dd8af5752b667aecc3cbbe076ff73e3a01a3264c1ccfe6483ab73bfc22289bbf748d5c8b02bfd660c71eff424cf48152351bf04b912fdb2d86471a0b0cdbbcb4b50e18ef454c985d6627dbd7d2962edc45a2877ad75eb5b55307b1b19dc8418ce9f582d1196790d5bb6eb774ad6f643ad06737f8f95a920e8c9c6ee38b0c9f5d07002a77f3ba30788817b8eefcdf593c216957e66dfaa0b4f5c3bd10a6cbf0e83616d6385520c1ee1fbc88bc833ff7a45481f1f811e9587580d2715c263c9fe1a584aec9f85dc5c7de + +Params = SHAKE256_W16_H16 +Msg = +PublicKey = 0b00000bf02f49914348709a35e51cef0abdfadcf08811ba9ce1eaea52760d767756e6ab956b0c75697b7e6f9dc5144e412966b6648164217d97925664e327cdf2b532412c8efcd6e9abd5dc08c724bb1ff4254a0d0159f1c448dd5e65af77177c320dd5f058109a5e8b5b818cf8553874a441bbe4403b006ad168a6da424a43c2ddf27d +Signature = 00000000000072402f41a1e0a5686c48f29c795169369d01cac3cdeb26052be3c85c279d13a95a21fe28818bfc18c2629aac3d14300d36e8d14b9402c3be8851a039fd444d28b57fb9eb3bf14652b1d8881a6df61dfa0c3782a6d9dab60277b6d92870f07da4bd9953ddf2d7b056d37e7d497742380ea91cb509f53c5d1fc162813ac49184dd05d794c657c8a3ed709da6ff7ca8ee9c43bfbfc0bdfcf1cdb179e2f3426c5b18c37791a6639c6b05a8515c703dbe8b22ba89b37b2c4fb10177ed1651bf80d6e785070c6caa34924d45d63e1002d2218b81c15bc144eaf0d0f607692ad62034bb7ea759f30f23ab5b3985ad949ae2f4083ba9840112d63b1ade3b42c46630c0f67600697f7d62456275cbbeac0529173b81ebea4d2bff4aa1ef15b05027957c68f7b4c1d40f719d4be3afd015cba91595d8f5c12c8a9530bc5a5c4c9ea59eb6c4bf7f4decb35a535abde741b60c068e480cc83c25ec9e85e1f7c82d5606264312f2e375f5289508f084d0cfb4bd4f9f6b8afc9f50fce535fb8bcca606197ab98479919875818602232874dabe76dc573ce0aec31845a65e42b697bc6f24b2c3dc8b451a8244e4edc934fc40bfa2455eb61eb7c7afc7643c23a0bc3e9faab71e1aea183c7e364ed2f5da0d02f416a2d3bd1797112699bd53f124e422bb29d9bd850151aa53c8144148cb1bf22530907da3948e3abb708c92e3f8567ac39d9d93a62967350a27a22777ca7fc11d6192ecb6f893a01ea1d84b0dff92b0d540c88a8a7ba05c79196028678212f30671358d59f7628bc9d74463e177a6631d9fce1bff4d750d9c59916446df7ba3b710d975e1bdc8b26b21d60df4ebb806137a539c15e1cf5af942e925f943d0a3276aa7c3feec8ba0502b2f99babc3a3d3bd9850183b0db6d11f702cd0fc4bb1283deaeb15cb61b0362be38c7f9c1feecd2494abc04c886c5e3f77579eb4e00f3263de01565d12ed396fdc2a3618f2af53425a5ae86cd4ac8f450177f0ca8d9a651b7a507841f9b23b1a28b0454369499b72046d4f1ea3139aa789e1d004a7299a7fa4beb344d30cde65e1d5da7ab8bebe4cac02d270f0b30309f837ea9075e4671af3cddd74fa07d25f963b5a9b6c2977c3a07f11c9e027ea1b1944d7af5b706a106c7e20982971f53aefe0ffcdfb3626c4b64d39b765da2eba81647b34e04679fa9e3b27b2a084da8d12aba0d4405b6797cc0b2dbf9c1d649afdb8b3802d937492fcafb0c99ed8340d7562a24e0014a96ebc081a08bc0292cf06c96c56c7727f1238c65daa475ab38a611008132146918718aa75013d870fd5428b1eb2d6d5c8e7ad518ba466e4747bb74e01ce23ed1f4629fdc097d841723eec860e181cdfde33d9cdaa2d6e36d43f9c98402cb771616c35abe5d92e3c2e9674f1af4a163a1e7adc4be038951f86f1edf7afab24f591fa71a3e96f03c5d254e55dbbb22bfe693a8693221e3747a016f9c95270e6ba581f0fc0c3e063ae151072166cf9e33a226759a67a3c9f192a8935c0ce88ae128d27b9805578cf64ad844c5fa45667d112b4a19d545d0a60d6332b1d71988e895f491e106dca9709ee203a4400fbb8429f007c888d9a957b31973e1fd7e22dbb85851aef7d8c883233a3cadb59715bdf12051162970b433893f524136e8aa7f76bc3d848259bc0506b0f3f98223e1fcfd75baed1b1ef2ae9d7031d2d196cd26b15e2df993ffe5148225284ee05bd09cb9397ceb3d621bfaea80c64fddb7230cc576173d4e1a1edf99a31f9b14caa55af0833848db16b5e92b1f9d628b13a1cec1a589b6a00753ec082adfd4565e6a47a3054cfd4994b68d747c380cfd5a625a04e8f7407f2520e6ff28448db68a55540dc4ca5cd6511b81585cab59ced31e61769d959130e750a87bd7d3ce8d04d72ca0e056a28026ad4f06730b91b36a060d8f0a9bde0fa9ae1a2787570ad666be6706deaf0a1d9f1464d6a3c2b731d7af99a4c6fddf6a7c384d71b785e637cee2647dc7618df4840188593ac57b577b55ba365f1b27df5c765c478e7bc79c732ba887c930f024c7bffd04131372c2b4169da6e00d55a51ffa7d38bf835feb47fbf6c65ced91c2d1f898abcfc2d5f5e025328c7d6be8eec74d6c43c25e99d42d89831be32ba6603c13d2e3a08ed79e57f5893607c3e3f13e5006924f166c66f95cbd3f6deb735ce56ef5dc3d7ac6c578025f5fddf851a822958b92535906b091cc48fe86c57f5843e83129a207c2b255087aabee2ce1cddea4ca8709f5095309a0edd710a3225f4853618472bdc2696b512f33504e2831a2f3bc8ca516dd1567ee02ea3f9f1fae16223174544f24e046fab0515cbfed9411573d1a25b38871ef84ce8fcb8b5c4aac6a9ccad2b6ff9253ee4b471eb9905ec9f537e4b3d2104fae94caa1b7c9d15f0e9dbdbb3ed3a017ad342b37c82d97e045ca690fb8d2b3172efd193c12e292d0373f6eac33f96a2a6b15b9a276a262fc9d1bea308d6541a2ac557badc631275ea290172a76e78d0259666cdab183a423134cfa40ec9e9c08074addae42a1a1dc54261948b63931756098806ae8ae27390fdada729c84927b1440ef6661edda084bc8114bf343ffb10a1a156bce796bb59b424cad1dd6d0bb701b88ce06cc2b7076d957de187c02aba2615f9a64270d12c894aca46f89d42a7daaf984c2475c7e9fc6dd252a2a758d78eff568a8b6d6c907e08c7436d898ed7d79c511352cb4384320057ec2538412aaefcbed70f602b3158c7f69c85341696c48468da08d991ba6b8962b80b83442df677e6d8b387d67e4c9d2f2cd98f4515872b43681ca11774b28d7f87b780f8b8247fb1d9a388c8f2468e6b6d2bdc1134ad2268ad47ce56a9f026f0a50ac8af288e4bd65968142b43b8c66b1d584849ce796cf79b526f6150d19d1d427d9a019b562199bd545dfc5d35d284420fe48a965a4f92f97a159fdae7676cde3b45bad2419988e3b7153be0de72df7489015ab86fb5894da2e3a75ee04872d2ebc67b55f54653e5726f8174c1c9f5e9d38e215e924c645c2951f2d0917ded9bbbdcd7b49abe32678e658e042b31fa0a40511f30391a695f25f2772c7a17f454a88c8b5bf48cd4123dc3dd4e0f36252c211a332016225a718fbf75a4474792cd8d733251b1bface1a1ef07da64381e23ffdbc3996c09414470883fcd860d7c154394d1a178e1310c10279b545e03ba1f7d82d59e22a2a995d259cf5a15298009f477e789867e36a331c0e7ba207a05dd4ccba718c544f2a69c6a5119c094e5ce0081eecdb7064973f3e27e9c156a84e63908a14322859f1059a7bcc2b733a455c6c31b4bfe4274b07fa0b134029a961e6d6af781d7c71036e40c69e7f5cea9b4f8ae010ebc6604bcdf73a7e9dd7ce60365073af57772216be7f2dfa67134e080c7af42b9a4ebaaa6c5aff5f048fdac7456931ba44586ed915e6f1b97d51225a8590fe71a644ebd0a1ffe55a483c486ffca577e28755a572fca2aa80f2ab7bca1adb083e7433012e10e52c4b25d0603e2c25daea332dff2334314ce323043e52702c6102de83fd8dc3c7921cc1481bdfb22e97cff6bacf4b194cf228030cc1faf7c0f6a166b3b8a3b8bb4b8fd1af6b92f858620978aafc86369a07a374c87a0e1c0769b7a48f23870a5028fc0e6e6d2ce2f295f32e2051811398f0b93739cfd62bb7f864449ccd06935706a6dc9348ec8ceda132dfe1159486881fe970da500836af0d11bce62a53a23c90eac58874f765904f74da56009a47c656661f8303214e2402b130f5f95d49a58d1f3603a51747d0c80b0ca2f18620e5213d7ab7454ae8de1c39a997c8be421eea735428455d182d00d2b67a915e678b0d8c0b0e4274a6e895cb1575c12640a24ef2577c6af4b0caa15334c4aede9130d61047990bc9d23f712a95724daeb943f764222452f7b162c14d56e55e9be7782cd1af17d46b77e64424d44796af2b9252a0cd3064cf82a7be5b5cb31f4a2b14d754290a1ad0be995b72b92a5114a370e61b8cc0f0b0de7ce1abde5fcf73eb9a4aa602b98bddacc8f86d42699fb9423ef6c06034d60ca1dee8aadfe236c0e28ae8299e4a0ef9f91d8527bf92644a55f0ed5d3300b9a37be65fef204b37a25bc1238b73529e4a46af744a7f57d0e7c847d0ff6e3ac95d194e0e967933859651a7725043a01f0bfcd788daa459320a6b93ddd506b05038dd9b5847b17f037d929ad5aead32341621ba53f6e5a04a3d86619256cdcac3e9b7ea039e679a7de94347f4d7ceddc3c046a09e10dbd1eadaa39ac946ecb1088ee170eba44110ab35f668d3c5442866d1e610fdd5934e50cc414462bfafd81ec0c7da11a19474baffbd4cf41d70892c095e829f57f45eea4f30a60b9b9b3af80bc1e67415b273a1d95f18ace7bc8b2740c2700dd3c0ed659493644a0a5b536c15c5a4518c1f9f3bbb11cbb4abe8e3525985a425a1ad6957617a4e23686a4b1292e51af498c9b6573112899d95c92d23898f2529c3ba4b9a5a3e806a73f5a53cf02a9718365dda49b78deddb1b4510f23d0279913ea7b6a0e2638a9dca63815d7946b21774075a4b9b7c6b1aff62cfc11de0ad94e664d42a0cdd5774aba15d0774b95ca2a0d70374e66d298a2cfccb210419633360c717a42aa23b21613af556a096e4b3f3191037f1117873ac6b9ed792a5a917b7c9fb53f3bad87044e3583a018d1c90ed7017ca2f4ff93205aadcbf4ac3452f3459f7bf08ebcb50a6119c983d4d0e50882bca3e1820cb621610ee5e5493e59418952bc845d8bc0dc943ff54f041bc6761b608d60b84bb0f8bc8abe7cbccde9490c20fe8e9ed861c93011dddf7f644c7db59459fd9d1cd13cac1f930866cb9b459fdfa63a3844062ea97297237946d293454e6f3e0a14b6ff570e9d3d00f71c119d0d2677d6f03017d70c8ae38786644cb1dd5649d04c398508877ed1897a747e0924b33749bf970cb0271a50cd9ac45474c9aa35cc3e874a450d4aa204a5fcc10815808c56523972dcfacbcff4efa5c1d1b45cc4bb72a4bcb25cc53b20075ab8bc11a8baa2c593be15f2a14579d08ffb654c5dbbab6b99475a193c791b8c5cfbf542d4a63ccb4f2a3322d663caca266e70cd989f0ca75dd8744a614be445d7060c3d3e089eca04f3f72e8c9d2476ebb85d3847a581d329059a02589536f3a5dd68a2086aed7dc3e21f412939e5182daeebd0cd2a35fed9f1e94ed2caca91b6c226c108b00897eded06eff1186332c4ed17f2c06561661b6bd68a7392acdf4b0fc877e83cf7fc48ad32f25d93b1709e79fed7612659aa9a7357430802d1ebee80a2b178d3a6b0b33168c4f266fd0642d82c552b20fa786685581fc1a7f2b871ee12eeed0616bbf6952e94adcb20614be850bdd16e79cb50921b7d219091ed0c8c31ffe385f08d2095f62aaa3dadcbd704433f0a028574044496dafbcb415ed1ae0cc7717d436ed0f8a01bcdfdba5c744a0222f99632c8e689174d5c329916b19e760719d1b97235e5b680b382ab1fe956ee52a2fd415ff76b621db02736297724620be22233362ff29f4582213291d45dc75e9ae3e40437d9deaa1cfcf0e9d6dbffad78494cf8b37ab0f2ee4dc05d4a72db4875ab9d2001cc0f785e4fad0770b6cdccf83a0c5f71ab2b116001ca50324173d960dc970ed473f1b6660eda866cca55e944a5473b76d4d963e6ff3e8e3f90d9034c01c46e06dc0b6d2fffccabc2cba8cb6dc39ccce5ebdff4f0b7e255e630f354462fa98ea324012051ff207076d9a96d23cdd7cfbfca1967412c7638ea94f0c6ec45dad0189ee0ef81222baaecdff54e14c185ba21c325e71f21505395ed741a5bf42ffabd1a045b6e5888b0a20bb92dde6c20539681631f238736b7c56260f44c10663eba540e5866aebf5085f0d8ffbbd9f3f674f8c4bd84509afef12934a2af29c48fe588e8aa4f10e1db61e9454ce9b3dc9a239f869d28b14dc3caf9243407837a9d900889a3ead0d2981700520fd1d826abbfd183da4949696a77c09e700d4ed1fad4050ac52f9066a9fa9e2da02eaec818be67c68ecf34392f30186de4609c9e026443c5b2e6a408b75541ea3ac4d33f997a8361a82282fdf03eeac0fbb0ac548ce933a21eb1abf5ab15dfaad49433bb8a3151511b60106c8d85d31da15d6e745db5fc0677d4c848b2e8807d882bfb477cca3377ec0890e7063e165adf97f4fa7cbd3279bac7424bb959c1c977273c0da950990846802c6016f58ab44b87dc2216d525ab6808259fb764995f094092497083b493b18a8aed54fd110e890cc646f8225f2915ed4cc6c68aae284aba191f4a4b59fd3ebe798721e2446406967845276daab992f7a6bc9de0c94473b6ddffc226d058dd3085805d8d527b458691f6a5e90063d00c80eaf4bc6654192dc9bc928bcbc6f5c7e1a21f7a30937ed99333486e66f434805c2212b60a074bedc3221554c5887e58e621d557647bce191043110eb6690887db221dbb8b3800b934d44471c66fb4adc4237e8238c15663dc515b81743da25b9cbfc52cc6b1827a9d82d93b6294addf6bfa329545b28d982a16cd521c46c59bd2eaf3206d5a3913b7b3a0d32c5889506dceb546f96a0cafb43e532fbc2dae5a432cd7324fd12c41a91eca0706d417042438ca02232f544be234a36037bf5d1697ec144c5732834db59e28000ab6de1ebd169b9f91fbea229ea7743cef52e42cd12c987b75068868ad811d89392d63c85320f86a34212cc30e1b611454d1abee4c330b404b3c7bdc1be89698e49a5b06b9fc6fc1db3b00c15be9aab80035619b5248b6e5ccca344cd6b5b91124a89b40913f9c62644ec91cc65479a892918282abf15617a9b2dbab887e67b021ddcf3e3135636dd69027fec08f71f720f4039d8bb4baabf81032f4d65633c443e8c0dd384ba4965c801187d7e86fd697348c5324494cce2b148a916598e760ad8cbf656aca94cd96c4199d5a7fcae9a7be061b9149d7c3e1374854fc2efad4b64089b6ad0ecb5716aee999297e5199fd3549b3d891a27fdf59749bae10350595099748bd77bfb7dd1e5f405efdbf950a51ec1dbf4448694a13eb359a56780b8d89955c755ec9abbc5c78e3907294a5bc6e4326769a2dbefdec950f9cc5c25a363b84787768786cf823f73883c1739ccca45920aece7cb38b54d54788be1fbd3cf909e08bdace8953d6695cece371d8c10110ce98de0c525063d59c62e81d56c82cd1958025da03cc072695c8153b3b37975b072f85fac5b32ef9569d6a3d1a6eccdc904b10576eeba15ea0257a257de92449ebb8adc00896b7aec9a16c164e96d6d1ac50dbce6cb7e5adcee4aac53cded9228b900260f5f4fe62d0b4afd02f65c9697f1750c1edee1f67cebb8d969b4c4ce414a86a028fac0872a84a005ce317bf36a83c7407fc1a778bb1c44c6025535e4e1b294bb9b474cb79e2cc19a49ab96c37a6e57f52c3f32cb91f95f46c27154fde6d194c424158ef0b5d060611dad96f4bef25b3aee3b453cfd9ddcab4a8a00c33410f7428172dedc8bf49ea106450d0db188a86fac83dffa3809c1fe8624406142d4bf92c2e67ed49f6b1a3173ef45b12ff0fe7481d29b4d27832dbc70a6716b078e157ab0238a7b5702dc55d65bf9afeec7b6b928cae11529f082c537042b23d004ad38e499c51411295fe7bd5c481c02a001a70e3aa9e2a02f9d9920cad54d7f900b49bda7fa1160b9b080e0b31352a58d3bf572c814beff0c368e0cbf6650ef3ad0042e835af6f11d804a4b6183920404f72928e8c10713d7fe2339d256db33260aaea70e59eca429472717d4cdeff6fb3e4c707634d468a43816a005a5b90fbf90d11eeb12e39d2df16e6ff1e25b1335aed01b4d485791cf739cef6a0cf903a4af4c4d592c42039be195c602d8d55570b2dc893566db4c71dab4350a8b432b9ca5fa7e7d6f1aaa4fc230c170774bdc770fb223fc920cf258cbcf0ae26a12d0dc4ea14042a538c8e7b78ea6fdd05255ebc68f2ef289475d687cb554a6335c9fbca6261dd5fc05d8c386ed5315b9b0f58a8674b02b0c6d5cc6ce1bfad60e037ca5bb73bab5da748339d97bc38e3acb932f796cb725a512a9b3183474be497b58b9204e5475504a46e99508f57c709ebf41980ba57ef72d93aaee52e1a447e29e11fbc3495ec07298d8233c6bfb1844445a44f77fa27b60f1f9afa5476048304777d1cdfd9e9f41ffec5562c3b6bff58a1c45c39436c798f8dbaa2cb6fb6ac2d6332d717f099cc1f29602e0e44f5f0a42e7c385fcfa4979f2b4300bdff05917fb76543962184a20015345446fea37ce926cb6149d4f433c463fec03aa672d56aa6edf61292ed106c7976fe4536284940021e5c3b924e2231e90ed4af9fc136b6f2ac9fbd00a656c58b498e1caa8a637ee052334098206714b94f2273132110a3a53b34551ff9409ba5e60d28e5640684899bd378fd577341cb57f01c7c839eee92b84f3cea5b4de9e9529f8a38f00e5748d30b1b46cbb33969c502725442b2afc776e1583378f10796c9b98a6b801f60e55c1d9bc0dcf61923ea0ea8d34ed13a36dfb55a8a25b191a088a2780ff7c97f50cbb8095a773cc604bced9471b215f498a1d6cfff9b8e78c4fef67c23e2618400d95437085005bee6013c20b3d0a127970ace0daf65da0675384841c2fb1519c88f9a36c4114b600c54863897f49595d21f46ac93d5d89a84647fd7444e85a04a640d0f541b273f98d6a04ff702bee11ae2d9f23bf2f68e74de5159c197c38ac6d2b4aaa58f747d2c80fcaf0a68b559351807b41f70ef48d3c39f5c62764c1f37b7f99398b926d789b9430ae56a1081a780615329fd461ec22154713cf340690c5577d28db73e737a32accfb7e075067f6836d1da730b426d65a2e46abfdee324a1311ea888b3a796c063bd78955f9777003d56c05425387420ae4b7225471deb2cb6a960e66b771949ae5c20026bbf5a13d5b098ff36a07d7dc77c2a4d128c246d0ffb18c2d851d3f23e65d377cf481a40f76b20f40e092f7f0a2f95009aab54c27f9afb44fb8e4f66540b6d2ef424b7cfd0bdc3b24907119216e03326e6d740c705340f6581d358f450aea634eb07a655e8e5a126179b5e2660c52c88c0710c7ed07990a70833185d454fd966eea1bbd7d354dee37643f74e3cd656aa65342a834653e1101c1315d90c092dca1d033353a23092ee47ec588b64761dd71edb060cd43cab625cfa543159bfb260f8ff50f875276b9f341a42b630e5edee80510a0b20dc6543816b673ec7be74e34ac6433a0a1045d5f370130ea8f8f6dce042f6063801febda0fd51af44d01a5c92109aed1c2e9c65d4924471f614e0459aa06fe49dd6216d67f36d8534e59bb38692ac890a994a751045f5b47e6a6ee6d06bc39c1405d34cf0b02af5cbba5226a96adb4e1be72c5d508cea36f76c36e38e68df6b32e8847e4c24c4430b904125cbf782311ccd1944013c93510467760a0eb229779669b4530da645ccc6d2d8447019771ffd848e9c7d935f0cddc325fd5f3b67b2c2f0513f9349c806842f20e53ebcf8d29fa2b8bc1bb4f4d1bba45bf13fb011b74b191d8a8f8ab6279588afad417bdb6d52c73343f270e08eb20e0dad3a0f53f7d7e4fe6cacb774b35ba8ad5ed8f9cc698051936f404f27441b8aeed75d587b6a409eb135db6682345cbd3426ed6ebaa90dab27982040b999f8fd69a7c16d81aa99ca9824f4af2b978ef56a5dfb7575fa25ca63154f25eae91606a5f64b7d311f8b1167996910ee9e0193acd4a4b75e80ac2efe81cc4cf2be50b0e15cf0ed09913b7ec8b08b9242eb59dc4122c9f29486c4575f8723f5c0e9e175774d839db2c4ba7a91dbd592ce60c2c99e8beff58b47eadec8c17cca2cb929cc8743bd8cb7d29d754df9abf8804c1afeeb9b36475f99e3298649e98e48f2bd1b978a68eaf380d8cb4823c8f32be34041e4771171615cb49a0db3d84f8603638b188a90189c4f62e8832de97e2acd33869f382911dae8bf7c90de63568523db5e5f2e35b34d1f3599d099cbeb1c967176ca3a7060600e3eaf3287449619a991e847658d0c165c6c5c4e399ed8296fc3f41f6b2bac9f3435107fe18932e1f89f537ad352b9013f1ecf448e30be17efcbbbe4b6a796a7757042ef39075ab73efb40e068d40b3382c7e38f3ba35fab91b7aae2f0bb207f1fa30370d40a8851d00cd374c1d5d1443eb75656b2b32a5a5109373c9410190c9a6910064fdcde176583b45261c43639c76c5aef48132a530f2cc4c6cf7ede9f3d5b3175be949c0e6acefb8d3140c92e36647780d589ff5b822c8a2c807e2643d7caad7bf2c1840d734053152eb3a54bd90a51f64a52fc2596754d8ebcffba144886c1d59460ef1d8148f71e9213bf1580f1e9e800b2fd36c358265a4b8c80380632fb9ab6bf1720f6e63a90c25342af620a911c94cd15f7230f47e5c7dd859679f8115b57f814c3d01850422fda3257bb2412216a6944efa819e10023bdf24fb8f756e8e828df17584b2aa28c82aec5cfffaf2d96904130dc84b8fc4e5fbd1a986ebdbf673f8365f8159d8270939ed14c3a40aa27911775534d44de80bc26b29943c0e85ebd08e116dd27a26c09fb9f09eded1b0415fcd5aff36f2118a41d2d90c643d0a2dcd043be12d54d1372b18d35a0506fd1ea3d26538a15a5a6ae222282206bca67d5d7de78b0215170b6baffbbb0c5d4c51290fe10e0c941165e0477b2dc56c452b8f5f6817c3a6d4f42801529bd612288247d1634a3815e19c0fcefe1f29cb18876ea7c7cead6f19133c5ddb052394b9f64b3dfb83b8ff910529f29608a162b4c87bd04d375e01006c90c0b22003a4c641f089ef832046f8c7d31b3dfec47d04984bdc0bdf862122c2fa95c84b92633d25eafb31d606022229b2fb4b8b3f6b9a2d1f4d490ead591c5341ab6d701d9e2286651097d71fa361a21dfe60aec9b47ce1f4aa31757c6ec504be930c9107a45d179dabe3f6d73bed26b679303b8e3a629e5dc1a1b632f4dd883b83c33ef3ac670c00c4a74c7ad413f7b5f2b8b71980793811b5451036416705b686db209d31940df1ab7b6fc36e4d8c741ec7ca7e0866cac639c626ffcf86fdfd7e6687dfa5cd646c3c26677abc9b894007eb4f1697857323cb413aaacd1ca549fc84f5b944af87ccc83c3680ff44a8362bb09123fb11d5f3c04be4d0cecc0f7f789df1b256661d670e805b7da73411fc5630912abf5748cfea50b4647b97d83f86cbc75e9a43598f5090d10ee5e7a45f143f9b42c51c163725fd665301cc58fbb50de396d44f76b0cba456777e2ed3cdea7054ac6456a1adb9bf95ba0d12f9e046175acc72bcbaa6aaf1d5765d6e17df6ae8e1ec0cfb05fda051a221a498f4bf885edfb97f0286503dbab6ce61af4697703d5537e7bae403331e3a53dc4a9912a013cab42de07f5f45e4310bec5b033a02b7777f69232800ef02b8640be4f4c66149eee2d2b6712deb869376761833ed5c67e77fa233a5761fe4ff3e9474ee0e2be0e93d3869be0cfd3cf0e6ed8b6c0c1bfb677055ea96f0c114f1c3082efc1dcd7ad2edd2a30094e7f7e6088c5427c4214ce36c757686c568d06ef236edb05ee0aaca4e9bce2c6addff5e7ddb4c2793bef4d9e380901c73c335f4b6b17403eae22380c28372125dfbea2c1434eb81b8d09caeb3667c3b4a1f283fabf92207dca37bd2ddff6ee2cae874ea2297637a3aba7fc635d5bbee439c286484b78ed4e12da497e463fa7a27f8e3d4876b122554c1ccd76107dd4894814a104e7bb0d6ee75b8458461d863539960528f72179188797f7d594cc2c656822445ae834bd4574b6b407cd541978ddbb4db11664e14c40ec1292c3ef54c34179c09917fde3dce71590c769416f81763892b92f6c585916fa5447d4e283b871f294942f3048592c3690b54e500ad93a3cea1219b2bb6e4379b735462795392280b74e2561cb63cb1748276f085b358a9be9ed4dd329aa369b6960c182179980f2b16088d64ab176e7c977d44faa856afea8a53cf7cd54b4a644002ecd7d86a51fdf02feb69cb75cfa586bee5949ae59cd9b453c5cc3978fd84aae4f3aaf937c0220dca1ab13ab7ef1a9e1088237c71d09b4303e789c4456fe15b7212fcc00fcfa5d683a98a946e8f7e921012c0d92c5c26d38efd73bf1c811245ce8d298fd1d6d0ed1a5e3538a86d32c0b25648efbab2ad1bf8bc12b08bf7d340bcde1764d6d904246bb6b80925f5c32c2ad4db6577dee8c4c067f99a811600f9ec1990dceb2688e239fbbe53d1937c7f20ffc52bb3311cc7cc5b868172f5e6ee4e14099ebfc257574c11e2f5946a8dd8912aa3924303ba5a50b60bf57c539c13bf52a7e1f88fd18276224911a044d260171418c38dd823939ca75732aa46d5f5c08b4d2957ba129e72f4dd06b86432099b21ba67c545da7e76d4e72c8c030dd014e1dc718b69e9e72496e58ea8de57d0f06e04cde578277c8f74eeea2763d16fe28cc495a742cf8869971843ae434de6bc51bdcd593954fd3eed7de1fcac68d79a809359272dd4f0599b61eb272a2be22f062445d515dfae94789c495ed73bc0e1272682092b0b827ddccce05cd5bb204d8d48fc2448172fcf1139784f324964d9a6b48eb82b32ebe96e136fc4a835b7f41ea14908c4da00ba26adff3563146dcab993cc726b21e1b0e33bc0b072a3efd32e001289c7f575ecfb328ccf51ad9fdab95d942f629673c8cb3d9805c2c8f855ceecb696d3176a93512b938c04539d0a982fa649924eb37693a82b8481344a52517bb2270779472d92c556c0636967c8cf98c088258972a5f3513d8a8b484069714ca911909cf362d593011f8efc9cefb256dc0bb4e7e39ca13c163fbf226e3a11c115899758ba865896714aed915e4c16ab007f35f9a11b6e6d121feb26b8850afcd514d5b8cfbd93c853b03b5afd91127dfcdbe2b8740b4c751557ff428d0a7cc2db7306df551eb42b4589fd0b1b9a7719bf95cb28d07ed095af5225df033b7c271e0740f6d92eca179dd5228bf3025eae81e39211bae1c03a089babf745a5d6694e65df8b7b637a9ec46d5f8533958afd7094e0327e39c2130bfd4bf7de1c2f28594b76fe0128a06912a002d242193ecd1fadd680c355160c80c6c1ce19c103ffa5f24470a08d3e5696d829a77e4c13515f834b9f47733d81499c512a960e67e735529f6170a8b62eacf7cf9e860494d813f6101a82dbfb1f15e17119beb5b3cc2d6611afe2e0a2383f1198a37f8b59de22bcc67ee8f986e137928c643f5db7a668d6e7d71d5405c7d8ad1a59396287bd5988948ebefd2ebf62eed475e9eb387abd7ae11e233c063f72cf8c27d5d437242fc8ea3ddec1cde3779ca5ff + +Params = SHAKE256_W16_H16 +Msg = a84ac56687bde5e2d8382fd88e343a128dcc899a02ce38126675fe2a3bfd6c2ad8adf8d092ed6f7951e042f8fc60a366e191c44f3fd3d77c8dd23505273cbac651a48ff067f90af5d467c4ac525872c4140e82358591a1daf8a7bf6716a6fea003d128ae6cf80a30bc06f6057702f97133de52648641a4f8dde73ca365bdcfc6c4bc3bdec3258b61f23105ebb52ca189c7ba30fc24f0752c66c00331c28e53aa16219a85c90658c615e20ce175028b6fc01dc0aa1ae9d92f5f8fb4212c6e4e0dea138c2cfa3f79495188eda3c2405e66b410c19617e4b5a2651e086b834182a0821b5794a7c417d7084a876fc7618c96172eeb972a5f323a924b6f0530daa8898f9907fcaad6ed374590d38fbc65de46f26bd8aa70bcb59b0119bfac482a1c10b415 +PublicKey = 0b00000bf47629d9bccf46257bdbc1a8a45c3842851bdd6f2f72b3b30792f60a6f3793e0c0060334212b5b781d2516171fc02653ad4b032317df30c371226e06aa368c5c656e84b3d5bfa1db1d5f1a5c1fdfe91983e446f3d49479bfe249c7e6d9465f3b77e0e759c21997305afc2cde6cbf18bfc95abefe46c6c4c4cc0479fac110ccf7 +Signature = 0000000000007b7bc85334b501b32d2e6c0001dba9f162fba39fca916ec55bd69dc701ac4c35358bdf99f366137a9f479d537765c89f95a66bffe68e1c624152b60b81151f174a04bc3fc6f8c1173629147c380f4837acc8e5208ffbc42fcfabae556b07a06119b301121a3751a76aae1c419fb3f20f574036f27fcd3a1f4cb7a3fc7821272603a30ca7f4d121faf83b0feda40de7848ca121d0119be82ede16ca080074a780a8302b53b779e481e7813b228ce0ef01e1d603e5717842a6ff0605a89e587fd8589fcf3f3b4885b2ef38f27e035dc9f2a50feb8ba17f7cd9f9ba3a04682b80d0c5954a8ba9df261e8a90c23dbc3600cf00e394ac0fb549921964d94d2512bd6ea6880a8650eede3aef7bf5d3937c087352cd3205084ca3a9fc190a5d914e6f5ad0d5e9b63e9a6696666f8296778d0e65e6413977312e40d8fb8fdd30d392940ae5d44d0f6f9c953843223d5c24db00b9e0804d1b6679b950f2cfbeef66e54244e70bf34c499813385b94573c682be393bcbc47d128cdb7a6c7f1bee4d0b1b17c63054b4f24bcb95c50e83da65ecf74ec565802ba6fb061201cec5e0d05fa11f438a69e16ea3af9ca023f08fb26e579d9372c5f9a8f2bfa1e2e009175639ccef32f6684769069933e725ab469a5f658409cd6cdb98ef4dba95efe3680bd43df025570d1dfec681c940130b23d5f68ea90205a1c7f0c675853c9ad38ee0f87970bee0cb9e88eedbce44e21dba941c126409f0977f8d1933b481c1736c15d6f0cc887b2a63b75e42a0e12e45f7692a985963c74b635b9018a7b624104051dce0ebd93eddd6db339b79fcc694339588a5536baa391ec196ef50050da35f9e5c4980a9b23a0abaadaf95f889c05e76d9f5d81882d4953fd53e17e607b63926d264a5dc11d974e11ceb40d1123ee4d2f864feb601eee640a198454554cdd5d09a1ae1239218a5d06c8300815b8a793a068424d087ea6f11c663c2f0109f6127292e3b705d3f8f85e13ab0ea7c4f2062f50804ec04323b62bfc7aa23357f08bb07d891b12bc64a3a733eaa3e76b50b0ef6454c6b780936f4ea286b91f7a63c3451468ace53e5ea85723356a9a86271bc7273b9fb100a79efef7d276415768576bf484244811c23816980839b7de687a50c0182d87fce923dd95615709bb380ab1f4cadec1cec0804b1084cff4c596255f871f6cb26c11814836368aa548258ed99e86ca4e1109834bfc7676c14af1e249dc864030db37cd6dee7632bc8172e8d619daeb1b045b74e4f9eaf6500e5ce7adee5d70d7fe4c70e31c6f1f6a38ee06252a71c3a937134637b6a82ac8cdaed1ffb293588ef2fa8efcf919931e122c15f718ec73b3ac8cffaa18657f1e4f07b8aec1ddece9a741817f3a776b41a69b758a8af9be87d58498ce11dd0849e5cd886d3fe1a19582c3e6c572f544890abaa00f8ed2d06ca768613b7fef481755c5db2511ec0ce987d18496e9305f2293e3159a50accaa2f423bad0ed2c6dd96f2c76784cb8b101e91277f13f99a4eef94107c2bdd7f628cc8be2e12f4e94920591dc2f6bb9213417f16204e9804e73bb0226c7b0e541ec2bd022b6e3ab662dc2d9bfe6ac448e7cf5b7bd3347e681c8d382f0a83020ef8f7eaec07a4fafb3a0d7771042022a7b069091c36bc410b168375946a0928c341e9c3cedd1d53f4258c257e5d681ad55c267a2a44f0fc97d28e50e49b46341baf1fad6f96934fcdc9837c820a0f2a895b681f27c25890fa24365dacf9e36efb5ff084f3ddb2594f3ba983ad1b295b04098162a5f6e227a00a5bee90c03fea8f8497b260b6f12dd3dd54b5174e6fd4e17bd28a5873655af2fed35f71a2f7b3ba632245c3cca74636db95a4c727e6e1100694f234969fdd30ecae9a6df133eb989387672d5257673aad85278640890416daabb5ca846731cb916f0fcd32d8dd5517cb0e9b90bf8f87ba78b64ce7d42891c82bf24d40d64cab3017d7b452405f31dea9e10a13cf8cb9c86f52589ed4260446920999d548d5508f3623784494addedd7d5a2c4c47d3453c7493b98a10c7251a1577e5f1185833277ff336ff9c9687af2ff5a57e79fd1cf6c1c8e1cf2231371c2036507c17393f46ad93f1443c8e1b8031e798d3e8a43abc04c3d6a2c059b809957266c26416b0482f0e940ba4fa5afae0897744b9aee9f469fc011088871fccacbcb15a0068b55d0ad8235f6fffcaecad63814b67a959936124805b4303c5f3bc9d73e42ca738369feaf3bd292d3121f47982145f0aac4e88389f54eb4b40f4117ce875d39c572802f9df10364f278f93e93cdddff28eded75edb2bb7e732b8ba51bde16393922030a604c939f439bb6288916448bddf98b8c912da4ec125967fc6b085fc92375b9238e8ab351d9c27829847311634e6f48b8f1aeeb3160ad9315ef2e0050663a17673557ac7f9984999be66aa6777259e9e73ca00705751ed8337abd88370d372de85a696272129a1e6d09e6b0b84b387111830dd29b548661534879055d0809a85a8289efd9ad63118742006812fe050abc2dc2770cce3846891b8a5cf5c3fe92a0daca43a15af123b6a16c45bdf705e349d0b611df1829b5345b209d2581c8b9afa37b57b413909a5033917f8f478e49e539617b97e47408789a7e77af4dac2e72aac934c771b6a9d4f6c9d7310d065f4c8cdb3cb3732c9189f56cee60238f844c3fe2300d2a7a1acdedb306b084098268c813e273d13c64377cf95c2fe6528cebb00f59ea80480e0f509063df0291325cfbd616a49528576dfa292a4511573f793a0320f1585f7082598da06fb1f87c2062ffc91a438f31cab166346cb6d85b39ba5a146aaa85ab45fbbf7670f31b9a963240dc2368e97f306abfcb52b2caf8c8bbd105b0c7d8f2cf06ebe5bde9e135286fb96918978c117c5053769704edf7d0015933fb31ab3cf7ae28f35f5e9ce03e076ba6ea914a9150e94438c23e8b08990ee576d06bbce4a08150370107dd10b7b48be6d65a92ea3536eb2b6f0a2ed49abd57f4f186c5a7abbc8de2305d5633de9d8844afca54cebda3f808be9918c51fe699b1a2897fea5c2cfaaa8c859087b8edf263a1b6c7bef2729b73410930989d2ff817e2ba2e080b637d37bef6c582f2d29ad6f54215de05545bfd2d09c697e29409b6b553471be003df45344e21bd814e2bbecc17a0ac14211d7fb11e759f78fdb6e5291da71d873e00348b8e72f5561e84826e7277e149d570d9f3aec879c10b9b384d50fbe7e602ee3418a83536ca1ad7779b29849bc7caf223c79636dedec2832a67e520647dc16db836341015890c61bab1a2b37af7856995275f8858c8ed757ba7f4ab6d21a0308190732ec2aeed3739e4fcc12ee4e19ccaf19b5631152a03fc5b891f340e2e8f6b4c05c43534f0342b4d76602d36178a5a4ae4a0ff6a40c8e908786c82af3da198b8a2e4829b50d6ffffdb98905da2972119831e3531a85d26631b66670d5477efd7f7b2fc19a36c4335937440165c7b10face7a0fdb384c9bace98f90d87bec7601c96d47ac29df3d341a32b3943266ce2add12983c12adfd6d0f1756f4c1a57e65d0348e97f52a8688f8f5471462d15371b3eaf6d6d701b106a83b07a2a06f0a39a502c07e75f6ced37d694d85fb5a6cf07fdb6aaa51b240f746ae8c55a20ef5ebf1fd9c660f169130c78b20f13a67e521bed741633c3044b152c2629937d9c1f9e2bdb0374c075cc63fcc8fc9a428fa22a820773dc1f3dc063ced4e332cbe8457f6df8a307d5568be7559f82d83d1831bdd5f843239ba4b58205ec549bee88f23ddfac10a234e078f18374ff665f259eeb86ecf0b07c4e1808941b081a822441be0f0da43ad5390732f1e4c387d4571615ee2c90d4d2dbcaea99497eff564cf2d2b805e7a65df4154e71cdaef922598a341886acf102a68fe17374ece9ae3449a115fee60f69380eebb1afce3579a902205ecab00edc08f125b9634ae3226776694b55387d685432a09a0d5ca3b99a0cfc8c33508ed51395e39b63bf1282a6645e16a320149c77f7b452c07b9bae882f8ae94ada67aeac8779b8c7a16ee3021f645b6fa74d326cb73f59efc7459dd71079d6c84bca827934c0c417bb403cdf57e7d411673e042e6554373a839edd943e267f7300d176be93ad0c78e6c771bef0f76d3fd7c91db60124f7c84dfd98e058ca0a19d987c91c843d17c634ffad2f4281139278ece25ff9210d48ead262c02b5eed91c141c116e5feeaec92540f3af70d40d40e7b212ad37c523d23d04aa03ae3480a10a8da6e1ddd1ac1fed9caacd2b8571ff1be0937b0abbaaab32cf59db40204454d4cbbf6c03af7664711894c131c3670db9c6e59e3a66eba559e36c835bb85d73123553fe20ef038aa7a54f617da120d76d42541da3cd267ed5d436ad0981e3e961f5bd198cd4e83478ab9b3747b3ded542c077392128768e783cf05ee97ca0fb05b8dd7095c6409dfc9e6c5d2cbe036d9a635ed5393e3c719afdf2767252b2a1ac0a31da261bf173f14621cdd22c23f1fd6e1167959e372cec18dcff5fc914e28e6e9a287365183e1d5a204cbf0ec35f9554c76ad7c3097bf46f786a2993f9093e3cf9f7d28452a8474ace5b6fd944eb8aa35389d5dd08cdee69d00ff98d63ddf09bda385fe5462a7adb7b77c6d78e5787d1a6ba6dad5fcfb38212179da3d8188c395fb74b41c28ea1c43ae170a534321307746cf3df768d5378112df015b2b5e3ebb315ef79a64426a6e18d5056514be73921405c9d21e46da75bea73eb04241db5dfb5720f76169d5d7bf244c58962a6e407e47ad29ed756c091a0e40a13d3b02949b74eaf4689374f9160f86d0e43651316e80a93b68f380ce6a087b3e3a2e690c649ff20b8aa3f27c51cd7772749807041e5acb731c89318464c090fed119779a998e3c1cbf87e945dce00ba8e6dea2d69d5ed7306b000a4b5260c19edaa6b7da52f44e30c07a754ff76c6e9f5b54228b1e42c0ac4f9a9c5c111c7fdf97796110475223a3b2792713c4963cd530f2145d414b1d7c933766a37138f56d6272693ffc711f05609e108920478c53b3efd379011d1a6a8373a43e4b0cd3c207e47523ae5daee5252c5a5280333aa269618cd0bf9adf1f170d9f67c2b07e2da0d6f4f6c090f5352e787e7d358dbd0145c375c796165f6a472c8c8ec6ffda3320b474f767373c71bb45286fb4469b606466f4fca56f424aa2d5ed57bb8e0e2cbd08925c658a70b9108b6127bfec04bd2e117e86a1fdf0e4504b6c893432330bc3bc6fe04244d3478b4af82b5d90869fc2e6579d362dc016569c028a5debe1255639748d8b333d4fc4d3e3afca7deed2fba51daf699cf06bdb9de98dd55f7737d3fcc5bc3c8ebddfc20afe99c0202f4f3cf9378540c588e5bb195d2afbbcc2bac819ca17ce511a91af4cac77695d223dcb5419d33d21e20b28c6405325448a2d03941a1f92f870ddbdf4cfc01250e94436e0615780b46c7d4904a3eb9e16d33e6410037740d3c80c3b573a2024b6c189c7db6d9cf5a7e90534a71f5ea55b7120b9720b9b910ed1189f90167d9be68de42ecf27507b49f054aed78d632392812f08384841e158568cf6594eaaede813b6e884a8aa1a5eb523bb4b13d746d285abfc8deb182278d50a2d9376b65424d5118d952bb16db788ca2a386a09baad2f38cceddb52be50380695b035ebd86995e3890f83934df2ba707bee07a40a3d8c2eec1a3222e97768f60c65cf57900fa63c9b1fb8d407b339bfd6c7f12c8d6c831a614ec70f6676454151c5889fee528636baca9abb473206f007d28b6288bb59373afce2a249c5e17d51c4822997b968896232b484fcc07869e4caf9a0f5a361f0e9425810622798b2cee33b5e3d09ba9519b3ad229f855c6f12c6adc2403b6406c89e76fb901d2c73936849a407249c3c5354564e25ac55210ab049a0adbfe1776b0e27790ef1f8b7af4accd5ca8d1653177055ff422f3577d84d9ce53e0c4ff07f829583fb0d2589540d802510959bc4f585c395b461faadd8c573dccd2b2c4373583751084842acdf897c6042112d3ac71b4958b0cf5dbc6aaa2f0820789a3fd44790bd08b4f010c74242fab1f57648771f3a6b3068585b93d589d56ea40ea25c2a8f8b09d844c57ad196b5f11fb889956d96d5f5ff32094585a280c583838bfc3abedc93ad3e5ec54401f82f0610a66263b3c1cbe1a76b8c29c46d73485008f9a9a4815f084f008bcb094fcc2c608b3dc267328a4e751527cfd1add527623f96cadafef338804f063453e8efe42863dfde0ed607c1e669309aebdddf0fae0a40985d67e6319c61979b5cecaa7f727a52b4bb9ad6a88cb0b2ff82d22fb2c211d31cd9736bcea02b4c4389676d3395e069e154ed90a2d10e6b72f66111efe3a664ea694f908c4e9ae133e948979735f5fbea8eb20c0a9e71604501748f322f24c4acba70644198c6ea4e466833fa17d12176ee68be8f06f8f8b106c24821d3dde97cc3f7d26cffc2076c35aaf29c7c9b284ca07b38dae91ec46ea1312e637837a7d6a4e25058463b3c422ffa0dcec776ab79ad3ab032dbd1f1ecf37a23ed7e4761b27412c447b059c1301f133522cdcff149711e23d86738b3d530ab3e4def04e5a00fd8ab89e251952b449ad2fd1f63615559222df0acc3b7b622a51c6ae278956cd421572669e81455647d8d4ad82c6c79943d136ab1686d1c6968029c28f41caf57ba5084a7c0d38013ee9b31bd0aa5a3207e02d464f2b8da0049539ab0f5a4a760a1486e39166295e1936722fda1e3712afe267eee71ee7fd46035825219108d5b0b3d2d2f9f18a787be108ad95388d325378868361a9752aabf77a44b3c1160f812167af4b3f3f714a2c6bf323f0bb55bfc230ffea6679ace40aa13a3e35573e2534402144169a5d520fd498ffb435094be0324820b43a63437b0d8268bd6b5b8328135173c6fe60c32c17ab2ea00d443bf08e826efce3aac4dc2947cdf7844a52b3afd526c41db8000cee804e98f6f53400fa37529da242c4874af6d879e4bf7b1b59695eca3363f66fa46c63f3e53a75c9b2b2da82c97867749241b62ec855e9cb0728131df9839689d4f203c5b40fcd92cbfd53cebd8ad1463543fedbdcc6a98923844cd2b3cfda06c02d3f8327e2db7744f93a632fea52e67d1c372c858775af497a08fb05f8f0efde784778d4a86809a908b4cb783bcb1e7fe789d020ab2d6955c0005ef7050a35726a2cbffb584bd4a9eef5f35d0e712ad91ef079eff491a7709595cd86fe67eb380131eb83113667de35d2300dc83eb729d5eee21c88a9b890599da2d9692fce67a92aa869763ff54890000d5c23591d6669ebffb5af26feb6706c01e1ac8da06161cc04138917cd59af89abb20a416d63344d0b98120ec6d0aeea95e53885fce5924f35c9615172f0ed838efe5d7873843f7498f7b68732be3eeb551dbb37b66f21e9cd7720ce3b03e0d33c75c13f58719f14933340dbf16f5bac13a3b44db0d275a65ec8362ab1964a88c6eb175dfd7a76703be29f8fbac7e73982c21417c9ad635d22bdb848632ff27be653502413d00d91fece935a77cb68cc41d176d87fb86fa21d07c5484797449e15421b9f90fa5b414281c492d6b933790160aeca2c65ca4e1d88005b858919218ae72d6b329266110e14a34741b65869133c48a0705b31ced9701ac0c02a76d5cc06e81210550d72b7640d514006361d28a5b2b54e4b6c63e8418b3a15885c772bd9f45fc3b42f346a45ea1087ca9ab1d8eb5dd6ffae0306da4af37bfbd48a8e0547b877ee6434834eb8c52ae9181e42e25109375f3c96723f98922645a51a2d55ddb67afe6b1c874bce00562641b9345ac41c76f44d8617afd1d3660bf6a7f2a4a9d4a1d35f31b87ddb95c0039119e6e79c0bbf1d8b59521ccbe385566d5a663990f67cc62f4efbe168a25a069232fbf87f519b8fdbc8c96d432e091892caf32dd17d812bde60f81c7a43e18e49edfa7f46d4f7f93b16ce6f18fb041eaac24a94fa0c46bf5419d44139d8b03a7244f194df6974b9ec9816cda2d98352a46e4c88e07e7d80f19990cd1258c4c7dd37533b4ad28036c8368ecd95f917f18cc15832352323d2898f818dead1f07e02cc205f4f3c36b33cc84c8ee71cc26b1fc5f230825886bf209019384a3d6e66fd7bdc37ccc500cf99a1f6f90ef46c58b3ff24396298bf9bd8c6fd0637a6c2185c6f5237a06b5ce42db181617d2a30c78d382110afef9cbb8691217deb1fc936265e52f7a7414066cee5cf8ae18f30d08cee2795aaf515374e5d2b874d56c7bf756e52bb765faf4bb0714faa9c57087a19487ecc9206d889d53abe7c977e298aa105685a5db3979d2b4e49215d6280ad040a8791a6a829079729be40600feddb82a13ba500e46cb45b843e7d6181e6801758bdd584b2f00f029c449583c326fd7b50959b05ba0342aafc2dac2bf890500cf2e3f8f5eb460870de1983952035117de1eb068af87c97352582238bb652732655e3f6a93f3cbcf122aeef63ce0f5877da11eda1f0b8716552be05a3faf3c3a77232b9ff7670ba9a657f2b515739bebd97fab9bf33347b1ffa36d2937c826ebcab0f87a2af0c4ec187a13724af6a7ec3a54210f72ed09e536d3c2ff81f089b51ff1ff3c67fcf6078af2a8992f58c4ecd1ea00776fcbdc3acc6289e04ee88a55a1372c5e13d9f68e3983bc8260d7df6ca86c3a7d3c80cbc269c15e31b3eb3415658572970592287b01c56f9143d8f3b910493679521964bcbb75331ecc6b6e9ad4ca18ec651677c3b649c20678baf6c488c19e9b6f3e3589def26b4f80e7aa1a5af2e612d32b3645b0d48387a6ffb47d8a2906f18e89e07fe6fc4b751ba5dae7e4febfc06b9c4e6e612e2fb90b1e35ca7fb6d7bfbb6a348ba03b3f8402beba4fa107a6821b0e4f72e6658d9b0eabe13f9f5b345ea65fdf535c89502064f66e6f13a2e4921fe6c5c5f64923f070963ce5828550929e36e4c999c6e88428f657ecd9b8368632f899476e4c4085b7bcfba9e3aed9c08881b0c3e474fbbb43a23444664b5b1eb0dd4ac5e901aaff7190f89c628aaae911db12122b18679082a9cbd5d1a41d2c53d95fec7c05cc732b4757bafd5f4ea7f28e961b2d5f959aec587e96dc48d5685cc1c0cd8ad84900e5158194467a2302c48c5dd7896c31e292cd779d42bcf8ec36ecb1a0cc3877e949e66cde3ad2df0165bef2cbd5eead8b36094c72b24ddb65f24a5b4b7e652db741dfc9d2d56941b51d8b97d40e4880475182566dbb718513e876f41839ade3218862c97436a98608f339ecdcbbb27079a06f81e9b0dbcf6f135003d3601a0945faf1ba88fb593ec25ca0db217a5419a5a9a638900c66a6090589e9142d3a9e9e0690afea7e33f3bbed184459ee9a62b4889d21f41a8558667ae27bc616b916a569c34bd5af6b126ea4165b710382c22f5f9741207a3b4fb293cf2dbed09f324a87182b86480d7ed695be1c449958ce30f32173722af73ce6c2091533f92a5d458aa623a97ddb50f0033c224d11620503f9199c7ae40f70e2ac66cb4a056e4010ae80165e8b87e08240d8c94a17e19b7c8173c98bffe88af78d35e0075bf5cdcc10e6634b3a2bcdc5f15021facb79415980a62613be6158121260d7dbfe041dd82b4a0beb917843919cba51ac27a851975ddb902532129beea364f0e3e76ea359d8cfe4d117bab28869b5251c8b55e96816cc0f4d11563393bb904844aed260c9ee65e5c57f3e3312fe696218e3f0c568a13012ac080a2178a1a66ebf27ded1466c46211f910594b22decc78602ebd06d4a0a2e1e68d3fed8b80da9c80db2ef8768b6fe64b9be5cb386a7869828dfe34264fc89950cea8b0af49eebb5353badee6c18b8dc07bca311f9ac5b32175f5c4bc2d13f55d4ac1af0a9ac1d3baffc9c6193cc8f4ffa1f534b4f4a02742e1e6af040f8d694a6cb41d3e254476b7364fdbad88390428fb0a2e701d4be51dac5b8d097a5729b164a6ca11e18431c3b81ed56454f48690267c74703dc4ba3dbda49944392eb1f352654675389cd1b14fe33fcfe015de3b5f95ffb77660773048c28b3341b6f1e88d046d17a761c64b9667d3ea25a4b992a41e8563fde2d9eff061b3bd87ec8987b09993e7a01a030488913d664dc84539ec0df7161527ddb28b3523a3045f5fd18225c055632b76b339610320005bce58e4a4c0445721d5a5fd551b3b2815a232c128ec63bf30eb8e7b7b9aa51ff2b241012d6ca1ef67d9942f5cc7f79c2e2b0088a53cb0721a308eb881588117491b0c87efc4c5454524d61f2cfefb74e1d2e34a18990daf850316704dc1475c7489242067768548ce64983a9fab82f7623d723d8ac2c5d4d692a0e3f15a7be967a29f4b4f3413600e3537f06ca7de90170e61015f02df19aa4bd7ccccb93581b4dde251451146921e177c23845f91eac814d20653bdd934e9b66cccefaeb2108f4e2637f2f8d58dcf41d783749f1e6999c86ce4e4828b074336530761aa7ae3f89d9f397bdb74b7326a65b7a8847ac2229904579a26caee0e3f69c82ec2330162be98c38e43986276840cae62399bc9e6c419911a80c33aaf53e0e80fa636333de6a5fb91eeae038e5cf7d4cb1977185469d3fc313906781480d31ef2cf58bf060e5019e2906f30fa51954f981ed2724691aa057017d6acb604e970c7f28ebefdceebf5d4a40fab47b6c12ad726df95eb6a02500340a639a5c5ca0a7722b022a18ef296ee45d6a8c275609d2940dbec5217e60cbe58ee9c2385cea1fad467c8a4ba399f3f127457dc61189cca83b477103634f74f4d8ccb2e7f795465c89805e9fdb88a7bb619a0dfa391abcb1a25d5ba321a9b153cb5f2b54773fe85c478a28624f23fd678832a6ce1303f875741dc887c5376d91f1d935f462202130293a3a4dd2c0bdc9279685d15449a36eef85a8d7f3d3c38e89c0edaac34de943c99fc4c5dd4830a970f34e364dffd6b9ea2e3a50ad71c02e2aec08f5d45f25f6222f590462f92937bb8202fcb9913eef3217a494a0282844b62903d7ad165fe7fa2f7c39d82b4704bcb33cef72843c7665f2e28fbb84e05cae8a93291727c3067fb99fa77a7d32a756e11d184e1e4aeeda48d7e55825ae19364e3bdcff35234bf985539997d6286914166005bbd2ddb356152b1658f966cf3b24feb2f944eaec2f2747621b027083a292b1e0c74f40ee988b6d713acd9ed24c0c8d6b230263e32faa78ed3983daa4e4e94a769762b6aa7069137c32e31b6b7f71e090bb5216ec84daff62901998f3b4c81e8856df1aa1c7a8fee9e2bca8600921f87711617c185c19fa9dd6abbd9d5e7f08d6dedafca0081a415060f5d9067ca25d3141838abddd7edde9a4699b663d8d774eb1b4b3728784b5cf76a45ea5c3762ded7b100a4313b99d941d9acd7749a09d18068bd8dcaa3daae65f5078ff7b2334f6f8873048b3e7dc7335737b0e3096834e00cd32a16029b533c3f87eebf01bf0dd9ddc79b32efacdd6499fed3dd1b594d7041e8f86fd3ca12cf21396b82744a45fbb3249efc6da94d696be1bfbe6ea74e325a97d44c6ad250d9460609b65873fd25c7ef74fffe75f7efb3538475f1bf0d04b43978b5d86756725ac0524efb50325f8dc1fbdad36d0607e4df2d2baa81fc68374bb61cdad930081dde419c3a01d3376dff1013efbc17b1a4e7b110a8fd48077250b7ecd024c79454b37aa04aa2ea54487beb409ce5c3ebd8b9f565b7dfc7355917b6bb25be12ae6b1f561314abfd8ba6ee562c7e3c78916b31b2414a8f825fd9337090e6d24e7d147c9fb4c9555781f5e31156771d9b94de3c211e6e8f8d167bdfa4467093af8023c44f86a848bbb991f4b30a809058ca839eff903245c617be2069fbb134427e42f91436170480deff3075748030a4e001d8c496b7863f1dfc417a350376d620dab11af4d6e70e75ef76e03751c88a2a536c39ef55a130bfa8f87798d2792c006d48f2e2e95992e550195c12b53c46577b36a9139b9ffe6e21f21df4b0049d4db5f792a7a7dbe751724c530e9bf21e008de7d0cfd1a2455fc28e92fded18ad81f5edd31a7ff420ff10edf12a7b4996e633039adbd72635918da7e1fbbb88a7c9b0a0fbf29a1c885a105f0769a2c819eeeed6eabb1ec556b6c98cd60baa1b471b7d92f05f64df3cc0ead6fc16249e34e572dc6f8dde98ddfa37ef0bb5105012ed969599f65ba7230caeb3bfa965e597f59d34b192069906d7818725b852ff75c21fd79bc273f9c3cf997aa23bb6a7c698d7a6bca74eb03d126169dc9c4c20dcb9245e099d545b7cc1e69cb9d64aa35ae2e671fe69649a59098f569fdf1e1d213d0aaadacff4893d72bc89a1d98e57ba97fdfd8f3c6f69525c0090e1da6439cd8d595251b0ba80b35ccd53927fe8d7d1d9d062716b1974a27e2a42d018b97c42c85f1a96501361f1456477f6cacca7b108156fd9636580af7e1f0374b9f4933120c9422299766e873bfe88fabce591fac3066525d9a6ba76b75597e5c17514945ca8fb596cff868f0f3e7b9c3dfa2203ffdb887eb41f3f884a0d658848f61f55606b07d97081a4a87bb860c0c50d7a2d353b4afee64060695911f8b49cf8e2ba02753e4e099e3077f763052dab152bead9445d624af1f835b5e8708b9a8282a452c6a3999c1e9ac63a332cb68ab011679931935d7a7be1da0e784fa85ceb4c1343282af98b7b40ee1bb197d800e9f3bc6babcd9b41e834db28f230c6b0b272239bba98dc2b8aadab1760f1480be11ce5f0285256893fed74be3c65f5ac4e4940a603e9eb88ebf59c1b7690913b76902ba96a0685f121fc3d25332674349a86d365c9347525ba6ed9c1d076a1e532ced4f27f1fd5131823861192d9d306506651bbd2f46916ee410a45bf197b25e07d1a6ddc38e3b2fc7ca17cf97dbe18cdd12b80816d6ff6eee609937747c83c5460ab47af0e349bab1cbe17c1202b89b06f3f30bb095db76bc17901b40c4ed86752809ac8e6b01cd631f58a49851d7814c53aa05788c34f75f3fe41864aa302ec0f703d0c1a4052f661ae8d92e81e863debe54eb23e694ac9bda9e89574e035d7156045b4d4e8888dbcb8974f51bd0c2177fcf2136390f4cb67f26da1c6c6ba60f5ecd857fe2381c0fa56c033a706ece69f5d815c8f3c18ca7752680b762bdb43f46395650a8b40466f6ad0d0bd9c1b0e38b9fa0639b24ff0c15bff7f0acf347b5779302b4f0564cf065fb5334bdbad0b98e62d815c1ca5bca374f25056ed56aec96d56c2b4f6fa6ed39dc56c14bd44b0a281166ebeccc90f4c5e52950e3d544d67c7b342b63f464c17cb75ad28262b705ed1544d025d9d2b63eaa3734a4886bdd8c3f8839fe42f60c0 + +Params = SHAKE256_W16_H20 +Msg = +PublicKey = 0c00000c51544a5f352653430cd7baf816d6c2bf8889b556ab69270a9eaf8981a05d1a5340a60c096904643a3fe5a7418294796ce452b83ca9206f2a854f7f4678a92a5bb3c196c4c85bc1a7a8847eeae9725617755557c8f10522933f79ec8461dd792d8b5712140598d3027e5de2ae79975e6a2b36a46383792a9980652b4fcc28e5c5 +Signature = 0000000000002ee19973fac1f51067e9f8203202d7183432b8144af2ced132452b8815e2980e9224f0f99d1ac21a0723d098ab065b06ea55cb41edd88c368f10e78b2513ddc37df57e0dfa9bbb30a3d79e986e2acbdebbb879c3911e75423b816a1cb421dee63f612b1544acea2dd2f1ca240ae751816ccf0ad702603dbf7938035312a705cf7cea8b87e21cf08eec23d361d506a6dcf55d57d09dbc47c012edbfbcda31441bf54dc150b58a02a1ee2bf44140a82ed1b33b13def8988a5b9aa95658a72f9091e3308e39e292186a0f13e51a32ba69659d81c0939169fa07ab9fa12cfed3246340e2d7dde77e5400998788a47dd6431c6dd15a7bc7f4d3fdd0aeb61dd3d6550c4295800cb23e1c6dad768b0880c7e3d462ea5599b2124c7f68b2256de2f9283ba126e2835b305e88a685852a36a843827ba91a3ed9af9580f917286b62970926aa94a80b6551ad36d8ec46173b5e705adcd6aa6524382be08ada69b8ec8ef729795e80a6695826033901743425bed68546e637e919acb20448b9f684148c8e9572ebba61039640b82d1414e81d4943dbeb3ec56a79ac790d0a4b188b67676d85c458b4a76dfbe2ce7464b14ed5f25552f9e8dea774478ab417dea6dd5e72b613a772ac0be9c31cda1f4e7e4ded44cbd9f9019d533a3ed9a7d2d053dc36f913a4f772c399ed3c5eb533ccaf9da1711db7873997db8b50afb9c2dd8d374c282b13e02415f46c3ede66e58469e4c769b170dd8fccdc40b7d2ac2483da939eb4df751b5f37eb11a64eb7565bdf89e59ecc526e94b6d0342ae292fd4f0ec4acf9fe89dd41dbbdaea87687ea1c38bf3721ffded1636f0c09b9627d45961454670a632dc4a83db48acbddf53099f1912ef5fc1c999dfa3b8e15f66d0a5fb75567d3c9c495c3ffd02ac5686317ceb142aa1cda0ceddd81902ed9a4dcb372fff369b6727afcdb3b4c6fa1eb17f340aef2010f490843fb25707c64ebd5117269d5aba150f197e2c3e01e93ef3bc45067051bab62a208b2ff6bd6966049bfcbe0f57824d8fc27491405e6950249836fa7ce55128a8d752faf7ea0a1645ff0bca1a4b4f851a0a82efbf5a6f2c1e5dd78c9b757c1bed85c2c9b5328465cc7d65258abf5bd6186e5dc1d80e65f5c5466d1159bb4db411775c585d199214a771fc3f1161b34c300f43bc069b0c949b08d63c483ee3833b837d3159b867aad3b7f517b5d058bb7178dd4e9215c84a975e597d501515662e0ab279424da6412f9dee49a000802cfe9d7410197f8125936c9435d1a92a93b85979e8278a2fc1d3685adad4ac5a0b199ca8155e3b156211d6765a5e2fbf5bec793507d650c84757280496a996df3c0a5c4dc66d0ac4b4a687a864da17f43a0b49c5ff6db502ac4cc087274ce125d7e432a30c28a66d61e2b46a5828e1e25eec9bdaf21a31c2c5d172d002d7d14f3a6cbbe14801973d8b8331a920dd419abfa6697b4aaa2f242c23f58ce2ccaff6d16c7ff0d870304079866fd358818fc3e4d174ee15581c9dff7d95e7f8b7e6288d6e6220227a585be5f743fa441f9248b2b6f3541a85448a55f4bf8691facd68f9c1f3a70dfd73195d2ac885c6f8d155735cbf8591efc86562344f580074cbed95ae910660766b193bb8e554e6235582871756fe263c61489b87d95b16597786731d33e0ba81803858af91060d66c7d932ea1b98e90e4327ca5d3adb8864f9969e04f41aae948d08ee69ea5085a2901eeecb62fe5c4df11d6af90896c7a5c622dfeeb2c1b3a0cc5c1aabc2df77f64311bddf5149d8d2c0fe5cb52c4bca221822006c74fb6e2afba83ee465044efb20d7e9694d9ceaf4977da4636af38a75bf6deab0aa06d0904421ed8ef58d20319e3a0ab600566b0a1cf8e93259d47e12b9845216dce879aa3cb4b0dd417e6e4e346ffe3aef87cb3941cf853bc7747e90c99474b06e30c8fd8f0619f7c236775736cc5ab9a31ac003915123fd3f0c91d7c1e963b31b733bbe61564b9b2565929a001c97c7eda664bb97a4a9f052ef1462c246dd8c3492b80067835b7cb6d3f18858fdc9b458d095b6ffc7f5542a3df99514124629d91614a555d478932b8e7cb6ca5eb50be80f7f42575dc8d218511935203a40b9106095b2f53225272cf784d39cf5a333e5679584d5a15e1f9817f450e56ba1f7d0be13700951b4e94a8df56dcd6dfed5aa1a0f0f61a0487fd23421903246ff2a5241826ebde16d56790c01f1485304d711285c01dff11943bc92fa38520bfd72dabb92700f7062edcd5c2557a1b15c0b872c0ef8718e55f13a1455e1add258591ffb2083b0c38611fa3779a313a58c25fd07a5d09424526e9db2df35b7b78acb44846e564116cc84258e5bfce04057a16503da8da57ef6643e2422b492786685fc790238a375651a3dc2afde18ab6a002f46127e5a9695b3fed953c826acb22f22acdd181f004425efb165bef2e7dc32e1701e8fdc67166da3a896f25610d345c9a007b54ea0dba45e1bd1d502946d69ab51b4ae88c8d6ba794a8129b3220c31ab3aba2c9fbd69e6f3549b0f0344045a7bc2e41b4f9ce8a8fc776463d120dab1184681e37c5578c78fbeaacd68d73cbdcd57970221c18a9c91e3a35a7d5ba246f590f04a6f4defb02fd4e8d55b68c132e0fb47c80663b548bd0585f68124dc8b1a9a1c066a7b7c25be1ddb1f8ead957a650782dd3d7c47723def2e681b887c9085934d7c66cd32e3ef359dabd54a700dfda2219e553145f58b2c65b226eea195463b0837748307fc1789f72d496962c6a5e4f2bda13edb599bf524b684c92512b9f9d3a17b03d31b53f184b9ac0fad8c09adea331f642c3ea5eb2a06cb593f69081362ab8dd817c2e8694823fb3c61244c5230a77b67ce3adb4eacd19d5d9c059b9df2b81dfd0f23c9a2c18f6a9c29afe54290a57a2e5330d0bed868fd1c0cda9cee56dd91aba6b302c147b5e044835ff6ed268b18ae7de49d18054e01940638fe583e3ee134d8dceba0bbe7fc86d1bae8334c1c9e8a21a8ed72990bef9142e8fef51e92904b05f44e3cf7d7595caaf35f90faae14b5fc650020d471a2fb149bcea9923aae0de6428ebc79ee588a97328b4a27c92e8248c0d1c22c48b3070ca35aa247d354fefe7b936c23aed09a69ada8c39cd63c563ec0d6a30ccc4b740b0320b89d35c658e810993002561a2ac56db9968193acec2a39bf3bd515798403c8f55fe5e958d6ac24cae11abfca31ede31fdd9e81ae21ceb85f59864165b95dc2e091c88c488ed48aa1154960508ee214899c665b2100c07d11f4db150134db58d8a027db100e3bf554679684e2e023c97dfe523279f6bad9a43c59add304c9a49f166919318062f4dbab185cac7b06df0a51b3a57dc9a0541ebe67b23b5208e524c9e5d42ae3b27723ba0a9b9c88724927757cec48efee3d264d16d8a65b01e10853ad7fbccccc6c21c8cf10586248a5fbc1496977bca08f5ff23aa3756b3909933d64dea4ff8092ab880521df11a937921a07caab6e38fe758cf3cf92961b923864ff23f1778f2ff96349c6c83956a2b27cf715300b4deadb26e2ee75d7a1ede1c9e82f955c1b897b383b256f78aa52f5be437e5bf5b2fe7101bd26a8fb143afb6e7bf52d3b720fe99ccf49857d265f1d0bbecf3722a3ad940a287cff6e9a9f9ae9cf32573ef6e7756a70842b622d0a587c9c21663f7203df90ed93e230d8ff142eda60c501478c8a12b5ea6e3acad2d641ea55cbd1a9252ecd341912795e47660b1b71a546ff8338e755e67f859b742f9c725a41d3c6e16f9225df7066d250ee44adb0b24a5fb936a58ac4efef41f5815ec8209c08533d60e08d07b0fa470e50260d3ab0e97d754dc60e32a7d83495f770948e67bd06417678bd7b9c9678d1c6106d434522aae177b938cbb5b860f4d93983f260460d63985c056c8e4e4440089aba9110f6dd2a985fb01d810fc47244712c9a8af325aefa17ea6365c9d0eb60d3a112c09983621a3a20b9dbc2d0f471fd2bf29e38fde6050cb569735ac8195cb41089e2ea1afb1216ad527a1781265256051e770b35fb026bcf397006171f8f65fcf22921d14eef738bcf7033796e920dfa180b746a1199c134287c0fbeb78ebd233c7cc4e2df6a735df5fcf24a0963ffaf8a8b42f048fda71c3115177c4ed592575f09d75be760556cd6e078a189d602cf5dd29cdc8120d09355b3cb868b079dfb5f75959aaab26ffaf43afae9168d946eab4b8baee31d1b947a0a927d016bd325f4c4a27f8a424ee504b9cb54a6910889d94d96535e1fbe932213c1d6d57e78085aaf9079607ac1f7d90b62e9b115cea8c407c1744688ec308a819e73373cdf565e2d80962bf047fb8a649fcaf00d7079d91d32aa1dd21215a31a70c7d68ae81eeba0923fea7f00963446d1e9f4ad5001cef11fcb3fa1b35120dbbbed77717ab2dc5fb0c09d6687efcbcad35c6d209b66f8635513141075f1ce1341a2cb6f177a5aa3307b5e430557616673cdfd324b6abc6756de23f1be055a6b01008704cfaab86f84e75f3dc3b05803811998cfe157700c7d5d3a130626d70c0b26b5699fb7ab33e9f7f9d97d7214e760c0224c283a064bc66df57c33bbef7ce829b9ae8a136b3225a3b96ade941e980f1946da477ebe040bdac8e7be031a0eee83695c6f7f181aef8165a599b7c9258d29273cbec0eb1caea11132d0fe49c9cf93e5e4da54dfef13a8b2f0f062b3c0b24b682b1c0c43f2cd5b25792afac91ab34a0c73356ff8d323c6f7d4649e80c8a9411a48d3c8ae2482bec69e198f353664ae9fd7efb46329e92fc4b042f17af6756592ce76e97addc3c360b6b91fbc712a436410c24ba7fbc67968528ea4b9a1af6dc82a2665276556d538cf97cfa25e42a691e92adaf1d5791b91323d15b60b68d386e2a96bd06f2a97477eeb4297777b548a05bb41f0aae3060d8058a178aa2d23ef35aa2c8ab6d9a60e686adc7f1b43b334aba0078b778ca310562080504059adb33762dab65721dbcc5ed0d9c1c46e938bf2eddbc54060ca35540429fc8ea83190371097413c6dbeb3838ef3c5866c46dafd5e319158f20d2d5b5747008a959ce7dd052c0d872cdc526673f7796d3c5076f4c3919e7c0f53053c08b623c6efdac19ebac2ee19edb13065323506971145b0c58369676ee20f4a02594dde0547b2997b675cb03d473c3b487f1b779bb7f598e33c3a691f67416fa9db2300a00ac9c52296776c815ef843d10926d3c4d1c425b39da40c9d8b8dd1162b653e052cd08ae56b94a6cdf7823f5ae2b7067b2e0a7693edcf28d806e0de435faf01a9164acd9338e37019760dc1320564f7a28fec76d37f5325d2cd375ebc940cdde22e04eb485c571abeb7db79376f313f9ef7dda0036abec679a4225e2c5789e872923521d01b03ad529d375cfa7230276bb1901645bb808c3a93ba5c5e5b230b0ab677346c3cd47ce529c76776a372b9450e9b097c5db31df4470f033c2c8e78a4de2c3092a4f9b6de21a2acfa92c90543212bb9ff8c5cd952950e57be298463ccf0360f9e518795195941a669b7a6e43afd0efa4e8d13e29b1b191de3528fb93dd1ac76ed2a7a402c02d60832b2588898eccb2a482e44d382256d75047b80953f7de2246549c12286c92af5b7a4d40036a1a09e7717d7dc6c8f5a07c6b2d39a4cabf809e0b8665b3fcc214be00eb66fcd29559f15e6513f9f382ee5953b5073694b6fba7991c453448a20e90db9e1384dbce0be6d0b37a855787f694125cff55a7c4c61d06c5bb8327827c8f3d68324b6c6d2c2ed3cecf24973620a55be164dd36e50e086a7930d3925d076d10d6a1757ac14a7b54053a9f2aa654c31b85e63652a45544dcff543df6149536dd54a7d7ea092d789a81a82193c59a73d698154d7a17df1acb4a4cc381cbf75593469691def846537e991d73d2c7dbc5fab61cfdcc5a97e41318aa7711b7eeda3688766b3559a5627c2d88bc50b4c12b0b975ce2550756753de6ad6a791bb5717acca37c443544efc352400524dc62a3b75eb953fa6705958a590cdea5a2dfa9b2efb842ab2ce6dd50edbd84fb7960b18be041c1b53cf5068cb40a4486d0f8e5490b0c39f99a3dff95edddb44c6f08151d19948dcb614dbd35dd676027664ac13b2af719b47424f58d01996a4926e6fb8824f865964d72a94429ca2a852153bb806e6b700183f8c39c22a7c504dc1ee7b816b01462ca1602dac44e81668e7d63e2bebbbad6f17aa60a4c356bef849e782a048a1266f20312ddbaacabda4ec4169aabf9966a70e84613cf1e87f727e02b6c8b39039422022e58554998ae22c9895502dfda5c05de6e9a568d19d964431f6635111603d5c3a4dba6b8879d754e7eebb6f54e5f903282e56435790eb963d4b6e68942b80609c0c3aa8cabf62c58abfef4534f815d6a620b881a10c7869591fbbe7c13e0757f93023511d488d8a4002a7b1bce8b7fe35c20dd5cf2da2c11eab8e0aa5133ae0ed46261d50395facdee96cfdaa5475c6db044f4c83e5a276e2c0dec09ec5ffac5a8ead71aa62095d1f2c594cf32ee5cb0bc33f54720fb684155f0a267628ce5295c596416f71b39711ed2d05881cece47f17cb1a3eecfd313570fd5f364963c122226b55e5d64acefc21db781ef23b15b8dc0b77c5e92b4ae933ec72efe44148aaf3bef8b4e1895e85866ac17c69a1e36dcf22c3c1de2472c0edf8048e6fda1e8101091cc941f831d059e6c5f6aca5ffee0f1a1bd8fecd162fb5e44c3459aacba7bea966a6e2b940cfe599ee35f5f96a228f104de96ac8649c570d036915146561df89b9c214b137f9e9d6969d6cc1ed69a47b5d93fa6eb7b1578b33788de70d10df85d0e4448888ad226fd9ef5d5a58f430551f607f714f0cb314825da91fb674bdb03f4cc387b0a5fdfe167b0e21e4e304d9c83d436cc7eec9516ffed387d3927a59da86ae54bf06a5812f7bb967d7131b75135bdf0495211c67a180579277654759f2efd4fdd6542b1e6c27f8c7aca9b38d7e05b0a823c6413521d6c47787ca0fc2d7f44db582718b7b06e19c127867fbffd459ddff392fc81fdb513d1c18480db79ea3875c66f2d6bbd211970bb2e0e5c5cd6672a80f89928dace30cb0e724097f721f292b577b9d4a1e4e5f5a9950c0b158917c624168d4914630b1d1939dcfc0bddf52ffd83e102c0d50814be8ae4d556bba65c6759ae344d88e1565c582ea8486d042d1dad8319e854ce2d205a0d33b2adcfbbc59ad1ce76d54c0152dbc1afeb11d055d3971cbd7e3c6499abeef6f01173c2819347ebe742580a78165d0f137031b3e22882f3b3d1235b594be783363567fc4b38bde5e982dbf7cad0b5c9bd202641141354c621c491385bc9fdc6e62dc5ba4d2a8cc90fb2837ccbb638ea93be6d3a2a729f03f2be53ec8cf1d1aa8dbc0220722ca14714262ca82672d8b9245f2f2857865ec3090718904ac4394be16c43d1d737682e5104d6b75f3173352e8dc0ef40b7aeeda9bad483c50d377db9026d2e0edd80191204f7244c80cf69bd5fe28e3c9be5569f0a0f49b27d90e89300e061c0831fb955c74c1c7b3ed68616acdaf6f2b6ef2af3ab56206750b540269686cced0b93531dd1dc9454aeee18d8e2d81a357fc74689cdf2e0708ca58727c08af7717c54cd3d33e7b5275b38da73ead1694886219c6e2eff4815d6563db6e92b9e0d99fa884601efed1fe37ebb557d331174adaa412545ea54c2cadebecc0488103de96af1b8200b4e99cf0b1fceef87c0feddc30c03881806f49be676a49f4bee3bf4ac164693b2c2b80655800f505e6bc15321894169b49011213e5a9772e6ba836ce22eada4babc37a6c08eca756fdb006b679bb39a2dbfb91c073f3683db869b2b97eb8a6022a4c5a6da48413d4ad0bd8f210fd1bf3a9d3999d215816fc2468455700c611e3c1195f3dcf312f7f6afa93469e9db65b4d688fff97713185fc0247320ff539098a3cd9edf6bdb2ce168d29892343cc7153649a91d17acdafb947b1fbe0b0fa92d59219554419f0369616e693decca4134468ab0f9acce36ff590aa8d710289d19de1c5796eadd537320730f4fd9f58d377a3c44a6cde79ff12d6fa328825976f8417f49167df8fe391cb21b7eb3d38131e615472f79b73d62f305ad1a8600592c2aca1f87b0069ec0e0138902833abc2efba2bed63a5792d2c8a32f80e69538154028497d8f7ef2a1c4688d5c0926d31a19c0fef5ad110b0143496fb7e349ce275aacbd9f985624831e58992303a497a231e44a6c528714a87c028ca7055d44df1d1292883c366a44fdd1c92394868373e6c11dee399304f8a2abd3d2a3bf27aa6308beeb6141b3d8cfd9da4d82962c39585d965a366c2576b6611a23d0d1a6d1aa49ad9ad07e19a65b9ca1fb29808b1acefa5411041e1fca64996a24fa0f7b0c0a99799e630cb0f21eaefe2fd74fd07833467d574b85d9b452d8768c21fa184b631466f776956052fa3d3aab81a93672f5bbad0b9f24cb8dc60b9b296423e525687e74f9732b7d6ee7f27924e1e667ff9d0c15ba8b5b24dab573be1dd1ea983cf0bfa9edd95cb7ded61af5c74f478049bc1e50ed1aafc57952895ac4ae53e8fbc2cd848fb32e435b82a56cdb3c7b58021d720dc00be695f5d00233fd8ed2fd0c22cf297ac2345de5dfc960d15bc36bcf20011d4caa0816bd634d726f0c265d74c66132b8a3936a5210325bc582b240b5e9535f087e9c4c3bb1875b90f70ce64c46958a4f4c2aafcdff4a2f0c0375f9d40b20598b181f824247690a51900db280e250bf382b30c300707836274b16f0dc8e3972a6235ce3b555053ab49b5f81fc53cdce891473a1ab708086e66420ce43a966c93f58519412a4c97e75ce9d0a54e0282fee529932c54334ec895ff1a5a97038c966d623e75ee01f8009f915ce88103c73c2e6c462aa28a8b6358938739ffce91bffb7358411874d7ff9c3d1d2f6dd21f7bba7d0749fa803cd0006f5fa5139afdaef1d955d76e2e79558c08a29dc9976dbc717da2ccbdb1ca2c331bbb7bb69aae0d34c8fcc8d38f473223c1eea8b41bcbe05ce2c2bd1d72d5d4627af4e16fe6425c59624bf2b13c175cf6fbc367603bdc4f417fb399d58aacf31b6f16609c9dca250687e909702fddef63194ea9b0534d2ef82d1b351e242fe639c76ccaa7530cd24d4cd33cd4fd87e10fad41e5130627a555ddcc1a57315a200ef6fe105169c47d36c3b03e6a8a6c8f3919822ea5ffb428d9745e8be513306f980e69a0b0d38ac794fb38d016e09adf84ed498a9156d40be6f989fc66b0b01902af6800dff891641a9833b5e20f5e47a9fdd76125dadfd442879a19952f6dd2e8404cd0c9002fa2ea4efcdaae3370f44b919e99e8f8d4984ffa08e3c362a8e145fe3a6b213bcbbd4c20310f08d809bca8af83657af3b924a375ed7f8310aa4cfe0a43895a36c257d51a32bd649b0f1b989eea90d8980d816bb4267d01f782abdfa948efa8bd11a7db10ee22c2b63cb81940f7ca606f30aaec73e7e810e7e389e32980a255ada2b22a992219b415b48d15ad9920d806230e9894fa7208f5dd9c15d25272bcc92abcc8c55625732e42a88f7e23a3fb692b871eb81182c4417a42df26151725482066af342ec8766b206ff78097d15397ebc197b04ac48ad2932dfd9f8a6e34ab7b3f5cf7758a5c3ded83701940f01931cd9f844da3cfc2e59433f13b3e65bea88cebdce4166863f642f821043196c853b60a9c5d9d703728edea421a2c20dbb177330c4659aacf7f020ecbd646925559b26f7228cc2e305af87780de9fa55593b582c337f638fb1865c50b138cd12388936cdd7e4654e7de8eb813d71689e90243d6e8ccb149d98832281808faffba201946943bd16d2b115f751cac08ba0c46b0b56a0a7dbb0761a1ce7f71bf39c7f6277a8e1fa169e0a7eb3d4edb4b696888da8853b49e0c135b63076cf35c7bf3d10f03c0373b3c3ca8a8d5baf632245e714507c91f723a4d3022781ba48fec51666deb4d17490233265bf15bed47dd6388c9cc8b68a51306475fdf7842fdbedcc1e0b42ad181166a9101a64976bce88309b0ff0096c66ac7d0afbce7445aae6be3ef97dc2ddd17724a34d63e53384c2832e060e7e3267a655f3de56033bfed264cb8c5cd90ee0556a0c73aeed785cc56963e4fb5eafda63d61b2a3d9e162dbe471d2935e57d043516693fe20ed5b5d631d626eaea97b35222de7a227c7d2e1703fe2e31db074c168eca147cb2565085fbb8131201e5b21bc2a077323dbaa7155cf0dd7964d21bf5dfcef02f6ded3d00ebc339f0d748606077eca8ccf4b013fe47f337250267f465ea406251669793aee1f389caf8d77b225bce04d46d549ed284fb54fab689bec62f808ec9ac14080bacfe178027fcfdff55025ee3c6a69e039ddbae692f69c6a5bdc89264b6d66186f3e16be72eef6221892a8cb173d8bb79f086dd3c43e4187ddcca8a48357143c6051543b182651f794cdb11f5ec9906a3a11eaab7b3b3ae2812ebf345847d97b577f1278b981f9ba35313b09dca7da3f873c019cd73285301f32c5c85ce2309d4ac45b491b4189d50c96c3b7cd364f7f7ffa7b883dca0708f31788b79bfaa3981a99a06a9710ec80ef318ad52e9781f31bfd039fc3bdae81a5a6152c99b68c9b55ca7ddaad356aff91bc4430efebc8f7aca34b382b6fa13a8c2fd03558f919d498055b950b918b6785ccc247d78b9d76839465999007b06b2a61f8f11fb7d48ae660aaa1baa2ded921d38789ef6f3dffbea2aeccb98662772c30a89aefb8ec3daea44aee4685bdf5a5a897bf986609432874f28f548f07da63bb6c514c8ddfecb41ffabd7bbec7e61aeb9a71cd7e7c45d4bc43426641246830ee13126889aca14492694bb858801170b63851967b4990dc2dfbfa17460b3e0eb6d468951b8e2dea37ce506dda144f1cd2f9118f5811e1619373c5bfd89d909d3f4d59e9a2de2aa40daeaf71e23ad7e0019c585a161f2622dd31c5e8d7bb8263c59888e5d4158ceeef48bc3013a1b2360b2502b123e8cdf1d820d1e86104144596e20f61a9237a97555f535aba57fb1a61aa56b9bea93e569e753ac2bf5bdbb49ef54fbc1bc03d71bfe2fc4bf879fee1cab5d28db7def24cd12bdca5eb2bbf98ccdf06d3809e5c03d0fd8762982032c7d7b43915ce2dab7ad46f8f70e0fe095c9f9562dddaf4c77f9908c6ec9e82f4019434aa7e5fb4ff0babe3902ad1d4e4ba8ec8f0c7f2a2c0ab87b7188273bc59ac1ea1dca9d8e8332a02835b45a271e75276c258d9bb27f2e2b0a5d776ee9652266c33b103e567ee2d2e8de8dd0a4c9129e5e30ff12dbbcbc9fcb3ae91b089d22521234da3909ccb42a86c7a8fe2f516fcb73f0d6f31206e749f010613c4f7d5e200d6e6a94fd97abc5b41a5783be19c069d311b79d542e73c5f1f9385c31c8c893eabfc7afad4f002b1920fa22a9cac3801e51a33edafec430e552e74e663ef50e246b9a99da1302c6f708578b0317dc4e06c5fc6d31d19ef411f76345489646597a86842fff97e5d81660cd3e1a5b19661bff6518ec31f7ee67869d7cd42b13182f0ac50dfb8d53c52c3bc6898c9ec5cf9f3315cdec8cc61dfc63b883c3cb1bb5bd88e352beca1c8d386f5198b43c3bcd20bcd06d2d41e600b29c14f56a92ea223415213129ab472f65b0c1dcde6023968d453a1f4de5008900d0fa7469b55c56146af91baa2ed3aa807b2641a4791309a40c9063be015786a4a35362845cf33f217787244c7ad0e139fc292d82d0624acf41fa72e8660e27b114ee71b14bb3ded9bb8147cff7f955513d2c727d378078b2ce4860d4897dc7bd55e4ad25363864692c92c59f2a531df3f3d8e4beeb9bbc874221ac8cf77b18e15eedffb24891bc970b74de8193f167c9742aa0858ac360dcf0a09a171e30efdf752760e6f1986149cd8bd59e76a0342bc62ca95fada8194b4c47caae10288e5daccc74915eda891965c0da1a7eba75779d255cfa0046d333c3d2e078fa744bdbd66761e3041d633bde4cb2e22475d10d98e6ffde8bf7a44c3ca8e6079940a3dc4db9208ae1b28ee3882152b4bf578bebc211440c6157f288a17f05a3f5ade8a8458f01e20abb9b98aa78da68bb7a8a8111c6e7a5639b1f07825f118f2cd1c041956b7bb0203e863085a47fec8923a53735a71f7688f27daf6b46c8db7bda357c5038b567fede6724ca3d39c3dfca7be086261e6c203ec89881e4e79f33b5636b0a8e5c90835d984029266f270a7ab9a0cc2926070890b5cf552bb9b88270483f5b945c234e91524d36098975444ba54d349068cdcc2eafd544ad240b8d07673a29acce34eb0d7c4fcc8b80035ae933eeab7cb0dae4092acf4d00f92303c213d575917f40fe8c0352efe910f7c025496ed53921569c057f6c53f667cb13333acb54458441f41b86593090e60bae2c3822c059ca2c36bc64b46ad74fef88a92735207e558ceb138bf186b8f821cc4c2b226da0a82e5de71e19946fc1cc21bce31f8c4eb69969faa7efb244466d9d58da84aba98abec07c277bc6d1d66583f9282d0ffb70ff7de0698b60fbe290ed48c6f81f1c7108e1a707eaa7a755e183c17d4baa505c429a7fcc3fa2892eb67c2f661fdf1990ea9ba1e88d4f2d75ba663350a59b7511c1ea068cd3d740a2b5461a1c6b780c8720222ab37c6bbb46326ee3ff69da887411ad1d159e8b6a537a73e70e4709a323be486fe4c479e1c957e1a5c834bf08d97dec17fa3c30d3b43308fc32e7b3c81622e15b218e015aef7affc6c401ef39970f1884379fcfac0e9e60d869123228065912366076bf23e59af54e014f892a16fbc1834e55b8cb136deff4a1d3932a63578fd41a24316b0e2ac3dfe2437b8df99d49ea5ac0984f8bd5baf36d92e4a95848fae01dece64f4f9f0e5d150d1d08bdd132ecffbd836a2647fa01c3e96836846e2f23d76b3a52e297532f88e59caa08ef63c66a951ca85f592c4d484e481021036b15d9375ca80176951e22a438ca3b9a37edf75536b1f7c9d4030d89ce5d642a3f7bbdc9e8311866c56f015d53ca701410d3ffd4cbc733e49cc4bdb5942aa245cf8a041ddc1187cc09534a0eb4bbff0cdd2bb2a6c187ee1d6707fbb4bd79ee46d72eb5d484638cc38a48a5dff62c9e5d8fcca88eab2ce3ffa5b2d499062ac4b89a37535c28e63868d682625f5d8fb64faea0baaa042c61c200648f541465e8eee98e1b2fd235257a2df58fed4917d55df4eca3b38d3d33b8a5d122aa0d204ec61e44f414d68719a5f4f19a8b101d0c68e94fc9bc93af0534f7606a0ef55c5234e95ccd5b22c3ad238c5fa048c7e2d6e75776a7129eaeb19c33008dff60c08b3c50ca9879b3e582e9dd68cfc2aa41b6d3b845519b1488a234f45ab09d8e52b7965c4af76949b69874555ba79adf83e50b97647ba97ce1c14ee5298a206532074b2fe92539ab3093cb68f6c1897912fffa96491e8a84b22a9c9889f747315c174349ea45c402b827ecc6e2476d8eb3ccdab6d65a995e2ee31e2139b68094ca3fb44414456b39c5c3e7b5cf2023812f8888c153f34237cfabbc5a2b44a8c70f6819c75686a5934664bf43bffc7d0af1897f746e0069a4ae6a25d6e901708800dcf81243b34d3e5dd2ba49231d58305e0aa331f270ec539e4014cd76c529c96913d1704cb3be5871b03f64c8e83519ed9ccdd33b86bd37579094550aefd2f9cacaf54969661bc3b78d6b2d5b77ba359fc359d5 + +Params = SHAKE256_W16_H20 +Msg = a84ac56687bde5e2d8382fd88e343a128dcc899a02ce38126675fe2a3bfd6c2ad8adf8d092ed6f7951e042f8fc60a366e191c44f3fd3d77c8dd23505273cbac651a48ff067f90af5d467c4ac525872c4140e82358591a1daf8a7bf6716a6fea003d128ae6cf80a30bc06f6057702f97133de52648641a4f8dde73ca365bdcfc6c4bc3bdec3258b61f23105ebb52ca189c7ba30fc24f0752c66c00331c28e53aa16219a85c90658c615e20ce175028b6fc01dc0aa1ae9d92f5f8fb4212c6e4e0dea138c2cfa3f79495188eda3c2405e66b410c19617e4b5a2651e086b834182a0821b5794a7c417d7084a876fc7618c96172eeb972a5f323a924b6f0530daa8898f9907fcaad6ed374590d38fbc65de46f26bd8aa70bcb59b0119bfac482a1c10b415 +PublicKey = 0c00000c9c0f7a40fdcfd0632e28250df5e3baee11d089a6d15be5ec41247eeebe67009dcce94de5668eb862d80d6690ad267e26ce4dedb697dc95d9314f52524142820275d45134ec0df695e554d8047c39c919abf247fa195889240223a8a44e55b40847e4b0d6139a3bba84eaf5771600b91af17c99257fa4f9225b7bc0219864d959 +Signature = 0000000000004a4e7e4ae155ea8df546a09bb06fd62603628eb71b71ef0e8954e2e7608687c7042cfb8d7082f75d53aec95b0e0de406352f9e0bc652ed53b95a1807fc7f66a54910a86661e40e8b70dc566fd162c8075268f76ac5535d453311508962678e1210b2df5d7ef52c5975ea44e8a8c605e4ede36724d9eb3b5879883f6a8e71d8f05e1232f3685c9bc77b112949140f3d3b7abd52ebc0f6d70a32fea276549aa1b68937752d7b9974a2196f66e369039240fecbb97b32b170d26a1c02df3220be8d1af801dfbde9ab310451e6f81cba492265ea8686b56167e2cc3b8b4054c7fb35a1f536cdb4c92f39ff78c8d43281f589f39820cda347a6e6dfa6324fa0508bc0b5394e4795cfa87428930c074b4d1459227da1d2acce2486ef51c733fb51d29e65ba5edcb5c7e7f967acde30218829a711c69c11fbc483c29809ac45a6e8d1ff73217baeaa72979d0576c11d11a28d690be28e4d8016eca09aa5afd0dd46db8f9b94e22ac0de9be462eb36c78c2bb5b1d1e72738df43d4a93bbc0f18e90c3b0d93301a3c4e09d7ff421ed16fc78a97ef9fa8af9f50e78a545d2965733ef77ecee407b14f84a4e1a18dc673bb53241b47ac52320641386ae191b16e5537fbc437aa2e5ab801be640045cd88c744d41bbd658dcf0824a900fded9d8b9618431e1cd3fb4520f1696b7846ff16c26324bdd977731e1ca72037868d03780cb368b219f58b5b86550292e26c7595fae45f506d9f8404b4374526f82229a5255dc58fbd2f0b36f8e14f0640ec2338770e03359db4a0c259ead5ed6447dd476fa1912f690f2635a431913c64a1b07e33873cc645052a204220366e5952f1ae313767d7f73262d914fee8baa2ea4318bdeefbde9d9fc0a9b9fd53c20a00b69359695584546c7b2d47e6b140d20062098822d23b185146cdfab6748659c5595b67fbfbd0cdbc314ef40eb90975b121550a6a8679722da1772f6ef4bd7b2549d8e76b47413d67124aaa82596a1a593682e48d98f21b84866ec823e1acea862c5f3ff0f9042720aefeae8aa087275c0a80785a3175b16fa5a43af82bd7fde814eac24a4e428cc9d8d0beb79c81d8642bccc78d42aee3f06509d7d8c95f9c91aa1bbb54bfaf7de5c935b90aa7599622fc27593e4c0f67c1d0bbee2bf107114eede2e07143d8af75c2066b74e6aad1be10ad2acc46dc718448b79cf95dd10f438556a72ea181cc4e396969bb5b97748d1be765d063836b180f1e2ae23829bb4e55d889489e3b4d3605581a0f85caa37369efb0c33e553544210a4f8e8788bc6d3d281ff2b960c478b2b606e1c9a9ada8738e582e219d5ecf15b16edf9948235e80d6e269c13d39902e0ec6751606ecaf5a252e4427e34531a19cc74502d9ad579a09ae164a9f9f07a95ab538cb6b1388cc04e9975b83e265c42a5c1afc946ebf524ccd86222d5f5c91314043ec386ede239dc3bbeabf5d7f23e47191c59dac76c9c656efd4efeb713cb9782ab53212ef84b0fd26621b19f579677befc76fb73bca2e2cdde9089dccb963496184e91a02f0b121513ff603966235865aea028e27ca7190f199aee848f261d44df125d2f277df0e72cbed2a59790612add132af1328cec4d3c2aa2519a7adb2bfac09050abc0318933e6af8dedbc54af68a9618330158978c0d1c30f606a19e82e63225fb15d9a231c5e2b04e57e07d18deccdb772e85de40e102c143f2799d92d68c744cf103ad6cc1aa19cfcc10ab1204bf98a83558d2330c71ea3c217b259f909429da8cddf5bc7461af6cd44f78bbcee02733f3d031a4cd3591fc47e3eeed34c2f0af4352eeaca1395306f5062d6d804b3bec080e71236a1d91768f20d52ccee3f2b3375a6af1f145d0409a7dd9b5964dde40249b635680c1141e6a1b5639a75a4474e42823bb19ac7ee00d8fe14246b5835d9fc32ad2449d521522aea76ca5f100647c18291628289d9abb76b699c7e8f36e07862a57b6f0571fd6652404bcf61a15b2e871d8d198340f215ad38b7acdaddd4db5e855d6a7f3c8c7535f68411a360ecef805ca53bdf497e656453a36ab97839dd86ff9960d1af644a7a8d918a66ffa3c1bc3116eff33e89b64fae2353c45093756843c12a60d9afed9cc1c535b768f584ffc71dfcb346c9b4c9cd211a69e87c55ece2f47bd63a09039228bc245c80cb8973cc3c6cba4026f5cac9b006d4918490b8c77cdc61622297d5da655de0ffacb24de2600c25556b6c89eac8f2677afff10849c7c93799fa75e85d5e9f873c5f6d0631027063b5a5557284484a71f57e10c96dd49e20d3b263813e4700325f8564eb07c319fe9074fbf25a94b33f772a19a3e228dae1c550ac5a386d515eea7942b887c79c5ded4bb87142dbf6b531967cce406ade84d9be0f42865c9fd0159403667140716c5794eca403e66348a89c3be1ac2b578bad588de52e82a726cf8161b7f01f3447576e707f88bf4e2e5e264e14207e180b57133a77cd147a552754b00faea38a7e7353edd55a93dda1a0a78fa6a10ed5bc3b30419e9f4fd659c43e5f9b24980ab1d81ef3298cc14d6d464ee3c4a14389fe1e25164d990fc48dd97550dd45a922272e75f12628310abeea2b844ebdf912a4421d451403c4982b966a81537c9645aee93c7367c3539bc088fcf043a1bc53aabbc6c2d413c127d2a90677838e7e24df0fe2963870b06620a5fc01fcde4e38d0a68dd92219142c86d49215426a750a7ca4392b30a7467c918bf3b2b2971381f94b91e29c1885256bd5fd7f2257152056d10ed3e8faa2fb2efe40d4c5d90b5c4fa969ae9a851f35bb3c3e182c9719b7fec3bc4734b105f68250b9f497f380eb5933c379f63b51303af07942fa64d869c3d6f357a1f183397ab1c22402cdc220a68aaff7ca4a30fc94b47a18cb44fc6f1776f0d93947f351e6546ec2c046892ae45fe931a6b8f28d1650a98bb47ed1769652ed951eeab133ab84ec24100f604aa39c55dd401d55f5e7e1edb06a23ecb98be48a797beec112dbdde84212dbafce230b730f846c42eff5c0f1bc1e8099ee9f1b8a3f67eeb808122c9ef78c9abf0a055aa8070838dbb2ced6cb47087be719884b912bdf290861ca7ef8b72781d98d8fca344dd80f23b65824f2acdc42490e0b9f2021a080b1d99c7e5e83e3c3b9fa6fbbaeb3c2d1bf7eca3d6a6633cdf4cbc0168d8fc55c974ed4bd2103e9415c61cb26833e858a6d6f5a9d6742da8f87dd5a8149fc14ddd4939baec23dc8e74b029913099543f80c2bf032374f9bd1592cd04717166574040ec3ce4cb5121b0dc9aa227ae67724ab2d81c0d34fb5f11c905b6628e168bf5b9da82881030943f1b9e884b67c7e635472deca14d142ad26d29c883918dea1d2d43e75a9c749d2278ab7ed315fe6c5c21e98070cb7e0fb467e1096f9967bf9d1e199f02a45d542daa4ae829c436f98e61968219288b4dc62299bd41bc526aed6769fd0559f88c6cbb01ee5ef62e318a0c71981cc1e0953df58bdeee7e302c90effd9440cf96cce24e7e3a8491af3a55f1d9f3fc6bbd326617fc65fbc43997e152384e3febfffe2321c26b3d80cade653832480dba760e39786155ffe5c763cfae895fd710a569e522dba4383e5aa88ade675258461a5165cfd49eb6239ef81cce76a16f3ab48b15fed06465086c083746db606ce6c4d329a4c4771b457ef77a4c44269bc73a7151a8183133e7de408f3622bc96b19e04fa2522d053dae00c3989a3c697a9ff2fc7e4afe7819eecfccd9b41caea501bc2151183352c5bad07169615f1899fb2cdf17c3a5403b8725c2bdf035292f12381e27102078830bdbce17abace65cde00e9f3a8b5ff34c8d7d6d11b13643ad2d7d7a22aa7289603a5354763dd344be551988910767db64cdc18b8b996882e924ecd3d06799e8a31e643d7191061d6281d722309e1d55fae5927b37f37d1a64f30022b9dc60969c3eaca34a3270ede79635310cd266a6ff36fe76bbde7928650fc0c94ed1dd094b322eadfc931769fde95b0ce5676df87759058678a0d39602d9b757ae10acec9cfc665cbd4a16ee20b2fcf55bd5b645b1f76fd891e3a02401110d532761ecbcf54c1c35b0a4a7e868f2667bb07b422a57beb1467db6440c51ee9e8f2b8601ebcab9297aba32223670eae3a5eb96f94a31560443cbb765e1d9216221d0ee0738b571b51f0fc577a55e1525e379e1faa913c506339f42ca8c5d815ff28d2654923db2a3346124f2d0be7d3c1b418dbdf31a44b8e30ad7f26dd0abce7a5842acc713927fbb997a7e1db73f29b02ebe48ca3d5271a9fb91c2bcd9b41909b01c33a03dab709a4139179b5f22d131641b180f3eea5829f931db01959ed650ef170c5f62efc5e8bf2c2027d1a750204c131113ff7fcc7f94763b993a8d53a67adf60d6f1353759ace48076c196f0578bebd29ccf0ef3239978a5ef05eeffe1cd08c72818718d801e31e6d85eac62b6c19931359532077109c88edafac9fda52d4a2703ec8f80e946e17d5db7c50f0ec3d1f8df99d159341aff6911a12b58fe57506e8a7fd9c719088744e94900d9aef231efbc55549a45f040338424c92c756b914220cf6f1fc01c443d863028f82921d9bff6c976fd2206724ab580beade72821ca885c5e882d42396ed5a32b7b5ded7e0f4df8c89ddeb7f4ff896c6060ba7be2546f16c148a0760b79cd0da02df4315ab94a08c669cbd24625e06761b7a0a527db33a157de1419d75ec8ceb7ea668e913e32c619371dee9f89d6bbc7557ff4d0ca153cbba13ff7b9b312d130efdd70c988b507d976cd1004e73b0e2c19651ede980506528dd5504d4dfbe41f48662c143d0326cd4d3fa13562f1d5692586ac4ec98a00e06ef0bc5aea72feced9447574ab823c4e5906dc36a3979275254f0ed3b46ed6edbdb70a730735bd7215429a3609c7ff80199cab077f2fbe55737e2610f56c5cf045a293c01b87adafe90272d560155ceb2709a7b80c301c5d2117b0fd07d16ee908aa94eea20d36ddb8ea83a8f666aec368944498fb9b5df27f207f89c4116cc23cfe489090ebe753d0f19f39401e1a6ec40615269328ed0538493716a23e98d3f30ff91cdf8b4ec87f6cd7b4f3745688db6cbe998d9c5d833033b5109ce6497a764537898a5c0872c4c49c627aee84884edb9fc69073b596e001ecbcdee49fa04289fcf6bd6ecb2811351f7a79eea6d88e7862b33d4cf4ecd7916d285f95f6801e420895b67d5809cdd298e41ad327f3377f62f8fb82b53f0ebbe52482597de63f990bf1f9969efd98a904422ca46093db2497b7c2ea829162e06f00f47ffac745ff27380f63cc07bab9c8c2e84dffcda1364739732fddc82fc0a6f896140ab138f19841a041b531bed29fcee0b85777de4714184be4baf85588ff6ce226538b11e4a01e0b9269cb02cd4fc8f31b0fc1230ccacedfd56a698afb74618562f65502a3d129876aee35e79780414ca5eb76ca01109ce9ffd43ab5410a855778911f906164473b8914836a3df87eb030d60d2be24ce99ef10cc483f4c2c27dd25bf0a8314a1b65e789f486eae11c2dc13605b753d75f7561bc9a0d3c7f84c91f5b846bcf4abddf0441dd7e9ad6e78e09162c9663803f9f0bae11ad105b5d1b6c3d0e9db055cfd67e00587adea9dbece56613e5b037517a4e49362a5c00405282cc2bcf400fc9164909de14765cdac84ec25315ac4ddd95e8bd23c872c8c4195a07e4cea05d48d0eec592c03ccd7348d0fbfd2c945693bb07cb1bbf7216848598b42a1908dc685a5521d429a22ca142a5b3fee418079d51f9ea58cc36bd4a985a5332624881d6b0425002fb6f248c0471b7e25bfefebed0f2b036f82c0037e8e1d9c93e918ab84ef0c4811d92b4d979839bb6c5f6cae835a0823c498a575afff69221cf260784209af2958751f40a2b54a0983f8eacb05756d7f99a4e6bfa65593a724fb867fffbbee5500eac3317750865b83c7c834f19344717b139cf8d0db9d8fa756eda69641aa0b20e9f5b970adfcddf57206304068234a01a3cbca7eb5515488b290f99d04354d593c28d5dfd0e26dc4fd19513cb76a7f53743488161e26692095df191d687f7223f85f630839912a251d0ce470f0423f04c4aa60302d65b4f7bd5c6a7bfa82eb3f81da7db8b45a050d536bd78ad32e032f67237ac5a286bdc9e00e813668d69bc82e0e9196917e4e8b9a5b493a65ab093f4e0799df9682b7d90933bcdd463cc51a3426cb68ffdb23dd348636637a40382898237d47005058dc8228af25f837b01faaba42c2c9cc7d72df9e14a791c7e1363cba7b1e9cc17e0e5842969dafa93e8c1d4e0123dcca548d87dcf1e6810cc237a0e5c8facb7b40421c80a97b98c977e736e643f3782809aa147677fb75b4a53a8269bd5e48c37122e45b38037c187a381bc2384d80b05102f23dc41114f082b462d895fe17b5887be93cfa410dd657313ee7e5cc2ac7e636284beec10a8d3019287a74f94c294349b619666d65bb9d4fb857d22c573ce979446f5bc164bda01b5b7f9d7634355514aba168cb63a1ae012de846234ebbc7a44f1fbee1702fa0b82e774f681cdaa7c17f7e59bb4cead59712c5c65a5136c9893b5d60e7ccb3b6f602b879c6817ccec900a00b8841356480abbb5904f2bc308d23164266bc175b49592908212183f3a676de470a629195159a610e08a36e6778a024b4db6f1cf395fcf3a106a373efd889a6e87fa6bcd7a6e780c74200910392f16ca18510545237c3b8bf44085c02d28d27e88091bf69584dda7247d465fcf856ae078ac4913da36a41e1d4ca0701588d837cd8a1f0399ad0b6da064ddede0bdb8416edf3dceaaa77e473620702ae42bebe8f13b0b0155d2f50b939e52a23c7ad14f0b01685b1063f5d9d835bd4f17e864780a2af2a000bf1445aee917c395e077290ac74c331a9bca943b1054d6e1c3e9f4c44bcfd931b03707970e91ecb30fe841e1efc6bd722592f0e08c5a6ec470bfa12684dc8d57162d0243bf3991e51b2196b2615a699552c2eba966b714ce3ff5b597ad3f36272914f076aab91635e0e6beaf158d94a0cf6f8100f24d4424db3ba4c559e32cb5b4aca2c25aaf9080f9d3582562a4effa01946fb5835f02d9d7b36fd289bd42b06a01636b7711ff00f1ff7a06fd7e18d71c79bf640a6ef4821b4cd2662e26d365fac3615fa190fe7f1705b3686044e5e90250927706f3d41d82e1b93b9183e348742246abef89209b8302645e483cc1e6bb3e359d116dbfd280b85c57c2ac5dbdf269aee2b9c228fd3cfb0e36c4f24625b718ddcafa9d5cf532d8744eadff8bbc8908cdf4492a0f509d9c9d2a11add47e340758f0197c35b559614427b16c443d9da405c016815910473b0788ab7885944b8bcee1eaa80635b458c73fcb252e37a9b9d56bb8fab8358e2d268c8205b22f2d5232413f8a358a1e076d2f09927085d4c466d9f78d35be88502e2e96110da88ca94af4e606327236f76d727265ce593d0fda264d0ea5ea700d345c97fcade4d1776dde905ee66d09b79be66a40b826d26bb41cdc8acc471759198c0f2c6fb9040883654273fc22d3acc3efe2ca32a453454c75fad160df60803a2d4e547e61b788166caad013861bd94e774c645fc0dd8346fbf1c6106f3e72f53e64d5c320dbd7a467fe4bb4cbafa2955960776866302dcb40b7b44329ee360fb3e7618ae5b00a38e553bc25d4c76f5f04f5878b27beb3da7966c2b0281ad5821e0a46bddc5d8dfd3b483bcdd24ebca66b96006d68473b570eddfab123b3a8a8f212e7c5f291e225269fae10c7afb48ebea53cf8890122ddf7870c636b1382e26106d9b059c60b4ecc685e73e2b6850a56757862bf8e6f673fdac55b5280cc6d44b053e2355640cfe5d9682a2843c7fa242537b4df5c628766b807d5897a062775c0dbef7ce03b554893e9c4e77a544563366bd816e201bfab5c56846e6bc404ecf9a105c44ae97d662ff2bf26481edce378b138cd002f741e2f8ccfa471d3e6ff7ba6129361305cacc8eae956e0dc4033985f861ac9d94d2945f89448095267381f6c66aa20e408b6d9a856c59626fd4ab0930c68bde84674afb74c85b940e81f754b6763a4b05fe80ade43b090fd5b7301c34b8498fc63a5c9e14b8280807d1d8c902e2bae0a5295c9b53885c6427e5692d4671528709a54645f1f3152bd313ea049d31822511cbafb6f929651408aa5705345d800177f8aa58586edf79c8804ac317dd836fbab04df38d410597ceea63fc637175dc8bf6cba785cd3f8d5dd0ee9af3a2e8bbc4d50cd3116798e71f153fedfa4c9e8d96c34b41b94da5fd99b4541325d6610ae51961e174af62447ff50da221390e41c4328b32614d6472b8566a22705d40431a0bfc46d8e4ef926703966d506b8928ed5e02d7432fd949521c2d444d4055c4880730da83935ae40afc4156fd960f5e9e5cbbe2a6ee57d126d98e33b04e119a658e2f98b3debed7167132111cd86da56d378acfe2082d520b6cdfa2a5a9bf29a5e7ebfaafbad9703b47624044e2abb803eed7a5637fc737f3ae03224ee0b8d9bbfbd0bb669e1d1d1dd8c706e4f190783ac9f2b36b972318a45db45d73e4de1ab2f0b84d41ba4175ff6d6ff89550d7287c122a92995a66a72cbe2268c9afc2c647d575fba1df36e22bfd48e454da5d02f7f0ee89ac1d414cf9411c979a536a16681dc67c8350109b66a4945b10cf86ad1e6e294f9c46bf749efd05d53def96961c4df0d91e955b9dc3bf968d0c6147768482b24b546ad4a0fbdbdb989cf066d00030913f14b2f6ec9c8489052ac1ef4390ed5075563bb6dd40935fb894f46e0bc93f5995796b6814e963b8828db4185fbf4139bb9661070c9ed6622ff794cd89a14a06c19620818311fced1ede476d317b6f731716a8dda20e4736dcc569875384c9d2c0c7cbf99d77d3a91de819742a7856eaa7dc97d466408943a7e9dc0173a2c73691963b75c38daaee3b886c1583d66ebf0efe33ea55249efe041119cadea40d9ac7d2f90ec80abfae25f741d386bebb8ee0c9b99f0037f33ad2c3b9cf1eb26403f8f548c751f0985d7728e261ab06f493899857016f1edfc83c67d8cd1f36afeba38c31bd413734c190c12aac702bec1310d5e7f65f034f4cbcb5d753bed02fe37ccffeca32810351e84dd89865b26a7b01d0cfdf9ef08f4b375b8302169fc433dfeae64e997c55b0d38ec24a2485bf799d14869199c0090a3af4141aeb685833809381513e02b7640d0e6228814c2852bc597ed277cf00e42828ea48ea7586f9f0658d90f21a0c52e1ead507bfa362a042d1ce951b2e5daeb14d313afddaff4289356bf5baafc3fd3ef4a13d10b0e258e59b26b20ff1cf3f57bf076af4c513aacf5714ca833348a878af3cc4659452409c97d7e3e90ac41915dc37e1300b269ddf4aa8df815b9e4344f47c339fc2571e8466cee99599e9c5db81fd828f84b9d4892d8f349b47e4a03144168370e5e7fe24365658732240e443356e18f8456bfdba1c7296c183c7fd39e8997b8e4adef74c58f2aad4cafd01ef9e5353554797f7521aa32d2bbc4f14ce9631b8b304f99cf591227fede34042ae2fc30b3a9d465337c0947cdfa71bbe45a4e61e9dd7f7b6937cdfaa2b9b86200d9e6755fb3cd5957da6153e71938105f3012364c1f567c012b605746dc4af2e6a8b9b4a13d5c81b12ae56cbbe6dce283fe73b46b6d7cb9182ead966ed205a9196b49fb9658512354f09abf27d8730ce33f9668c02b4155b077fb52e715bc47263aae3c369392003aeccc2735289e90fa4ca7773e90dfe0e30720f4ddd7eb973a89f5a799f8ee6088e44b4ace304d8af69e881c02248b433bc6532212ec8bd437d3589f2165156bd37c1139e539d2420f2ef4e5f4cb07f648044e0e579a0c8d1d0751bcad2215536f8d0a2744920965ade434a404dc07031769a4f53bf38579dc0f9038c065636874133e5a8e694566c9bb5d91e1d1ffbad7dac8c0de1caf4a64c61497b905d2819ffb54cbcd8dc5f06febaaed73aaf301de30e77c8f4d0e649c89293ecd88bd08a37fceff7c80abcb2b7a33a52012a033a35001eed5f9b32cbe064970041bdd096ba1246f228fd5fb31d15e3b62ad4a71fefd2992d9942c6ab3d9812986bff3691ea2973f9280adb081f61477ed0d36954d2d695d8a91ab7af5675e493e1f68a21b5d029d509af885170b1938bc433832ea0dbe977999333c24990a1940a095526300282894c1ba8069e1ca7ea9a748a33a0556e63a08cc34e22ecd1e9b8823f925bf7785259dc054fad3102054b753ba17ddb949bc433e6ecce288dd105bb180f5bbd06143682041dcdb167ea302d6a4ee765c519c1c7f9afd60a625c5108e8b92644c1533ce5bcd780205a09fc596c799a972559f67036f253738726f5ce7f699131beabfb1d5ac00dee1ccb6a92357bfe20bd74e59e58aebf967d64e94adf358174799f2343fa227dc71cf1abc95e9489241cf55edbfd42d1d01a56ee340678c65b7a07598232868959b64ce8ec90d0c7ab0a3c38de185817b98cd233bfc6ea88f35a096a93bf7d4c450d8b7e4e7825cc74ff147b246a943dc71fa90195c5d84f8180403c3cbe0bf16764b466cef287e2e938b59c00d67985a4678161170069b525f0a93ce2eede6c8ab1bd419443b643ad8096229d0ceb85dc96cb2b04a55a24439696a6f98d5730f50b7f6f49db14f6582ccb343c471b26f4c879f0509a428e1765f480b84a63976119a22499db27d1fc99775e15b47d62822e0849d29c8d5811ec78986d803d24b7221fac3304c689f65b61d16839e3724c0415560546814b7ca61d3010c216d8350e9c521b421e073976c6281ae650f30c2b6da6e61a91f0fda14d98659caae726087ec83197f5621b537c1b75410f7607a1e95f5161f5d2056b68d57c02d2508a6077554b451d05cd5be2ce96fb4ec8267dde3b81af1b3c279b87fc82137dd53141b844de0a167013d4641821a1037961fe3bf4be7f783262959b2f931440ddf2b7536e1c0bb715540fb66036a4e6aeb9e0ffc59bda845c85b641725068de1d8026074d8cb7c065bfa7cb60da7bfab0637484139c6421c73131ec4866d28780f3b50171a64e890745a2262a063be6ec262f1d857a017df5c031f70e2801b97e23ecfe8f3ffcbacdcead35191dd77050f940b6df0e6da3151e5abc4ccf58df8e7c91c1052b0cdc9c4e7557c612f9ecff1dfcb9631b39cafd5dad3df8b4ea088358746b76c5bf1058d6caffd2d929501e340bffb52e7329abf3d708c1f2e7919727257e2a89a969bcaaf1b4770684278c1d20ee12560e5a7017be8596aa03abcb12e87ccdb7a4f91118756a2f10322f1405b81f2c65db9091cd8b36642a192f463eb37d0e6ada551b47176910370b90193a2b433f7995a50868e71bf06713df847ee74a7a801fe760fc07022fcb69d7d49d82669a356878997059c41c4211a88fffe50975dd490bcca324baf5d7264bea57744ced5ebe7dcafaee195ce533b25b49ccc57b4d8f020944930bf639daf0d36e11a53004aa5b845b9bac5e0d225b7ad4b60bf394e82cdfcbfa9ccffaaa09c3e1d74b9c5dec366f9fb505173d360360d773f669af8c412dc7ad0612fd69935cef5629b87b601fc13d7187dfa88221cedc7c6a74f13d09af15a51bff394b800c567347a12ddf8c61aaff30a716401997e53707a1b007e9f35f1d17c53d2456ed9d72d33f274de71e29cefed33b34ab7fbd4a4a5494112d0603f2f559499b3a26c19815304a8ad03d67d2ff671ddb5de79342024100dc0fd077ee352d00d7077db137b81b892ca52cf5580d4d9aedf062eae68e38a71c28f3a6c9b5e45dd59e37f1ecf40bc406801ed54883f52a805b96c052982a3ea84f2d41cb95091d0179fbd3183ffcc6415851b8b685b75277ee3bfe45cf3c92d95d45065c9951b68fa15a47ad06fdfb04fe93508d3aa8929ebfa67bcaa2fd081bcc1470f29d8f5ad6559012d6a87d18b74840d636dc792faffed514315189b0b0c234acfb3242459058b3178c0d29ef573eaa0e01c7eba3d405492de99ee4e0b6ed9dac023938814c137a3e54afab4d20708243615d5207aca695645aa1169d567773c1344b58ff81e4676135d5144db72aa2773fff72fab5065ce4f3fb879128c3fc636f35c9b792ecd77365fd9cc88af54992dcec0530fdb2593a05f50b3471ec63c5c617d38f344ac64e38889339bd05da7d9d01b56dcc4d25882fc91121d3e592044b2809ca6298e841bdc58c7706fd5bfbb4c29d26276c6a834e89561e5c4182df08ed1e984c6ee125e5aefe13efbb4290639c84660ef04bb03dcd1601dd002b8d328fbd4cac780375ce79842cf97d0db08ae30d58edd97bcb8035a21c1c04f14d3b7a1682ecfaede853f2ae308030478d0d1686d261c3bcff36f1b1b09af53c5be50cb879caba49ec85c5f797597a03f7889feae3518e9f6a01fd64688b6cd9d2df00fe605f20d663139f3f8e1824a7425837c0e17d24db202d843ccbbf071e3ae0f6e47cf874948490e43df6afc63e4c1fa1562332c8dc23ee9ee67d9f99c61124b13a34b5e06579671ff957a6e0bf345e1cdd754721beee3371ffe548a28da503f72151952303c311f008f6bd24a2dc010eec74e13ce66c8c1f55b467324ff895eadafbea73bc98bfc0735d8707d0bdb08e3173f459bfac0cdb0ce7af45cbd832bf36c2507aca87c934c5cb541da5525e731492b82a8f7a8ffd34060c5aab7f5b8c5164bc859d683d2c0c9ffc68945958e4d7b17678825580e5ab76e2cc3f172bf6354c9f39d937a96e07028dbd239f5414191c8af8e7eb877e9ae1d567117a39ba913ac658009ef0fbf3dc4b701089c4c3822adc7ec923d45498e77ff28baa0987b4dcce973030ca4fa3fa5fcfcf9d57e21fad39d58d862bbc25a15de666c33047c7e9f859f811afe93cabcb026ff8a94933d76c70ccb8d2a20607e47fb8ce68ea0acd0e3a9d32bf12ed6cea17faabc6778944517deff7ddf6acfdcd3ac60fc21269ccc277cecc7a5837f21bbfecc37664cce6d9bc4f7ae3ee3c2366ab7432f8dcae2ae501c86405dfdef8a488be4edee4dec538638cad2585b85bf95ed55055483a7512cbc70f64f031d803b400aa90cd1e31ee23c3e7f5cdc4b4ada1ee50b329593333496e6cfd06bdb3e32da12d3146146113150759c16eeb9ec7e43b78dd2c49681f1bb29c112463fe7c1dd943da579ca973fca81bbd349bc8a6b47f5565c1cf284a4298c97bd99fda6c1c7c1bc02a7898876f5d1c0300194a099f134b5c45fab8342bf33161b131c6e3ef9d0a8002870ddace8e8b12392dd973007dcfebc2e1de393c485bdf3bc71a96d489c15009baeedde46abf647d60b5519b3cc9efd781fd0d3d94d80f5c8843fb35f36298684cf9b774da3a5f77c3309ea4f01897ad954f5f6d931098f19dcc686eafc2137341197851d9fba48888548b94b1e0cf30f67f155672033b8e44dd59b209cb13fe6b9173e9c3c3ce207ac0f05a9e978179d18d54e0b026d024146877282ffbcb1e20063cc091101ceca06e4c52a7b10be2edac0a12557076e6438bedbca7fa9a65a99dc21ad1d598ec3ad221d67f16c7ea5873928985c4c6f07f5f0d2462a852b16d3e0ef6b2e95f762e04b26e44c63f5381a54e6d75a2018de0a2c97e5cf184f34ea85b70390098c2be7d7d0aa33ccf2e585a5e4edc88462e207a5fa726f6bfac0307e154279530404341998f5b055 + diff --git a/src/tests/data/tls-policy/datagram.txt b/src/tests/data/tls-policy/datagram.txt new file mode 100644 index 000000000..e78429238 --- /dev/null +++ b/src/tests/data/tls-policy/datagram.txt @@ -0,0 +1,23 @@ +allow_tls10 = false +allow_tls11 = false +allow_tls12 = false +allow_dtls10 = false +allow_dtls12 = true +ciphers = ChaCha20Poly1305 AES-256/GCM AES-128/GCM AES-256/CCM AES-128/CCM AES-256 AES-128 +macs = AEAD +signature_hashes = SHA-512 SHA-384 SHA-256 +signature_methods = ECDSA RSA +key_exchange_methods = CECPQ1 ECDH DH +ecc_curves = x25519 secp256r1 secp521r1 secp384r1 brainpool256r1 brainpool384r1 brainpool512r1 +allow_insecure_renegotiation = false +include_time_in_hello_random = true +allow_server_initiated_renegotiation = false +hide_unknown_users = false +server_uses_own_ciphersuite_preferences = true +negotiate_encrypt_then_mac = true +session_ticket_lifetime = 86400 +dh_group = modp/ietf/2048 +minimum_dh_group_size = 1024 +minimum_ecdh_group_size = 255 +minimum_rsa_bits = 2048 +minimum_signature_strength = 110 diff --git a/src/tests/data/tls-policy/default.txt b/src/tests/data/tls-policy/default.txt new file mode 100644 index 000000000..eb4ee245c --- /dev/null +++ b/src/tests/data/tls-policy/default.txt @@ -0,0 +1,23 @@ +allow_tls10 = true +allow_tls11 = true +allow_tls12 = true +allow_dtls10 = false +allow_dtls12 = true +ciphers = ChaCha20Poly1305 AES-256/GCM AES-128/GCM AES-256/CCM AES-128/CCM AES-256 AES-128 +macs = AEAD SHA-256 SHA-384 SHA-1 +signature_hashes = SHA-512 SHA-384 SHA-256 +signature_methods = ECDSA RSA +key_exchange_methods = CECPQ1 ECDH DH +ecc_curves = x25519 secp256r1 secp521r1 secp384r1 brainpool256r1 brainpool384r1 brainpool512r1 +allow_insecure_renegotiation = false +include_time_in_hello_random = true +allow_server_initiated_renegotiation = false +hide_unknown_users = false +server_uses_own_ciphersuite_preferences = true +negotiate_encrypt_then_mac = true +session_ticket_lifetime = 86400 +dh_group = modp/ietf/2048 +minimum_dh_group_size = 1024 +minimum_ecdh_group_size = 255 +minimum_rsa_bits = 2048 +minimum_signature_strength = 110 diff --git a/src/tests/data/tls-policy/strict.txt b/src/tests/data/tls-policy/strict.txt new file mode 100644 index 000000000..2f8dfbb3d --- /dev/null +++ b/src/tests/data/tls-policy/strict.txt @@ -0,0 +1,23 @@ +allow_tls10 = false +allow_tls11 = false +allow_tls12 = true +allow_dtls10 = false +allow_dtls12 = true +ciphers = ChaCha20Poly1305 AES-256/GCM AES-128/GCM +macs = AEAD +signature_hashes = SHA-512 SHA-384 +signature_methods = ECDSA RSA +key_exchange_methods = CECPQ1 ECDH +ecc_curves = x25519 secp256r1 secp521r1 secp384r1 brainpool256r1 brainpool384r1 brainpool512r1 +allow_insecure_renegotiation = false +include_time_in_hello_random = true +allow_server_initiated_renegotiation = false +hide_unknown_users = false +server_uses_own_ciphersuite_preferences = true +negotiate_encrypt_then_mac = true +session_ticket_lifetime = 86400 +dh_group = modp/ietf/2048 +minimum_dh_group_size = 1024 +minimum_ecdh_group_size = 255 +minimum_rsa_bits = 2048 +minimum_signature_strength = 110 diff --git a/src/tests/data/tls-policy/suiteb.txt b/src/tests/data/tls-policy/suiteb.txt new file mode 100644 index 000000000..77e7ce5a0 --- /dev/null +++ b/src/tests/data/tls-policy/suiteb.txt @@ -0,0 +1,23 @@ +allow_tls10 = false +allow_tls11 = false +allow_tls12 = true +allow_dtls10 = false +allow_dtls12 = false +ciphers = AES-128/GCM +macs = AEAD +signature_hashes = SHA-256 +signature_methods = ECDSA +key_exchange_methods = ECDH +ecc_curves = secp256r1 +allow_insecure_renegotiation = false +include_time_in_hello_random = true +allow_server_initiated_renegotiation = false +hide_unknown_users = false +server_uses_own_ciphersuite_preferences = true +negotiate_encrypt_then_mac = true +session_ticket_lifetime = 86400 +dh_group = modp/ietf/2048 +minimum_dh_group_size = 1024 +minimum_ecdh_group_size = 255 +minimum_rsa_bits = 2048 +minimum_signature_strength = 128 diff --git a/src/tests/data/x509test/expected.txt b/src/tests/data/x509test/expected.txt index 23cc9daf1..14782ecf8 100644 --- a/src/tests/data/x509test/expected.txt +++ b/src/tests/data/x509test/expected.txt @@ -1,4 +1,4 @@ -InvalidExtendedKeyUsage.pem:Invalid usage +InvalidExtendedKeyUsage.pem:Certificate does not allow the requested usage InvalidIntCAFlag.pem:CA certificate not allowed to issue certs InvalidIntCAKeyUsage.pem:CA certificate not allowed to issue certs InvalidIntCALen.pem:Certificate chain too long @@ -6,7 +6,7 @@ InvalidIntCALoop.pem:Loop in certificate chain InvalidIntCASelfSign.pem:Cannot establish trust InvalidIntCAVersionOne.pem:CA certificate not allowed to issue certs InvalidIntCAVersionTwo.pem:CA certificate not allowed to issue certs -InvalidKeyUsage.pem:Invalid usage +InvalidKeyUsage.pem:Certificate does not allow the requested usage InvalidName.pem:Certificate does not match provided name InvalidNameAltName.pem:Certificate does not match provided name InvalidNameAltNameWithSubj.pem:Certificate does not match provided name diff --git a/src/tests/main.cpp b/src/tests/main.cpp index cf61ea0b0..3fa6ce4ab 100644 --- a/src/tests/main.cpp +++ b/src/tests/main.cpp @@ -35,7 +35,7 @@ namespace { class Test_Runner : public Botan_CLI::Command { public: - Test_Runner() : Command("test --threads=0 --soak=5 --drbg-seed= --data-dir= --pkcs11-lib= --log-success *suites") {} + Test_Runner() : Command("test --threads=0 --soak=5 --run-online-tests --drbg-seed= --data-dir= --pkcs11-lib= --log-success *suites") {} std::string help_text() const override { @@ -76,6 +76,7 @@ class Test_Runner : public Botan_CLI::Command const size_t soak_level = get_arg_sz("soak"); const std::string drbg_seed = get_arg("drbg-seed"); const bool log_success = flag_set("log-success"); + const bool run_online_tests = flag_set("run-online-tests"); const std::string data_dir = get_arg_or("data-dir", "src/tests/data"); const std::string pkcs11_lib = get_arg("pkcs11-lib"); @@ -179,7 +180,8 @@ class Test_Runner : public Botan_CLI::Command throw Botan_Tests::Test_Error("No usable RNG enabled in build, aborting tests"); } - Botan_Tests::Test::setup_tests(soak_level, log_success, data_dir, pkcs11_lib, rng.get()); + Botan_Tests::Test::setup_tests(soak_level, log_success, run_online_tests, + data_dir, pkcs11_lib, rng.get()); const size_t failed = run_tests(req, output(), threads); diff --git a/src/tests/test_aead.cpp b/src/tests/test_aead.cpp index 24352a536..ed94d75ba 100644 --- a/src/tests/test_aead.cpp +++ b/src/tests/test_aead.cpp @@ -32,6 +32,8 @@ class AEAD_Tests : public Text_Based_Test std::unique_ptr<Botan::AEAD_Mode> enc(Botan::get_aead(algo, Botan::ENCRYPTION)); + result.test_eq("AEAD encrypt output_length is correct", enc->output_length(input.size()), expected.size()); + // First some tests for reset() to make sure it resets what we need it to // set garbage values enc->set_key(mutate_vec(key)); @@ -132,6 +134,8 @@ class AEAD_Tests : public Text_Based_Test std::unique_ptr<Botan::AEAD_Mode> dec(Botan::get_aead(algo, Botan::DECRYPTION)); + result.test_eq("AEAD decrypt output_length is correct", dec->output_length(input.size()), expected.size()); + // First some tests for reset() to make sure it resets what we need it to // set garbage values dec->set_key(mutate_vec(key)); diff --git a/src/tests/test_block.cpp b/src/tests/test_block.cpp index 82ab0618d..48d6230c3 100644 --- a/src/tests/test_block.cpp +++ b/src/tests/test_block.cpp @@ -36,7 +36,7 @@ class Block_Cipher_Tests : public Text_Based_Test if(!cipher) { - result.note_missing(algo + " from " + provider_ask); + result.test_failure("Cipher " + algo + " supported by " + provider_ask + " but not found"); continue; } @@ -54,6 +54,14 @@ class Block_Cipher_Tests : public Text_Based_Test cipher->clear(); cipher->set_key(key); + + // Test that clone works and does not affect parent object + std::unique_ptr<Botan::BlockCipher> clone(cipher->clone()); + result.confirm("Clone has different pointer", cipher.get() != clone.get()); + result.test_eq("Clone has same name", cipher->name(), clone->name()); + clone->set_key(Test::rng().random_vec(cipher->maximum_keylength())); + + // have called set_key on clone: process input values std::vector<uint8_t> buf = input; cipher->encrypt(buf); @@ -67,6 +75,7 @@ class Block_Cipher_Tests : public Text_Based_Test cipher->clear(); result.test_eq(provider, "decrypt", buf, input); + } return result; diff --git a/src/tests/test_certstor.cpp b/src/tests/test_certstor.cpp index 13f8891a7..693630e54 100644 --- a/src/tests/test_certstor.cpp +++ b/src/tests/test_certstor.cpp @@ -54,7 +54,7 @@ Test::Result test_certstor_insert_find_remove_test( if(priv) { - result.test_eq("Got wrong private key",key->pkcs8_private_key(),priv->pkcs8_private_key()); + result.test_eq("Got wrong private key",key->private_key_bits(),priv->private_key_bits()); auto rev_certs = store.find_certs_for_key(*priv); diff --git a/src/tests/test_compression.cpp b/src/tests/test_compression.cpp index d8dcdb410..ff3b03cbe 100644 --- a/src/tests/test_compression.cpp +++ b/src/tests/test_compression.cpp @@ -12,6 +12,8 @@ namespace Botan_Tests { +#if defined(BOTAN_HAS_COMPRESSION) + namespace { const char* text_str = @@ -50,8 +52,6 @@ const char* text_str = "All mimsy were the borogoves," "And the mome raths outgrabe."; -#if defined(BOTAN_HAS_COMPRESSION) - class Compression_Tests : public Test { public: @@ -75,6 +75,8 @@ class Compression_Tests : public Test continue; } + result.test_ne("Not the same name", c->name(), d->name()); + const Botan::secure_vector<uint8_t> empty; const Botan::secure_vector<uint8_t> all_zeros(text_len, 0); const Botan::secure_vector<uint8_t> random_binary = Test::rng().random_vec(text_len); @@ -140,8 +142,8 @@ class Compression_Tests : public Test BOTAN_REGISTER_TEST("compression", Compression_Tests); -#endif - } +#endif + } diff --git a/src/tests/test_hash.cpp b/src/tests/test_hash.cpp index dc93bb4d1..2ff74d1f2 100644 --- a/src/tests/test_hash.cpp +++ b/src/tests/test_hash.cpp @@ -38,7 +38,7 @@ class Hash_Function_Tests : public Text_Based_Test if(!hash) { - result.note_missing(algo + " from " + provider_ask); + result.test_failure("Hash " + algo + " supported by " + provider_ask + " but not found"); continue; } @@ -63,12 +63,19 @@ class Hash_Function_Tests : public Text_Based_Test result.test_eq(provider, "hashing after clear", hash->final(), expected); + // TODO: feed in random pieces to fully test buffering if(input.size() > 1) { hash->update(input[0]); hash->update(&input[1], input.size() - 1); result.test_eq(provider, "hashing split", hash->final(), expected); } + + if(hash->hash_block_size() > 0) + { + // GOST-34.11 uses 32 byte block + result.test_gte("If hash_block_size is set, it is large", hash->hash_block_size(), 32); + } } return result; diff --git a/src/tests/test_kdf.cpp b/src/tests/test_kdf.cpp index 50034de0e..ec3688fef 100644 --- a/src/tests/test_kdf.cpp +++ b/src/tests/test_kdf.cpp @@ -44,6 +44,11 @@ class KDF_KAT_Tests : public Text_Based_Test result.test_eq("name", kdf->name(), kdf_name); result.test_eq("derived key", kdf->derive_key(outlen, secret, salt, label), expected); + // Test that clone works + std::unique_ptr<Botan::KDF> clone(kdf->clone()); + result.confirm("Clone has different pointer", kdf.get() != clone.get()); + result.test_eq("Clone has same name", kdf->name(), clone->name()); + return result; } diff --git a/src/tests/test_mac.cpp b/src/tests/test_mac.cpp index 33972fabc..be897143b 100644 --- a/src/tests/test_mac.cpp +++ b/src/tests/test_mac.cpp @@ -46,7 +46,7 @@ class Message_Auth_Tests : public Text_Based_Test if(!mac) { - result.note_missing(algo + " from " + provider_ask); + result.test_failure("MAC " + algo + " supported by " + provider_ask + " but not found"); continue; } @@ -72,6 +72,13 @@ class Message_Auth_Tests : public Text_Based_Test mac->start(iv); mac->update(input); + // Test that clone works and does not affect parent object + std::unique_ptr<Botan::MessageAuthenticationCode> clone(mac->clone()); + result.confirm("Clone has different pointer", mac.get() != clone.get()); + result.test_eq("Clone has same name", mac->name(), clone->name()); + clone->set_key(key); + clone->update(Test::rng().random_vec(32)); + result.test_eq(provider + " correct mac", mac->verify_mac(expected.data(), expected.size()), true); if(input.size() > 2) diff --git a/src/tests/test_mceliece.cpp b/src/tests/test_mceliece.cpp index 1d581e938..693d7d2c1 100644 --- a/src/tests/test_mceliece.cpp +++ b/src/tests/test_mceliece.cpp @@ -62,8 +62,8 @@ class McEliece_Keygen_Encrypt_Test : public Text_Based_Test Test::Result result("McEliece keygen"); - result.test_eq("public key fingerprint", hash_bytes(mce_priv.x509_subject_public_key()), fprint_pub); - result.test_eq("private key fingerprint", hash_bytes(mce_priv.pkcs8_private_key()), fprint_priv); + result.test_eq("public key fingerprint", hash_bytes(mce_priv.public_key_bits()), fprint_pub); + result.test_eq("private key fingerprint", hash_bytes(mce_priv.private_key_bits()), fprint_priv); rng.clear(); rng.initialize_with(encrypt_seed.data(), encrypt_seed.size()); @@ -120,7 +120,7 @@ class McEliece_Tests : public Test if(!hash) throw Test_Error("Hash " + hash_algo + " not available"); - hash->update(key.pkcs8_private_key()); + hash->update(key.private_key_bits()); return Botan::hex_encode(hash->final()); } @@ -130,7 +130,7 @@ class McEliece_Tests : public Test if(!hash) throw Test_Error("Hash " + hash_algo + " not available"); - hash->update(key.x509_subject_public_key()); + hash->update(key.public_key_bits()); return Botan::hex_encode(hash->final()); } @@ -153,8 +153,8 @@ class McEliece_Tests : public Test Botan::McEliece_PrivateKey sk1(Test::rng(), param_sets[i].code_length, t); const Botan::McEliece_PublicKey& pk1 = sk1; - const std::vector<byte> pk_enc = pk1.x509_subject_public_key(); - const Botan::secure_vector<byte> sk_enc = sk1.pkcs8_private_key(); + const std::vector<byte> pk_enc = pk1.public_key_bits(); + const Botan::secure_vector<byte> sk_enc = sk1.private_key_bits(); Botan::McEliece_PublicKey pk(pk_enc); Botan::McEliece_PrivateKey sk(sk_enc); diff --git a/src/tests/test_ocsp.cpp b/src/tests/test_ocsp.cpp new file mode 100644 index 000000000..41faa5edf --- /dev/null +++ b/src/tests/test_ocsp.cpp @@ -0,0 +1,205 @@ +/* +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "tests.h" + +#if defined(BOTAN_HAS_OCSP) + #include <botan/ocsp.h> + #include <botan/x509path.h> + #include <botan/certstor.h> + #include <botan/calendar.h> +#endif + +namespace Botan_Tests { + +#if defined(BOTAN_HAS_OCSP) + +class OCSP_Tests : public Test + { + private: + std::vector<uint8_t> slurp_data_file(const std::string& path) + { + const std::string fsname = Test::data_file(path); + std::ifstream file(fsname.c_str(), std::ios::binary); + if(!file.good()) + throw Test_Error("Error reading from " + fsname); + + std::vector<uint8_t> contents; + + while(file.good()) + { + std::vector<uint8_t> buf(4096); + file.read(reinterpret_cast<char*>(buf.data()), buf.size()); + size_t got = file.gcount(); + + if(got == 0 && file.eof()) + break; + + contents.insert(contents.end(), buf.data(), buf.data() + got); + } + + return contents; + } + + std::shared_ptr<const Botan::X509_Certificate> load_test_X509_cert(const std::string& path) + { + return std::make_shared<const Botan::X509_Certificate>(Test::data_file(path)); + } + + std::shared_ptr<const Botan::OCSP::Response> load_test_OCSP_resp(const std::string& path) + { + return std::make_shared<const Botan::OCSP::Response>(slurp_data_file(path)); + } + + Test::Result test_response_parsing() + { + Test::Result result("OCSP response parsing"); + + // Simple parsing tests + const std::vector<std::string> ocsp_input_paths = { + "ocsp/resp1.der", + "ocsp/resp2.der", + "ocsp/resp3.der" + }; + + for(std::string ocsp_input_path : ocsp_input_paths) + { + try + { + Botan::OCSP::Response resp(slurp_data_file(ocsp_input_path)); + result.test_success("Parsed input " + ocsp_input_path); + } + catch(Botan::Exception& e) + { + result.test_failure("Parsing failed", e.what()); + } + } + + return result; + } + + Test::Result test_request_encoding() + { + Test::Result result("OCSP request encoding"); + + const Botan::X509_Certificate end_entity(Test::data_file("ocsp/gmail.pem")); + const Botan::X509_Certificate issuer(Test::data_file("ocsp/google_g2.pem")); + + try + { + const Botan::OCSP::Request bogus(end_entity, issuer); + result.test_failure("Bad arguments (swapped end entity, issuer) accepted"); + } + catch(Botan::Invalid_Argument&) + { + result.test_success("Bad arguments rejected"); + } + + const Botan::OCSP::Request req(issuer, end_entity); + const std::string expected_request = "ME4wTKADAgEAMEUwQzBBMAkGBSsOAwIaBQAEFPLgavmFih2NcJtJGSN6qbUaKH5kBBRK3QYWG7z2aLV29YG2u2IaulqBLwIIQkg+DF+RYMY="; + + result.test_eq("Encoded OCSP request", + req.base64_encode(), + expected_request); + + return result; + } + + Test::Result test_response_verification() + { + Test::Result result("OCSP request check"); + + std::shared_ptr<const Botan::X509_Certificate> ee = load_test_X509_cert("ocsp/randombit.pem"); + std::shared_ptr<const Botan::X509_Certificate> ca = load_test_X509_cert("ocsp/letsencrypt.pem"); + std::shared_ptr<const Botan::X509_Certificate> trust_root = load_test_X509_cert("ocsp/geotrust.pem"); + + const std::vector<std::shared_ptr<const Botan::X509_Certificate>> cert_path = { ee, ca, trust_root }; + + std::shared_ptr<const Botan::OCSP::Response> ocsp = load_test_OCSP_resp("ocsp/randombit_ocsp.der"); + + Botan::Certificate_Store_In_Memory certstore; + certstore.add_certificate(trust_root); + + // Some arbitrary time within the validity period of the test certs + const auto valid_time = Botan::calendar_point(2016,11,20,8,30,0).to_std_timepoint(); + + std::vector<std::set<Botan::Certificate_Status_Code>> ocsp_status = Botan::PKIX::check_ocsp( + cert_path, + { ocsp }, + { &certstore }, + valid_time); + + if(result.test_eq("Expected size of ocsp_status", ocsp_status.size(), 1)) + { + if(result.test_eq("Expected size of ocsp_status[0]", ocsp_status[0].size(), 1)) + { + result.confirm("Status good", ocsp_status[0].count(Botan::Certificate_Status_Code::OCSP_RESPONSE_GOOD)); + } + } + + return result; + } + +#if defined(BOTAN_HAS_ONLINE_REVOCATION_CHECKS) + Test::Result test_online_request() + { + Test::Result result("OCSP online check"); + + std::shared_ptr<const Botan::X509_Certificate> ee = load_test_X509_cert("ocsp/randombit.pem"); + std::shared_ptr<const Botan::X509_Certificate> ca = load_test_X509_cert("ocsp/letsencrypt.pem"); + std::shared_ptr<const Botan::X509_Certificate> trust_root = load_test_X509_cert("ocsp/identrust.pem"); + + const std::vector<std::shared_ptr<const Botan::X509_Certificate>> cert_path = { ee, ca, trust_root }; + + Botan::Certificate_Store_In_Memory certstore; + certstore.add_certificate(trust_root); + + std::vector<std::set<Botan::Certificate_Status_Code>> ocsp_status = Botan::PKIX::check_ocsp_online( + cert_path, + { &certstore }, + std::chrono::system_clock::now(), + std::chrono::milliseconds(3000), + true); + + if(result.test_eq("Expected size of ocsp_status", ocsp_status.size(), 2)) + { + if(result.test_eq("Expected size of ocsp_status[0]", ocsp_status[0].size(), 1)) + { + result.confirm("Status good", ocsp_status[0].count(Botan::Certificate_Status_Code::OCSP_RESPONSE_GOOD)); + } + if(result.test_eq("Expected size of ocsp_status[1]", ocsp_status[1].size(), 1)) + { + result.confirm("Status good", ocsp_status[1].count(Botan::Certificate_Status_Code::OCSP_RESPONSE_GOOD)); + } + } + + return result; + } +#endif + + public: + std::vector<Test::Result> run() override + { + std::vector<Test::Result> results; + + results.push_back(test_request_encoding()); + results.push_back(test_response_parsing()); + results.push_back(test_response_verification()); + +#if defined(BOTAN_HAS_ONLINE_REVOCATION_CHECKS) + if(Test::run_online_tests()) + results.push_back(test_online_request()); +#endif + + return results; + } + }; + +BOTAN_REGISTER_TEST("ocsp", OCSP_Tests); + +#endif + +} diff --git a/src/tests/test_pbkdf.cpp b/src/tests/test_pbkdf.cpp index 393a96243..af2cdd498 100644 --- a/src/tests/test_pbkdf.cpp +++ b/src/tests/test_pbkdf.cpp @@ -24,6 +24,12 @@ class PBKDF_KAT_Tests : public Text_Based_Test Test::Result run_one_test(const std::string& pbkdf_name, const VarMap& vars) override { + const size_t outlen = get_req_sz(vars, "OutputLen"); + const size_t iterations = get_req_sz(vars, "Iterations"); + const std::vector<uint8_t> salt = get_req_bin(vars, "Salt"); + const std::string passphrase = get_req_str(vars, "Passphrase"); + const std::vector<uint8_t> expected = get_req_bin(vars, "Output"); + Test::Result result(pbkdf_name); std::unique_ptr<Botan::PBKDF> pbkdf(Botan::PBKDF::create(pbkdf_name)); @@ -33,11 +39,7 @@ class PBKDF_KAT_Tests : public Text_Based_Test return result; } - const size_t outlen = get_req_sz(vars, "OutputLen"); - const size_t iterations = get_req_sz(vars, "Iterations"); - const std::vector<uint8_t> salt = get_req_bin(vars, "Salt"); - const std::string passphrase = get_req_str(vars, "Passphrase"); - const std::vector<uint8_t> expected = get_req_bin(vars, "Output"); + result.test_eq("Expected name", pbkdf->name(), pbkdf_name); const Botan::secure_vector<byte> derived = pbkdf->derive_key(outlen, passphrase, salt.data(), salt.size(), iterations).bits_of(); diff --git a/src/tests/test_pk_pad.cpp b/src/tests/test_pk_pad.cpp new file mode 100644 index 000000000..79448e63f --- /dev/null +++ b/src/tests/test_pk_pad.cpp @@ -0,0 +1,69 @@ +/* +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "tests.h" + +#if defined(BOTAN_HAS_PK_PADDING) + #include <botan/emsa.h> + #include <botan/eme.h> +#endif + +namespace Botan_Tests { + +#if defined(BOTAN_HAS_PK_PADDING) + +class EME_Decoding_Tests : public Text_Based_Test + { + public: + EME_Decoding_Tests() : + Text_Based_Test("pk_pad_eme", + std::vector<std::string>{"RawCiphertext","ValidInput"}, + std::vector<std::string>{"Plaintext"}) {} + + Test::Result run_one_test(const std::string& algo, const VarMap& vars) override + { + Test::Result result(algo + " Decoding"); + + std::unique_ptr<Botan::EME> eme(Botan::get_eme(algo)); + + if(eme == nullptr) + { + result.note_missing(algo); + return result; + } + + const std::vector<uint8_t> ciphertext = get_req_bin(vars, "RawCiphertext"); + const std::vector<uint8_t> plaintext = get_opt_bin(vars, "Plaintext"); + const bool is_valid = get_req_bool(vars, "ValidInput"); + + if(is_valid == false) + result.test_eq("Plaintext value is empty for invalid EME inputs", plaintext.size(), 0); + + uint8_t valid_mask = 0; + Botan::secure_vector<byte> decoded = + eme->unpad(valid_mask, ciphertext.data(), ciphertext.size()); + + result.confirm("EME valid_mask has expected value", valid_mask == 0x00 || valid_mask == 0xFF); + result.test_eq("EME decoding valid/invalid matches", valid_mask == 0xFF, is_valid); + + if(is_valid && valid_mask == 0xFF) + { + result.test_eq("EME decoded plaintext correct", decoded, plaintext); + } + + // TODO: also test that encoding is accepted + + return result; + } + }; + +BOTAN_REGISTER_TEST("pk_pad_eme", EME_Decoding_Tests); + +#endif + +} + + diff --git a/src/tests/test_pkcs11_high_level.cpp b/src/tests/test_pkcs11_high_level.cpp index 7b4be9e08..cf3fdac62 100644 --- a/src/tests/test_pkcs11_high_level.cpp +++ b/src/tests/test_pkcs11_high_level.cpp @@ -918,7 +918,7 @@ Test::Result test_ecdsa_privkey_export() ECDSA_PrivateKey exported = pk.export_key(); result.test_success("ECDSA private key export was successful"); result.confirm("Check exported key valid", exported.check_key(Test::rng(), true)); - result.test_eq("Check exported key contents", exported.pkcs8_private_key(), priv_key.pkcs8_private_key()); + result.test_eq("Check exported key contents", exported.private_key_bits(), priv_key.private_key_bits()); pk.destroy(); return result; @@ -1330,6 +1330,7 @@ Test::Result test_rng_generate_random() PKCS11_RNG rng(test_session.session()); + result.confirm("RNG already seeded", rng.is_seeded()); std::vector<byte> random(20); rng.randomize(random.data(), random.size()); result.test_ne("random data generated", random, std::vector<byte>(20)); diff --git a/src/tests/test_pubkey.cpp b/src/tests/test_pubkey.cpp index a96097de1..293756db9 100644 --- a/src/tests/test_pubkey.cpp +++ b/src/tests/test_pubkey.cpp @@ -36,12 +36,9 @@ void check_invalid_signatures(Test::Result& result, const std::vector<uint8_t> zero_sig(signature.size()); result.test_eq("all zero signature invalid", verifier.verify_message(message, zero_sig), false); - std::vector<uint8_t> bad_sig = signature; - for(size_t i = 0; i < Test::soak_level(); ++i) { - while(bad_sig == signature) - bad_sig = Test::mutate_vec(bad_sig, true); + const std::vector<uint8_t> bad_sig = Test::mutate_vec(signature); if(!result.test_eq("incorrect signature invalid", verifier.verify_message(message, bad_sig), false)) @@ -56,14 +53,11 @@ void check_invalid_ciphertexts(Test::Result& result, const std::vector<uint8_t>& plaintext, const std::vector<uint8_t>& ciphertext) { - std::vector<uint8_t> bad_ctext = ciphertext; - size_t ciphertext_accepted = 0, ciphertext_rejected = 0; for(size_t i = 0; i < Test::soak_level(); ++i) { - while(bad_ctext == ciphertext) - bad_ctext = Test::mutate_vec(bad_ctext, true); + const std::vector<uint8_t> bad_ctext = Test::mutate_vec(ciphertext); try { @@ -94,59 +88,79 @@ PK_Signature_Generation_Test::run_one_test(const std::string&, const VarMap& var Test::Result result(algo_name() + "/" + padding + " signature generation"); - std::unique_ptr<Botan::Private_Key> privkey = load_private_key(vars); + std::unique_ptr<Botan::Private_Key> privkey; + try + { + privkey = load_private_key(vars); + } + catch(Botan::Lookup_Error& e) + { + result.note_missing(e.what()); + return result; + } + std::unique_ptr<Botan::Public_Key> pubkey(Botan::X509::load_key(Botan::X509::BER_encode(*privkey))); - for(auto&& sign_provider : possible_pk_providers()) + std::vector<std::unique_ptr<Botan::PK_Verifier>> verifiers; + + for(std::string verify_provider : possible_pk_providers()) { - std::unique_ptr<Botan::PK_Signer> signer; + std::unique_ptr<Botan::PK_Verifier> verifier; try { - signer.reset(new Botan::PK_Signer(*privkey, Test::rng(), padding, Botan::IEEE_1363, sign_provider)); + verifier.reset(new Botan::PK_Verifier(*pubkey, padding, Botan::IEEE_1363, verify_provider)); } catch(Botan::Lookup_Error&) { - //result.test_note("Skipping signing with " + sign_provider); + //result.test_note("Skipping verifying with " + verify_provider); continue; } + result.test_eq("KAT signature valid", verifier->verify_message(message, signature), true); + + check_invalid_signatures(result, *verifier, message, signature); + verifiers.push_back(std::move(verifier)); + } + + for(auto&& sign_provider : possible_pk_providers()) + { std::unique_ptr<Botan::RandomNumberGenerator> rng; if(vars.count("Nonce")) { rng.reset(test_rng(get_req_bin(vars, "Nonce"))); } - const std::vector<uint8_t> generated_signature = - signer->sign_message(message, rng ? *rng : Test::rng()); + std::unique_ptr<Botan::PK_Signer> signer; + + std::vector<uint8_t> generated_signature; + + try + { + signer.reset(new Botan::PK_Signer(*privkey, Test::rng(), padding, Botan::IEEE_1363, sign_provider)); + + generated_signature = signer->sign_message(message, rng ? *rng : Test::rng()); + } + catch(Botan::Lookup_Error&) + { + //result.test_note("Skipping signing with " + sign_provider); + continue; + } if(sign_provider == "base") { result.test_eq("generated signature matches KAT", generated_signature, signature); } - - for(auto&& verify_provider : possible_pk_providers()) + else if(generated_signature != signature) { - std::unique_ptr<Botan::PK_Verifier> verifier; - - try - { - verifier.reset(new Botan::PK_Verifier(*pubkey, padding, Botan::IEEE_1363, verify_provider)); - } - catch(Botan::Lookup_Error&) + for(std::unique_ptr<Botan::PK_Verifier>& verifier : verifiers) { - //result.test_note("Skipping verifying with " + verify_provider); - continue; + if(!result.test_eq("generated signature valid", + verifier->verify_message(message, generated_signature), true)) + { + result.test_failure("generated signature", generated_signature); + } } - - if(!result.test_eq("generated signature valid", - verifier->verify_message(message, generated_signature), true)) - { - result.test_failure("generated signature", generated_signature); - } - - check_invalid_signatures(result, *verifier, message, signature); - result.test_eq("KAT signature valid", verifier->verify_message(message, signature), true); } } @@ -198,6 +212,26 @@ PK_Encryption_Decryption_Test::run_one_test(const std::string&, const VarMap& va //std::unique_ptr<Botan::Public_Key> pubkey(Botan::X509::load_key(Botan::X509::BER_encode(*privkey))); Botan::Public_Key* pubkey = privkey.get(); + std::vector<std::unique_ptr<Botan::PK_Decryptor>> decryptors; + + for(auto&& dec_provider : possible_pk_providers()) + { + std::unique_ptr<Botan::PK_Decryptor> decryptor; + + try + { + decryptor.reset(new Botan::PK_Decryptor_EME(*privkey, Test::rng(), padding, dec_provider)); + } + catch(Botan::Lookup_Error&) + { + continue; + } + + result.test_eq(dec_provider, "decryption of KAT", decryptor->decrypt(ciphertext), plaintext); + check_invalid_ciphertexts(result, *decryptor, plaintext, ciphertext); + } + + for(auto&& enc_provider : possible_pk_providers()) { std::unique_ptr<Botan::PK_Encryptor> encryptor; @@ -225,29 +259,15 @@ PK_Encryption_Decryption_Test::run_one_test(const std::string&, const VarMap& va result.test_eq(enc_provider, "generated ciphertext matches KAT", generated_ciphertext, ciphertext); } - - for(auto&& dec_provider : possible_pk_providers()) + else if(generated_ciphertext != ciphertext) { - std::unique_ptr<Botan::PK_Decryptor> decryptor; - - try + for(std::unique_ptr<Botan::PK_Decryptor>& dec : decryptors) { - decryptor.reset(new Botan::PK_Decryptor_EME(*privkey, Test::rng(), padding, dec_provider)); - } - catch(Botan::Lookup_Error&) - { - continue; - } - - result.test_eq(dec_provider, "decryption of KAT", decryptor->decrypt(ciphertext), plaintext); - check_invalid_ciphertexts(result, *decryptor, plaintext, ciphertext); - - if(generated_ciphertext != ciphertext) - { - result.test_eq(dec_provider, "decryption of generated ciphertext", - decryptor->decrypt(generated_ciphertext), plaintext); + result.test_eq("decryption of generated ciphertext", + dec->decrypt(generated_ciphertext), plaintext); } } + } return result; @@ -363,6 +383,9 @@ std::vector<Test::Result> PK_Key_Generation_Test::run() result.confirm("Key passes self tests", key.check_key(Test::rng(), true)); + result.test_gte("Key has reasonable estimated strength (lower)", key.estimated_strength(), 64); + result.test_lt("Key has reasonable estimated strength (upper)", key.estimated_strength(), 512); + // Test PEM public key round trips OK try { diff --git a/src/tests/test_rng.cpp b/src/tests/test_rng.cpp index f7cf3585e..5b2ce0dd0 100644 --- a/src/tests/test_rng.cpp +++ b/src/tests/test_rng.cpp @@ -12,6 +12,10 @@ #include <botan/hmac_drbg.h> #endif +#if defined(BOTAN_HAS_AUTO_RNG) + #include <botan/auto_rng.h> +#endif + #if defined(BOTAN_HAS_ENTROPY_SOURCE) #include <botan/entropy_src.h> #endif @@ -540,6 +544,97 @@ BOTAN_REGISTER_TEST("hmac_drbg_unit", HMAC_DRBG_Unit_Tests); #endif +#if defined(BOTAN_HAS_AUTO_RNG) + +class AutoSeeded_RNG_Tests : public Test + { + private: + Test::Result auto_rng_tests() + { + Test::Result result("AutoSeeded_RNG"); + + Botan::Entropy_Sources no_entropy_for_you; + Botan::Null_RNG null_rng; + + result.test_eq("Null_RNG is null", null_rng.is_seeded(), false); + + try + { + Botan::AutoSeeded_RNG rng(no_entropy_for_you); + result.test_failure("AutoSeeded_RNG should have rejected useless entropy source"); + } + catch(Botan::PRNG_Unseeded&) + { + result.test_success("AutoSeeded_RNG rejected empty entropy source"); + } + + try + { + Botan::AutoSeeded_RNG rng(null_rng); + } + catch(Botan::PRNG_Unseeded&) + { + result.test_success("AutoSeeded_RNG rejected useless RNG"); + } + + try + { + Botan::AutoSeeded_RNG rng(null_rng, + no_entropy_for_you); + } + catch(Botan::PRNG_Unseeded&) + { + result.test_success("AutoSeeded_RNG rejected useless RNG+entropy sources"); + } + + Botan::AutoSeeded_RNG rng; + + result.test_eq("AutoSeeded_RNG::name", rng.name(), + std::string("HMAC_DRBG(") + BOTAN_AUTO_RNG_HMAC + ")"); + + result.confirm("AutoSeeded_RNG starts seeded", rng.is_seeded()); + rng.random_vec(16); // generate and discard output + rng.clear(); + result.test_eq("AutoSeeded_RNG unseeded after calling clear", rng.is_seeded(), false); + + // AutoSeeded_RNG automatically reseeds as required: + rng.random_vec(16); + result.confirm("AutoSeeded_RNG can be reseeded", rng.is_seeded()); + + result.confirm("AutoSeeded_RNG ", rng.is_seeded()); + rng.random_vec(16); // generate and discard output + rng.clear(); + result.test_eq("AutoSeeded_RNG unseeded after calling clear", rng.is_seeded(), false); + + const size_t no_entropy_bits = rng.reseed(no_entropy_for_you, 256, std::chrono::milliseconds(300)); + result.test_eq("AutoSeeded_RNG can't reseed from nothing", no_entropy_bits, 0); + result.test_eq("AutoSeeded_RNG still unseeded", rng.is_seeded(), false); + + rng.random_vec(16); // generate and discard output + result.confirm("AutoSeeded_RNG can be reseeded", rng.is_seeded()); + + rng.clear(); + + return result; + } + + public: + std::vector<Test::Result> run() override + { + std::vector<Test::Result> results; + + results.push_back(auto_rng_tests()); + + return results; + } + + }; + +BOTAN_REGISTER_TEST("auto_rng_unit", AutoSeeded_RNG_Tests); + +#endif + + } } diff --git a/src/tests/test_stream.cpp b/src/tests/test_stream.cpp index d53777593..0af0be12c 100644 --- a/src/tests/test_stream.cpp +++ b/src/tests/test_stream.cpp @@ -47,7 +47,7 @@ class Stream_Cipher_Tests : public Text_Based_Test if(!cipher) { - result.note_missing(algo + " from " + provider_ask); + result.test_failure("Stream " + algo + " supported by " + provider_ask + " but not found"); continue; } @@ -58,6 +58,8 @@ class Stream_Cipher_Tests : public Text_Based_Test if(nonce.size()) { + if(!cipher->valid_iv_length(nonce.size())) + throw Test_Error("Invalid nonce for " + algo); cipher->set_iv(nonce.data(), nonce.size()); } else @@ -67,12 +69,20 @@ class Stream_Cipher_Tests : public Text_Based_Test * null/empty nonce. Call set_iv with such a nonce to make sure * set_iv accepts it. */ + if(!cipher->valid_iv_length(0)) + throw Test_Error("Stream cipher " + algo + " requires nonce but none provided"); cipher->set_iv(nullptr, 0); } if (seek != 0) cipher->seek(seek); + // Test that clone works and does not affect parent object + std::unique_ptr<Botan::StreamCipher> clone(cipher->clone()); + result.confirm("Clone has different pointer", cipher.get() != clone.get()); + result.test_eq("Clone has same name", cipher->name(), clone->name()); + clone->set_key(Test::rng().random_vec(cipher->maximum_keylength())); + std::vector<uint8_t> buf = input; cipher->encrypt(buf); diff --git a/src/tests/test_workfactor.cpp b/src/tests/test_workfactor.cpp new file mode 100644 index 000000000..b0a140692 --- /dev/null +++ b/src/tests/test_workfactor.cpp @@ -0,0 +1,47 @@ +/* +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "tests.h" + +#if defined(BOTAN_HAS_PUBLIC_KEY_CRYPTO) + #include <botan/workfactor.h> +#endif + +namespace Botan_Tests { + +#if defined(BOTAN_HAS_PUBLIC_KEY_CRYPTO) +class PK_Workfactor_Tests : public Text_Based_Test + { + public: + PK_Workfactor_Tests() : Text_Based_Test("pubkey/workfactor.vec", + {"ParamSize", "Workfactor"}) + {} + + Test::Result run_one_test(const std::string& type, const VarMap& vars) override + { + const size_t param_size = get_req_sz(vars, "ParamSize"); + const size_t exp_output = get_req_sz(vars, "Workfactor"); + + size_t output = 0; + + // TODO: test McEliece strength tests also + + if(type == "RSA_Strength") + output = Botan::if_work_factor(param_size); + else if(type == "DL_Exponent_Size") + output = Botan::dl_exponent_size(param_size) / 2; + + Test::Result result(type + " work factor calculation"); + result.test_eq("Calculated workfactor for " + std::to_string(param_size), + output, exp_output); + return result; + } + }; + +BOTAN_REGISTER_TEST("pk_workfactor", PK_Workfactor_Tests); +#endif + +} diff --git a/src/tests/test_x509_path.cpp b/src/tests/test_x509_path.cpp index ae52de541..facebf139 100644 --- a/src/tests/test_x509_path.cpp +++ b/src/tests/test_x509_path.cpp @@ -93,7 +93,7 @@ class X509test_Path_Validation_Tests : public Test if(path_result.successful_validation() && path_result.trust_root() != root) path_result = Botan::Path_Validation_Result(Botan::Certificate_Status_Code::CANNOT_ESTABLISH_TRUST); - result.test_eq("validation result", path_result.result_string(), expected_result); + result.test_eq("test " + filename, path_result.result_string(), expected_result); results.push_back(result); } diff --git a/src/tests/test_xmss.cpp b/src/tests/test_xmss.cpp index 2cf942655..eb75daa38 100644 --- a/src/tests/test_xmss.cpp +++ b/src/tests/test_xmss.cpp @@ -1,4 +1,4 @@ -/** +/* * Extended Hash-Based Signatures Tests * * (C) 2014,2015 Jack Lloyd @@ -60,16 +60,27 @@ class XMSS_Signature_Verify_Tests : public PK_Signature_Verification_Test std::unique_ptr<Botan::Public_Key> load_public_key(const VarMap& vars) override { - const std::vector<byte> raw_key = get_req_bin(vars, "PublicKey"); - const Botan::secure_vector<byte> sec_key(raw_key.begin(), raw_key.end()); + const std::vector<byte> raw_key = get_req_bin(vars, "PublicKey"); + const Botan::secure_vector<byte> sec_key(raw_key.begin(), raw_key.end()); - std::unique_ptr<Botan::Public_Key> key(new Botan::XMSS_PublicKey(sec_key)); + std::unique_ptr<Botan::Public_Key> key(new Botan::XMSS_PublicKey(sec_key)); return key; } }; +class XMSS_Keygen_Tests : public PK_Key_Generation_Test + { + public: + std::vector<std::string> keygen_params() const override + { + return { "XMSS_SHA2-256_W16_H10" }; + } + std::string algo_name() const override { return "XMSS"; } + }; + BOTAN_REGISTER_TEST("xmss_sign", XMSS_Signature_Tests); BOTAN_REGISTER_TEST("xmss_verify", XMSS_Signature_Verify_Tests); +BOTAN_REGISTER_TEST("xmss_keygen", XMSS_Keygen_Tests); #endif diff --git a/src/tests/tests.cpp b/src/tests/tests.cpp index 13094f5dc..b78b7a2e2 100644 --- a/src/tests/tests.cpp +++ b/src/tests/tests.cpp @@ -264,6 +264,16 @@ bool Test::Result::test_gte(const std::string& what, size_t produced, size_t exp return test_success(); } +bool Test::Result::test_ne(const std::string& what, const std::string& str1, const std::string& str2) + { + if(str1 != str2) + { + return test_success(str1 + " != " + str2); + } + + return test_failure(who() + " " + what + " produced matching strings " + str1); + } + bool Test::Result::test_ne(const std::string& what, size_t produced, size_t expected) { if(produced != expected) @@ -272,7 +282,7 @@ bool Test::Result::test_ne(const std::string& what, size_t produced, size_t expe } std::ostringstream err; - err << who() << " " << what << " produced " << produced << " prohibited value"; + err << who() << " " << what << " produced " << produced << " unexpected value"; return test_failure(err.str()); } @@ -467,11 +477,13 @@ Botan::RandomNumberGenerator* Test::m_test_rng = nullptr; std::string Test::m_data_dir; size_t Test::m_soak_level = 0; bool Test::m_log_success = false; +bool Test::m_run_online_tests = false; std::string Test::m_pkcs11_lib; //static void Test::setup_tests(size_t soak, bool log_success, + bool run_online, const std::string& data_dir, const std::string& pkcs11_lib, Botan::RandomNumberGenerator* rng) @@ -479,6 +491,7 @@ void Test::setup_tests(size_t soak, m_data_dir = data_dir; m_soak_level = soak; m_log_success = log_success; + m_run_online_tests = run_online; m_test_rng = rng; m_pkcs11_lib = pkcs11_lib; } @@ -508,6 +521,12 @@ bool Test::log_success() } //static +bool Test::run_online_tests() + { + return m_run_online_tests; + } + +//static std::string Test::pkcs11_lib() { return m_pkcs11_lib; @@ -583,6 +602,20 @@ std::string Text_Based_Test::get_opt_str(const VarMap& vars, return i->second; } +bool Text_Based_Test::get_req_bool(const VarMap& vars, const std::string& key) const + { + auto i = vars.find(key); + if(i == vars.end()) + throw Test_Error("Test missing variable " + key); + + if(i->second == "true") + return true; + else if(i->second == "false") + return false; + else + throw Test_Error("Invalid boolean for key '" + key + "' value '" + i->second + "'"); + } + size_t Text_Based_Test::get_req_sz(const VarMap& vars, const std::string& key) const { auto i = vars.find(key); diff --git a/src/tests/tests.h b/src/tests/tests.h index 236a89d6f..32aaad0fb 100644 --- a/src/tests/tests.h +++ b/src/tests/tests.h @@ -230,6 +230,8 @@ class Test bool test_ne(const std::string& what, size_t produced, size_t expected); + bool test_ne(const std::string& what, const std::string& str1, const std::string& str2); + #if defined(BOTAN_HAS_BIGINT) bool test_eq(const std::string& what, const BigInt& produced, const BigInt& expected); bool test_ne(const std::string& what, const BigInt& produced, const BigInt& expected); @@ -358,12 +360,14 @@ class Test static void setup_tests(size_t soak, bool log_succcss, + bool run_online_tests, const std::string& data_dir, const std::string& pkcs11_lib, Botan::RandomNumberGenerator* rng); static size_t soak_level(); static bool log_success(); + static bool run_online_tests(); static std::string pkcs11_lib(); static const std::string& data_dir(); @@ -376,7 +380,7 @@ class Test static std::string m_data_dir; static Botan::RandomNumberGenerator* m_test_rng; static size_t m_soak_level; - static bool m_log_success; + static bool m_log_success, m_run_online_tests; static std::string m_pkcs11_lib; }; @@ -426,6 +430,8 @@ class Text_Based_Test : public Test virtual std::vector<Test::Result> run_final_tests() { return std::vector<Test::Result>(); } + bool get_req_bool(const VarMap& vars, const std::string& key) const; + std::vector<uint8_t> get_req_bin(const VarMap& vars, const std::string& key) const; std::vector<uint8_t> get_opt_bin(const VarMap& vars, const std::string& key) const; diff --git a/src/tests/unit_tls.cpp b/src/tests/unit_tls.cpp index b69f97cca..9952ea77c 100644 --- a/src/tests/unit_tls.cpp +++ b/src/tests/unit_tls.cpp @@ -39,21 +39,25 @@ class Credentials_Manager_Test : public Botan::Credentials_Manager { public: Credentials_Manager_Test(const Botan::X509_Certificate& rsa_cert, + Botan::Private_Key* rsa_key, const Botan::X509_Certificate& rsa_ca, + const Botan::X509_CRL& rsa_crl, const Botan::X509_Certificate& ecdsa_cert, + Botan::Private_Key* ecdsa_key, const Botan::X509_Certificate& ecdsa_ca, - Botan::Private_Key* rsa_key, - Botan::Private_Key* ecdsa_key) : + const Botan::X509_CRL& ecdsa_crl) : m_rsa_cert(rsa_cert), m_rsa_ca(rsa_ca), + m_rsa_key(rsa_key), m_ecdsa_cert(ecdsa_cert), m_ecdsa_ca(ecdsa_ca), - m_rsa_key(rsa_key), m_ecdsa_key(ecdsa_key) { std::unique_ptr<Botan::Certificate_Store_In_Memory> store(new Botan::Certificate_Store_In_Memory); store->add_certificate(m_rsa_ca); store->add_certificate(m_ecdsa_ca); + store->add_crl(ecdsa_crl); + store->add_crl(rsa_crl); m_stores.push_back(std::move(store)); m_provides_client_certs = false; } @@ -97,16 +101,6 @@ class Credentials_Manager_Test : public Botan::Credentials_Manager return chain; } - void verify_certificate_chain( - const std::string& type, - const std::string& purported_hostname, - const std::vector<Botan::X509_Certificate>& cert_chain) override - { - Credentials_Manager::verify_certificate_chain(type, - purported_hostname, - cert_chain); - } - Botan::Private_Key* private_key_for(const Botan::X509_Certificate& crt, const std::string&, const std::string&) override @@ -135,8 +129,11 @@ class Credentials_Manager_Test : public Botan::Credentials_Manager } public: - Botan::X509_Certificate m_rsa_cert, m_rsa_ca, m_ecdsa_cert, m_ecdsa_ca; - std::unique_ptr<Botan::Private_Key> m_rsa_key, m_ecdsa_key; + Botan::X509_Certificate m_rsa_cert, m_rsa_ca; + std::unique_ptr<Botan::Private_Key> m_rsa_key; + + Botan::X509_Certificate m_ecdsa_cert, m_ecdsa_ca; + std::unique_ptr<Botan::Private_Key> m_ecdsa_key; std::vector<std::unique_ptr<Botan::Certificate_Store>> m_stores; bool m_provides_client_certs; }; @@ -154,13 +151,15 @@ create_creds(Botan::RandomNumberGenerator& rng, std::unique_ptr<Botan::Private_Key> ecdsa_ca_key(new Botan::ECDSA_PrivateKey(rng, ecdsa_params)); std::unique_ptr<Botan::Private_Key> ecdsa_srv_key(new Botan::ECDSA_PrivateKey(rng, ecdsa_params)); - Botan::X509_Cert_Options ca_opts("Test CA/VT"); - ca_opts.CA_key(1); + Botan::X509_Cert_Options rsa_ca_opts("RSA Test CA/VT"); + Botan::X509_Cert_Options ecdsa_ca_opts("ECDSA Test CA/VT"); + rsa_ca_opts.CA_key(1); + ecdsa_ca_opts.CA_key(1); const Botan::X509_Certificate rsa_ca_cert = - Botan::X509::create_self_signed_cert(ca_opts, *rsa_ca_key, "SHA-256", rng); + Botan::X509::create_self_signed_cert(rsa_ca_opts, *rsa_ca_key, "SHA-256", rng); const Botan::X509_Certificate ecdsa_ca_cert = - Botan::X509::create_self_signed_cert(ca_opts, *ecdsa_ca_key, "SHA-256", rng); + Botan::X509::create_self_signed_cert(ecdsa_ca_opts, *ecdsa_ca_key, "SHA-256", rng); const Botan::X509_Cert_Options server_opts("server.example.com"); @@ -183,10 +182,12 @@ create_creds(Botan::RandomNumberGenerator& rng, const Botan::X509_Certificate ecdsa_srv_cert = ecdsa_ca.sign_request(ecdsa_req, rng, start_time, end_time); + Botan::X509_CRL rsa_crl = rsa_ca.new_crl(rng); + Botan::X509_CRL ecdsa_crl = ecdsa_ca.new_crl(rng); + Credentials_Manager_Test* cmt = new Credentials_Manager_Test( - rsa_srv_cert, rsa_ca_cert, - ecdsa_srv_cert, ecdsa_ca_cert, - rsa_srv_key.release(), ecdsa_srv_key.release()); + rsa_srv_cert, rsa_srv_key.release(), rsa_ca_cert, rsa_crl, + ecdsa_srv_cert, ecdsa_srv_key.release(), ecdsa_ca_cert, ecdsa_crl); cmt->m_provides_client_certs = with_client_certs; return cmt; @@ -309,10 +310,10 @@ Test::Result test_tls_handshake(Botan::TLS::Protocol_Version offer_version, server_sent.clear(); // TLS::Server object constructed by legacy constructor. - server.reset( + server.reset( new Botan::TLS::Server(queue_inserter(s2c_traffic), queue_inserter(server_recv), - alert_cb_with_data, + alert_cb_with_data, handshake_complete, server_sessions, creds, @@ -322,7 +323,7 @@ Test::Result test_tls_handshake(Botan::TLS::Protocol_Version offer_version, false)); // TLS::Client object constructed by legacy constructor. - client.reset( + client.reset( new Botan::TLS::Client(queue_inserter(c2s_traffic), queue_inserter(client_recv), alert_cb_with_data, @@ -622,7 +623,7 @@ Test::Result test_dtls_handshake(Botan::TLS::Protocol_Version offer_version, server.reset( new Botan::TLS::Server(queue_inserter(s2c_traffic), queue_inserter(server_recv), - alert_cb_with_data, + alert_cb_with_data, handshake_complete, server_sessions, creds, @@ -635,7 +636,7 @@ Test::Result test_dtls_handshake(Botan::TLS::Protocol_Version offer_version, client.reset( new Botan::TLS::Client(queue_inserter(c2s_traffic), queue_inserter(client_recv), - alert_cb_with_data, + alert_cb_with_data, handshake_complete, client_sessions, creds, @@ -838,9 +839,110 @@ class Test_Policy : public Botan::TLS::Text_Policy size_t dtls_maximum_timeout() const override { return 8; } size_t minimum_rsa_bits() const override { return 1024; } + + size_t minimum_signature_strength() const override { return 80; } }; +Test::Result test_tls_alert_strings() + { + Test::Result result("TLS::Alert::type_string"); + + const std::vector<Botan::TLS::Alert::Type> alert_types = { + Botan::TLS::Alert::CLOSE_NOTIFY, + Botan::TLS::Alert::UNEXPECTED_MESSAGE, + Botan::TLS::Alert::BAD_RECORD_MAC, + Botan::TLS::Alert::DECRYPTION_FAILED, + Botan::TLS::Alert::RECORD_OVERFLOW, + Botan::TLS::Alert::DECOMPRESSION_FAILURE, + Botan::TLS::Alert::HANDSHAKE_FAILURE, + Botan::TLS::Alert::NO_CERTIFICATE, + Botan::TLS::Alert::BAD_CERTIFICATE, + Botan::TLS::Alert::UNSUPPORTED_CERTIFICATE, + Botan::TLS::Alert::CERTIFICATE_REVOKED, + Botan::TLS::Alert::CERTIFICATE_EXPIRED, + Botan::TLS::Alert::CERTIFICATE_UNKNOWN, + Botan::TLS::Alert::ILLEGAL_PARAMETER, + Botan::TLS::Alert::UNKNOWN_CA, + Botan::TLS::Alert::ACCESS_DENIED, + Botan::TLS::Alert::DECODE_ERROR, + Botan::TLS::Alert::DECRYPT_ERROR, + Botan::TLS::Alert::EXPORT_RESTRICTION, + Botan::TLS::Alert::PROTOCOL_VERSION, + Botan::TLS::Alert::INSUFFICIENT_SECURITY, + Botan::TLS::Alert::INTERNAL_ERROR, + Botan::TLS::Alert::INAPPROPRIATE_FALLBACK, + Botan::TLS::Alert::USER_CANCELED, + Botan::TLS::Alert::NO_RENEGOTIATION, + Botan::TLS::Alert::UNSUPPORTED_EXTENSION, + Botan::TLS::Alert::CERTIFICATE_UNOBTAINABLE, + Botan::TLS::Alert::UNRECOGNIZED_NAME, + Botan::TLS::Alert::BAD_CERTIFICATE_STATUS_RESPONSE, + Botan::TLS::Alert::BAD_CERTIFICATE_HASH_VALUE, + Botan::TLS::Alert::UNKNOWN_PSK_IDENTITY, + Botan::TLS::Alert:: NO_APPLICATION_PROTOCOL, + }; + + std::set<std::string> seen; + + for(auto alert : alert_types) + { + const std::string str = Botan::TLS::Alert(alert).type_string(); + result.test_eq("No duplicate strings", seen.count(str), 0); + seen.insert(str); + } + + Botan::TLS::Alert unknown_alert = Botan::TLS::Alert(Botan::secure_vector<uint8_t>{01, 66}); + + result.test_eq("Unknown alert str", unknown_alert.type_string(), "unrecognized_alert_66"); + + return result; + } + + +std::string read_tls_policy(const std::string& policy_str) + { + const std::string fspath = Test::data_file("tls-policy/" + policy_str + ".txt"); + + std::ifstream is(fspath.c_str()); + if(!is.good()) + throw Test_Error("Missing policy file " + fspath); + + Botan::TLS::Text_Policy policy(is); + return policy.to_string(); + } + +std::string tls_policy_string(const std::string& policy_str) + { + std::unique_ptr<Botan::TLS::Policy> policy; + if(policy_str == "default") + policy.reset(new Botan::TLS::Policy); + else if(policy_str == "suiteb") + policy.reset(new Botan::TLS::NSA_Suite_B_128); + else if(policy_str == "strict") + policy.reset(new Botan::TLS::Strict_Policy); + else if(policy_str == "datagram") + policy.reset(new Botan::TLS::Datagram_Policy); + else + throw Test_Error("Unknown TLS policy type '" + policy_str + "'"); + + return policy->to_string(); + } + +Test::Result test_tls_policy() + { + Test::Result result("TLS Policy"); + const std::vector<std::string> policies = { "default", "suiteb", "strict", "datagram" }; + + for(std::string policy : policies) + { + result.test_eq("Values for TLS " + policy + " policy", + tls_policy_string(policy), + read_tls_policy(policy)); + } + + return result; + } class TLS_Unit_Tests : public Test { @@ -878,6 +980,9 @@ class TLS_Unit_Tests : public Test policy.set("key_exchange_methods", kex_policy); policy.set("negotiate_encrypt_then_mac", etm_policy); + if(kex_policy == "RSA") + policy.set("signature_methods", "RSA"); + std::vector<Botan::TLS::Protocol_Version> versions = { Botan::TLS::Protocol_Version::TLS_V10, Botan::TLS::Protocol_Version::TLS_V11, @@ -914,9 +1019,38 @@ class TLS_Unit_Tests : public Test return test_with_policy(results, client_ses, server_ses, creds, versions, policy); } + Test::Result test_tls_ciphersuites() + { + Test::Result result("TLS::Ciphersuite"); + + for(size_t csuite_id = 0; csuite_id <= 0xFFFF; ++csuite_id) + { + Botan::TLS::Ciphersuite ciphersuite = Botan::TLS::Ciphersuite::by_id(csuite_id); + + if(ciphersuite.valid()) + { + result.test_eq("Valid Ciphersuite is not SCSV", Botan::TLS::Ciphersuite::is_scsv(csuite_id), false); + + if(ciphersuite.cbc_ciphersuite() == false) + result.test_eq("Expected MAC name for AEAD ciphersuites", ciphersuite.mac_algo(), "AEAD"); + else + result.test_eq("MAC algo and PRF algo same for CBC suites", ciphersuite.prf_algo(), ciphersuite.mac_algo()); + + // TODO more tests here + } + } + + return result; + } + public: std::vector<Test::Result> run() override { + std::vector<Test::Result> results; + results.push_back(test_tls_alert_strings()); + results.push_back(test_tls_policy()); + results.push_back(test_tls_ciphersuites()); + Botan::RandomNumberGenerator& rng = Test::rng(); std::unique_ptr<Botan::TLS::Session_Manager> client_ses; @@ -935,7 +1069,6 @@ class TLS_Unit_Tests : public Test #endif std::unique_ptr<Botan::Credentials_Manager> creds(create_creds(rng)); - std::vector<Test::Result> results; #if defined(BOTAN_HAS_TLS_CBC) for(std::string etm_setting : { "false", "true" }) @@ -962,6 +1095,7 @@ class TLS_Unit_Tests : public Test server_ses->remove_all(); } + client_ses->remove_all(); test_modern_versions(results, *client_ses, *server_ses, *creds, "DH", "AES-128", "SHA-256"); #endif @@ -970,16 +1104,25 @@ class TLS_Unit_Tests : public Test test_with_policy(results, *client_ses, *server_ses, *creds, {Botan::TLS::Protocol_Version::TLS_V12}, strict_policy); + Botan::TLS::NSA_Suite_B_128 suiteb_128; + test_with_policy(results, *client_ses, *server_ses, *creds, + {Botan::TLS::Protocol_Version::TLS_V12}, suiteb_128); + + // Remove server sessions before client, so clients retry with session server doesn't know + server_ses->remove_all(); + test_modern_versions(results, *client_ses, *server_ses, *creds, "RSA", "AES-128/GCM"); test_modern_versions(results, *client_ses, *server_ses, *creds, "ECDH", "AES-128/GCM"); - client_ses->remove_all(); - test_modern_versions(results, *client_ses, *server_ses, *creds, "ECDH", "AES-128/GCM", "AEAD", { { "signature_methods", "RSA" } }); + client_ses->remove_all(); + #if defined(BOTAN_HAS_CECPQ1) test_modern_versions(results, *client_ses, *server_ses, *creds, "CECPQ1", "AES-256/GCM", "AEAD"); + test_modern_versions(results, *client_ses, *server_ses, *creds, "CECPQ1", "ChaCha20Poly1305", "AEAD", + { { "signature_methods", "RSA" }}); #endif test_modern_versions(results, *client_ses, *server_ses, *creds, "ECDH", "AES-128/GCM", "AEAD", @@ -1006,6 +1149,8 @@ class TLS_Unit_Tests : public Test test_modern_versions(results, *client_ses, *server_ses, *creds, "ECDH", "AES-128/OCB(12)"); #endif + server_ses->remove_all(); + #if defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305) test_modern_versions(results, *client_ses, *server_ses, *creds, "ECDH", "ChaCha20Poly1305"); #endif @@ -1027,6 +1172,7 @@ class TLS_Unit_Tests : public Test test_modern_versions(results, *client_ses, *server_ses, *creds, "ECDH", "AES-128/GCM", "AEAD", { { "ecc_curves", BOTAN_HOUSE_ECC_CURVE_NAME } }); #endif + return results; } diff --git a/src/tests/unit_x509.cpp b/src/tests/unit_x509.cpp index ae860067c..56a6e8b82 100644 --- a/src/tests/unit_x509.cpp +++ b/src/tests/unit_x509.cpp @@ -17,6 +17,9 @@ #include <botan/x509path.h> #include <botan/x509_ca.h> #include <botan/pk_algs.h> +#include <botan/ber_dec.h> +#include <botan/der_enc.h> +#include <botan/oids.h> #endif @@ -98,6 +101,69 @@ std::unique_ptr<Botan::Private_Key> make_a_private_key(const std::string& algo) } +Test::Result test_cert_status_strings() + { + Test::Result result("Certificate_Status_Code to_string"); + + std::set<std::string> seen; + + result.test_eq("Same string", + Botan::to_string(Botan::Certificate_Status_Code::OK), + Botan::to_string(Botan::Certificate_Status_Code::VERIFIED)); + + const std::vector<Botan::Certificate_Status_Code> codes = { + Botan::Certificate_Status_Code::OCSP_RESPONSE_GOOD, + Botan::Certificate_Status_Code::OCSP_SIGNATURE_OK, + Botan::Certificate_Status_Code::VALID_CRL_CHECKED, + Botan::Certificate_Status_Code::OCSP_NO_HTTP, + + Botan::Certificate_Status_Code::SIGNATURE_METHOD_TOO_WEAK, + Botan::Certificate_Status_Code::UNTRUSTED_HASH, + Botan::Certificate_Status_Code::NO_REVOCATION_DATA, + Botan::Certificate_Status_Code::CERT_NOT_YET_VALID, + Botan::Certificate_Status_Code::CERT_HAS_EXPIRED, + Botan::Certificate_Status_Code::OCSP_NOT_YET_VALID, + Botan::Certificate_Status_Code::OCSP_HAS_EXPIRED, + Botan::Certificate_Status_Code::CRL_NOT_YET_VALID, + Botan::Certificate_Status_Code::CRL_HAS_EXPIRED, + Botan::Certificate_Status_Code::CERT_ISSUER_NOT_FOUND, + Botan::Certificate_Status_Code::CANNOT_ESTABLISH_TRUST, + Botan::Certificate_Status_Code::CERT_CHAIN_LOOP, + Botan::Certificate_Status_Code::CHAIN_LACKS_TRUST_ROOT, + Botan::Certificate_Status_Code::CHAIN_NAME_MISMATCH, + Botan::Certificate_Status_Code::POLICY_ERROR, + Botan::Certificate_Status_Code::INVALID_USAGE, + Botan::Certificate_Status_Code::CERT_CHAIN_TOO_LONG, + Botan::Certificate_Status_Code::CA_CERT_NOT_FOR_CERT_ISSUER, + Botan::Certificate_Status_Code::NAME_CONSTRAINT_ERROR, + Botan::Certificate_Status_Code::CA_CERT_NOT_FOR_CRL_ISSUER, + Botan::Certificate_Status_Code::OCSP_CERT_NOT_LISTED, + Botan::Certificate_Status_Code::OCSP_BAD_STATUS, + Botan::Certificate_Status_Code::CERT_NAME_NOMATCH, + Botan::Certificate_Status_Code::UNKNOWN_CRITICAL_EXTENSION, + Botan::Certificate_Status_Code::OCSP_SIGNATURE_ERROR, + Botan::Certificate_Status_Code::OCSP_ISSUER_NOT_FOUND, + Botan::Certificate_Status_Code::OCSP_RESPONSE_MISSING_KEYUSAGE, + Botan::Certificate_Status_Code::OCSP_RESPONSE_INVALID, + Botan::Certificate_Status_Code::CERT_IS_REVOKED, + Botan::Certificate_Status_Code::CRL_BAD_SIGNATURE, + Botan::Certificate_Status_Code::SIGNATURE_ERROR, + Botan::Certificate_Status_Code::CERT_PUBKEY_INVALID, + }; + + for(auto code : codes) + { + std::string s = Botan::to_string(code); + result.confirm("String is long enough to be informative", s.size() > 12); + result.test_eq("No duplicates", seen.count(s), 0); + seen.insert(s); + } + + return result; + + } + + Test::Result test_x509_dates() { Test::Result result("X509_Time"); @@ -647,6 +713,126 @@ Test::Result test_valid_constraints(const std::string& pk_algo) return result; } +/** + * @brief X.509v3 extension that encodes a given string + */ +class String_Extension : public Botan::Certificate_Extension + { + public: + String_Extension() : m_contents() {} + String_Extension(const std::string& val) : m_contents(val) {} + + std::string value() const { return m_contents; } + + String_Extension* copy() const override { return new String_Extension(m_contents); } + + Botan::OID oid_of() const override { return m_oid; } + std::string oid_name() const override { return "String Extension"; } + + void contents_to(Botan::Data_Store&, Botan::Data_Store&) const override {} + + std::vector<byte> encode_inner() const override + { + return Botan::DER_Encoder().encode(Botan::ASN1_String(m_contents, Botan::UTF8_STRING)).get_contents_unlocked(); + } + + void decode_inner(const std::vector<byte>& in) override + { + Botan::ASN1_String str; + Botan::BER_Decoder(in).decode(str, Botan::UTF8_STRING).verify_end(); + m_contents = str.value(); + } + + private: + Botan::OID m_oid {"1.2.3.4.5.6.7.8.9.1"}; + std::string m_contents; + }; + +Test::Result test_x509_extensions(const std::string& sig_algo, const std::string& hash_fn = "SHA-256") + { + using Botan::Key_Constraints; + + Test::Result result("X509 Extensions"); + + /* Create the CA's key and self-signed cert */ + std::unique_ptr<Botan::Private_Key> ca_key(make_a_private_key(sig_algo)); + + if(!ca_key) + { + // Failure because X.509 enabled but requested signature algorithm is not present + result.test_note("Skipping due to missing signature algorithm: " + sig_algo); + return result; + } + + /* Create the self-signed cert */ + Botan::X509_Certificate ca_cert = + Botan::X509::create_self_signed_cert(ca_opts(), + *ca_key, + hash_fn, + Test::rng()); + + /* Create the CA object */ + Botan::X509_CA ca(ca_cert, *ca_key, hash_fn); + + std::unique_ptr<Botan::Private_Key> user_key(make_a_private_key(sig_algo)); + + Botan::X509_Cert_Options opts("Test User 1/US/Botan Project/Testing"); + opts.constraints = Key_Constraints::DIGITAL_SIGNATURE; + + // include a custom extension in the request + Botan::Extensions req_extensions; + Botan::OID oid("1.2.3.4.5.6.7.8.9.1"); + req_extensions.add(new String_Extension("1Test"), false); + opts.extensions = req_extensions; + + /* Create a self-signed certificate */ + Botan::X509_Certificate self_signed_cert = Botan::X509::create_self_signed_cert(opts, *user_key, hash_fn, Test::rng()); + + // check if known Key_Usage extension is present in self-signed cert + auto key_usage_ext = self_signed_cert.v3_extensions().get(Botan::OIDS::lookup("X509v3.KeyUsage")); + if(result.confirm("Key_Usage extension present in self-signed certificate", key_usage_ext != nullptr)) + { + result.confirm("Key_Usage extension value matches in self-signed certificate", + dynamic_cast<Botan::Cert_Extension::Key_Usage&>(*key_usage_ext).get_constraints() == opts.constraints); + } + + // check if custom extension is present in self-signed cert + auto string_ext = self_signed_cert.v3_extensions().get_raw<String_Extension>(oid); + if(result.confirm("Custom extension present in self-signed certificate", string_ext != nullptr)) + { + result.test_eq("Custom extension value matches in self-signed certificate", string_ext->value(), "1Test"); + } + + + Botan::PKCS10_Request user_req = + Botan::X509::create_cert_req(opts, + *user_key, + hash_fn, + Test::rng()); + + /* Create a CA-signed certificate */ + Botan::X509_Certificate user_cert = + ca.sign_request(user_req, Test::rng(), + from_date(2008, 01, 01), + from_date(2033, 01, 01)); + + // check if known Key_Usage extension is present in CA-signed cert + key_usage_ext = self_signed_cert.v3_extensions().get(Botan::OIDS::lookup("X509v3.KeyUsage")); + if(result.confirm("Key_Usage extension present in user certificate", key_usage_ext != nullptr)) + { + result.confirm("Key_Usage extension value matches in user certificate", + dynamic_cast<Botan::Cert_Extension::Key_Usage&>(*key_usage_ext).get_constraints() == Botan::DIGITAL_SIGNATURE); + } + + // check if custom extension is present in CA-signed cert + string_ext = user_cert.v3_extensions().get_raw<String_Extension>(oid); + if(result.confirm("Custom extension present in user certificate", string_ext != nullptr)) + { + result.test_eq("Custom extension value matches in user certificate", string_ext->value(), "1Test"); + } + + return result; + } class X509_Cert_Unit_Tests : public Test { @@ -659,6 +845,7 @@ class X509_Cert_Unit_Tests : public Test Test::Result cert_result("X509 Unit"); Test::Result usage_result("X509 Usage"); Test::Result self_issued_result("X509 Self Issued"); + Test::Result extensions_result("X509 Extensions"); for(const auto& algo : sig_algos) { @@ -685,11 +872,20 @@ class X509_Cert_Unit_Tests : public Test { self_issued_result.test_failure("test_self_issued " + algo, e.what()); } + + try { + extensions_result.merge(test_x509_extensions(algo)); + } + catch(std::exception& e) + { + extensions_result.test_failure("test_extensions " + algo, e.what()); + } } results.push_back(cert_result); results.push_back(usage_result); results.push_back(self_issued_result); + results.push_back(extensions_result); const std::vector<std::string> pk_algos { "DH", "ECDH", "RSA", "ElGamal", "GOST-34.10", "DSA", "ECDSA", "ECGDSA", "ECKCDSA" }; @@ -702,6 +898,7 @@ class X509_Cert_Unit_Tests : public Test results.push_back(valid_constraints_result); results.push_back(test_x509_dates()); + results.push_back(test_cert_status_strings()); return results; } |