diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /comm/third_party/botan/src/lib/mac | |
parent | Initial commit. (diff) | |
download | thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'comm/third_party/botan/src/lib/mac')
24 files changed, 1717 insertions, 0 deletions
diff --git a/comm/third_party/botan/src/lib/mac/cbc_mac/cbc_mac.cpp b/comm/third_party/botan/src/lib/mac/cbc_mac/cbc_mac.cpp new file mode 100644 index 0000000000..ba403b564a --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/cbc_mac/cbc_mac.cpp @@ -0,0 +1,99 @@ +/* +* CBC-MAC +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/cbc_mac.h> + +namespace Botan { + +/* +* Update an CBC-MAC Calculation +*/ +void CBC_MAC::add_data(const uint8_t input[], size_t length) + { + verify_key_set(m_state.empty() == false); + + size_t xored = std::min(output_length() - m_position, length); + xor_buf(&m_state[m_position], input, xored); + m_position += xored; + + if(m_position < output_length()) + return; + + m_cipher->encrypt(m_state); + input += xored; + length -= xored; + while(length >= output_length()) + { + xor_buf(m_state, input, output_length()); + m_cipher->encrypt(m_state); + input += output_length(); + length -= output_length(); + } + + xor_buf(m_state, input, length); + m_position = length; + } + +/* +* Finalize an CBC-MAC Calculation +*/ +void CBC_MAC::final_result(uint8_t mac[]) + { + verify_key_set(m_state.empty() == false); + + if(m_position) + m_cipher->encrypt(m_state); + + copy_mem(mac, m_state.data(), m_state.size()); + zeroise(m_state); + m_position = 0; + } + +/* +* CBC-MAC Key Schedule +*/ +void CBC_MAC::key_schedule(const uint8_t key[], size_t length) + { + m_state.resize(m_cipher->block_size()); + m_cipher->set_key(key, length); + } + +/* +* Clear memory of sensitive data +*/ +void CBC_MAC::clear() + { + m_cipher->clear(); + zap(m_state); + m_position = 0; + } + +/* +* Return the name of this type +*/ +std::string CBC_MAC::name() const + { + return "CBC-MAC(" + m_cipher->name() + ")"; + } + +/* +* Return a clone of this object +*/ +MessageAuthenticationCode* CBC_MAC::clone() const + { + return new CBC_MAC(m_cipher->clone()); + } + +/* +* CBC-MAC Constructor +*/ +CBC_MAC::CBC_MAC(BlockCipher* cipher) : + m_cipher(cipher) + { + } + +} diff --git a/comm/third_party/botan/src/lib/mac/cbc_mac/cbc_mac.h b/comm/third_party/botan/src/lib/mac/cbc_mac/cbc_mac.h new file mode 100644 index 0000000000..ed4eb2bd18 --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/cbc_mac/cbc_mac.h @@ -0,0 +1,50 @@ +/* +* CBC-MAC +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CBC_MAC_H_ +#define BOTAN_CBC_MAC_H_ + +#include <botan/mac.h> +#include <botan/block_cipher.h> + +BOTAN_FUTURE_INTERNAL_HEADER(cbc_mac.h) + +namespace Botan { + +/** +* CBC-MAC +*/ +class BOTAN_PUBLIC_API(2,0) CBC_MAC final : public MessageAuthenticationCode + { + public: + std::string name() const override; + MessageAuthenticationCode* clone() const override; + size_t output_length() const override { return m_cipher->block_size(); } + void clear() override; + + Key_Length_Specification key_spec() const override + { + return m_cipher->key_spec(); + } + + /** + * @param cipher the block cipher to use + */ + explicit CBC_MAC(BlockCipher* cipher); + private: + void add_data(const uint8_t[], size_t) override; + void final_result(uint8_t[]) override; + void key_schedule(const uint8_t[], size_t) override; + + std::unique_ptr<BlockCipher> m_cipher; + secure_vector<uint8_t> m_state; + size_t m_position = 0; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/mac/cbc_mac/info.txt b/comm/third_party/botan/src/lib/mac/cbc_mac/info.txt new file mode 100644 index 0000000000..994a63872b --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/cbc_mac/info.txt @@ -0,0 +1,7 @@ +<defines> +CBC_MAC -> 20131128 +</defines> + +<requires> +block +</requires> diff --git a/comm/third_party/botan/src/lib/mac/cmac/cmac.cpp b/comm/third_party/botan/src/lib/mac/cmac/cmac.cpp new file mode 100644 index 0000000000..38752471dd --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/cmac/cmac.cpp @@ -0,0 +1,139 @@ +/* +* CMAC +* (C) 1999-2007,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/cmac.h> +#include <botan/exceptn.h> +#include <botan/internal/poly_dbl.h> + +namespace Botan { + +/* +* Perform CMAC's multiplication in GF(2^n) +*/ +secure_vector<uint8_t> CMAC::poly_double(const secure_vector<uint8_t>& in) + { + secure_vector<uint8_t> out(in.size()); + poly_double_n(out.data(), in.data(), out.size()); + return out; + } + +/* +* Update an CMAC Calculation +*/ +void CMAC::add_data(const uint8_t input[], size_t length) + { + const size_t bs = output_length(); + + buffer_insert(m_buffer, m_position, input, length); + if(m_position + length > bs) + { + xor_buf(m_state, m_buffer, bs); + m_cipher->encrypt(m_state); + input += (bs - m_position); + length -= (bs - m_position); + while(length > bs) + { + xor_buf(m_state, input, bs); + m_cipher->encrypt(m_state); + input += bs; + length -= bs; + } + copy_mem(m_buffer.data(), input, length); + m_position = 0; + } + m_position += length; + } + +/* +* Finalize an CMAC Calculation +*/ +void CMAC::final_result(uint8_t mac[]) + { + xor_buf(m_state, m_buffer, m_position); + + if(m_position == output_length()) + { + xor_buf(m_state, m_B, output_length()); + } + else + { + m_state[m_position] ^= 0x80; + xor_buf(m_state, m_P, output_length()); + } + + m_cipher->encrypt(m_state); + + copy_mem(mac, m_state.data(), output_length()); + + zeroise(m_state); + zeroise(m_buffer); + m_position = 0; + } + +/* +* CMAC Key Schedule +*/ +void CMAC::key_schedule(const uint8_t key[], size_t length) + { + clear(); + m_cipher->set_key(key, length); + m_cipher->encrypt(m_B); + poly_double_n(m_B.data(), m_B.size()); + poly_double_n(m_P.data(), m_B.data(), m_P.size()); + } + +/* +* Clear memory of sensitive data +*/ +void CMAC::clear() + { + m_cipher->clear(); + zeroise(m_state); + zeroise(m_buffer); + zeroise(m_B); + zeroise(m_P); + m_position = 0; + } + +/* +* Return the name of this type +*/ +std::string CMAC::name() const + { + return "CMAC(" + m_cipher->name() + ")"; + } + +/* +* Return a clone of this object +*/ +MessageAuthenticationCode* CMAC::clone() const + { + return new CMAC(m_cipher->clone()); + } + +/* +* CMAC Constructor +*/ +CMAC::CMAC(BlockCipher* cipher) : + m_cipher(cipher), + m_block_size(m_cipher->block_size()) + { + if(poly_double_supported_size(m_block_size) == false) + { + throw Invalid_Argument("CMAC cannot use the " + + std::to_string(m_block_size * 8) + + " bit cipher " + m_cipher->name()); + } + + m_state.resize(output_length()); + m_buffer.resize(output_length()); + m_B.resize(output_length()); + m_P.resize(output_length()); + m_position = 0; + } + +} diff --git a/comm/third_party/botan/src/lib/mac/cmac/cmac.h b/comm/third_party/botan/src/lib/mac/cmac/cmac.h new file mode 100644 index 0000000000..f73167590d --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/cmac/cmac.h @@ -0,0 +1,67 @@ +/* +* CMAC +* (C) 1999-2007,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CMAC_H_ +#define BOTAN_CMAC_H_ + +#include <botan/mac.h> +#include <botan/block_cipher.h> + +BOTAN_FUTURE_INTERNAL_HEADER(cmac.h) + +namespace Botan { + +/** +* CMAC, also known as OMAC1 +*/ +class BOTAN_PUBLIC_API(2,0) CMAC final : public MessageAuthenticationCode + { + public: + std::string name() const override; + size_t output_length() const override { return m_block_size; } + MessageAuthenticationCode* clone() const override; + + void clear() override; + + Key_Length_Specification key_spec() const override + { + return m_cipher->key_spec(); + } + + /** + * CMAC's polynomial doubling operation + * + * This function was only exposed for use elsewhere in the library, but it is not + * longer used. This function will be removed in a future release. + * + * @param in the input + */ + static secure_vector<uint8_t> + BOTAN_DEPRECATED("This was only for internal use and is no longer used") + poly_double(const secure_vector<uint8_t>& in); + + /** + * @param cipher the block cipher to use + */ + explicit CMAC(BlockCipher* cipher); + + CMAC(const CMAC&) = delete; + CMAC& operator=(const CMAC&) = delete; + private: + void add_data(const uint8_t[], size_t) override; + void final_result(uint8_t[]) override; + void key_schedule(const uint8_t[], size_t) override; + + std::unique_ptr<BlockCipher> m_cipher; + secure_vector<uint8_t> m_buffer, m_state, m_B, m_P; + const size_t m_block_size; + size_t m_position; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/mac/cmac/info.txt b/comm/third_party/botan/src/lib/mac/cmac/info.txt new file mode 100644 index 0000000000..d78b3851ee --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/cmac/info.txt @@ -0,0 +1,8 @@ +<defines> +CMAC -> 20131128 +</defines> + +<requires> +block +poly_dbl +</requires> diff --git a/comm/third_party/botan/src/lib/mac/gmac/gmac.cpp b/comm/third_party/botan/src/lib/mac/gmac/gmac.cpp new file mode 100644 index 0000000000..6b162857f3 --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/gmac/gmac.cpp @@ -0,0 +1,134 @@ +/* + * GMAC + * (C) 2016 Matthias Gierlings, René Korthaus + * (C) 2017 Jack Lloyd + * + * Botan is released under the Simplified BSD License (see license.txt) + */ + +#include <botan/gmac.h> +#include <botan/ghash.h> +#include <botan/exceptn.h> +#include <botan/block_cipher.h> + +namespace Botan { + +GMAC::GMAC(BlockCipher* cipher) : + m_cipher(cipher), + m_ghash(new GHASH), + m_aad_buf(GCM_BS), + m_aad_buf_pos(0), + m_initialized(false) + { + } + +void GMAC::clear() + { + m_cipher->clear(); + m_ghash->clear(); + zeroise(m_aad_buf); + m_aad_buf_pos = 0; + m_initialized = false; + } + +GMAC::~GMAC() { /* for unique_ptr */ } + +Key_Length_Specification GMAC::key_spec() const + { + return m_cipher->key_spec(); + } + +std::string GMAC::name() const + { + return "GMAC(" + m_cipher->name() + ")"; + } + +size_t GMAC::output_length() const + { + return GCM_BS; + } + +void GMAC::add_data(const uint8_t input[], size_t size) + { + if(m_aad_buf_pos > 0) + { + const size_t taking = std::min(GCM_BS - m_aad_buf_pos, size); + copy_mem(&m_aad_buf[m_aad_buf_pos], input, taking); + m_aad_buf_pos += taking; + input += taking; + size -= taking; + + if(m_aad_buf_pos == GCM_BS) + { + m_ghash->update_associated_data(m_aad_buf.data(), GCM_BS); + m_aad_buf_pos = 0; + } + } + + const size_t left_over = size % GCM_BS; + const size_t full_blocks = size - left_over; + m_ghash->update_associated_data(input, full_blocks); + input += full_blocks; + + if(left_over > 0) + { + copy_mem(&m_aad_buf[m_aad_buf_pos], input, left_over); + m_aad_buf_pos += left_over; + } + } + +void GMAC::key_schedule(const uint8_t key[], size_t size) + { + clear(); + m_cipher->set_key(key, size); + + secure_vector<uint8_t> H(GCM_BS); + m_cipher->encrypt(H); + m_ghash->set_key(H); + } + +void GMAC::start_msg(const uint8_t nonce[], size_t nonce_len) + { + secure_vector<uint8_t> y0(GCM_BS); + + if(nonce_len == 12) + { + copy_mem(y0.data(), nonce, nonce_len); + y0[GCM_BS - 1] = 1; + } + else + { + m_ghash->ghash_update(y0, nonce, nonce_len); + m_ghash->add_final_block(y0, 0, nonce_len); + } + + secure_vector<uint8_t> m_enc_y0(GCM_BS); + m_cipher->encrypt(y0.data(), m_enc_y0.data()); + m_ghash->start(m_enc_y0.data(), m_enc_y0.size()); + m_initialized = true; + } + +void GMAC::final_result(uint8_t mac[]) + { + // This ensures the GMAC computation has been initialized with a fresh + // nonce. The aim of this check is to prevent developers from re-using + // nonces (and potential nonce-reuse attacks). + if(m_initialized == false) + throw Invalid_State("GMAC was not used with a fresh nonce"); + + // process the rest of the aad buffer. Even if it is a partial block only + // ghash_update will process it properly. + if(m_aad_buf_pos > 0) + { + m_ghash->update_associated_data(m_aad_buf.data(), m_aad_buf_pos); + } + + m_ghash->final(mac, output_length()); + clear(); + } + +MessageAuthenticationCode* GMAC::clone() const + { + return new GMAC(m_cipher->clone()); + } +} diff --git a/comm/third_party/botan/src/lib/mac/gmac/gmac.h b/comm/third_party/botan/src/lib/mac/gmac/gmac.h new file mode 100644 index 0000000000..b78aeec6f1 --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/gmac/gmac.h @@ -0,0 +1,64 @@ +/* + * GMAC + * (C) 2016 Matthias Gierlings, René Korthaus + * (C) 2017 Jack Lloyd + * + * Botan is released under the Simplified BSD License (see license.txt) + */ + +#ifndef BOTAN_GMAC_H_ +#define BOTAN_GMAC_H_ + +#include <botan/mac.h> + +BOTAN_FUTURE_INTERNAL_HEADER(gmac.h) + +namespace Botan { + +class BlockCipher; +class GHASH; + +/** +* GMAC +* +* GMAC requires a unique initialization vector be used for each message. +* This must be provided via the MessageAuthenticationCode::start() API +*/ +class BOTAN_PUBLIC_API(2,0) GMAC final : public MessageAuthenticationCode + { + public: + void clear() override; + std::string name() const override; + size_t output_length() const override; + MessageAuthenticationCode* clone() const override; + + Key_Length_Specification key_spec() const override; + + /** + * Creates a new GMAC instance. + * + * @param cipher the underlying block cipher to use + */ + explicit GMAC(BlockCipher* cipher); + + GMAC(const GMAC&) = delete; + GMAC& operator=(const GMAC&) = delete; + + ~GMAC(); + + private: + void add_data(const uint8_t[], size_t) override; + void final_result(uint8_t[]) override; + void start_msg(const uint8_t nonce[], size_t nonce_len) override; + void key_schedule(const uint8_t key[], size_t size) override; + + static const size_t GCM_BS = 16; + std::unique_ptr<BlockCipher> m_cipher; + std::unique_ptr<GHASH> m_ghash; + secure_vector<uint8_t> m_aad_buf; + size_t m_aad_buf_pos; + bool m_initialized; + }; + +} +#endif diff --git a/comm/third_party/botan/src/lib/mac/gmac/info.txt b/comm/third_party/botan/src/lib/mac/gmac/info.txt new file mode 100644 index 0000000000..cc473feb90 --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/gmac/info.txt @@ -0,0 +1,8 @@ +<defines> +GMAC -> 20160207 +</defines> + +<requires> +ghash +block +</requires> diff --git a/comm/third_party/botan/src/lib/mac/hmac/hmac.cpp b/comm/third_party/botan/src/lib/mac/hmac/hmac.cpp new file mode 100644 index 0000000000..eada1e1bcf --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/hmac/hmac.cpp @@ -0,0 +1,150 @@ +/* +* HMAC +* (C) 1999-2007,2014,2020 Jack Lloyd +* 2007 Yves Jerschow +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/hmac.h> +#include <botan/internal/ct_utils.h> + +namespace Botan { + +/* +* Update a HMAC Calculation +*/ +void HMAC::add_data(const uint8_t input[], size_t length) + { + verify_key_set(m_ikey.empty() == false); + m_hash->update(input, length); + } + +/* +* Finalize a HMAC Calculation +*/ +void HMAC::final_result(uint8_t mac[]) + { + verify_key_set(m_okey.empty() == false); + m_hash->final(mac); + m_hash->update(m_okey); + m_hash->update(mac, m_hash_output_length); + m_hash->final(mac); + m_hash->update(m_ikey); + } + +Key_Length_Specification HMAC::key_spec() const + { + // Support very long lengths for things like PBKDF2 and the TLS PRF + return Key_Length_Specification(0, 4096); + } + +size_t HMAC::output_length() const + { + return m_hash_output_length; + } + +/* +* HMAC Key Schedule +*/ +void HMAC::key_schedule(const uint8_t key[], size_t length) + { + const uint8_t ipad = 0x36; + const uint8_t opad = 0x5C; + + m_hash->clear(); + + m_ikey.resize(m_hash_block_size); + m_okey.resize(m_hash_block_size); + + clear_mem(m_ikey.data(), m_ikey.size()); + clear_mem(m_okey.data(), m_okey.size()); + + /* + * Sometimes the HMAC key length itself is sensitive, as with PBKDF2 where it + * reveals the length of the passphrase. Make some attempt to hide this to + * side channels. Clearly if the secret is longer than the block size then the + * branch to hash first reveals that. In addition, counting the number of + * compression functions executed reveals the size at the granularity of the + * hash function's block size. + * + * The greater concern is for smaller keys; being able to detect when a + * passphrase is say 4 bytes may assist choosing weaker targets. Even though + * the loop bounds are constant, we can only actually read key[0..length] so + * it doesn't seem possible to make this computation truly constant time. + * + * We don't mind leaking if the length is exactly zero since that's + * trivial to simply check. + */ + + if(length > m_hash_block_size) + { + m_hash->update(key, length); + m_hash->final(m_ikey.data()); + } + else if(length > 0) + { + for(size_t i = 0, i_mod_length = 0; i != m_hash_block_size; ++i) + { + /* + access key[i % length] but avoiding division due to variable + time computation on some processors. + */ + auto needs_reduction = CT::Mask<size_t>::is_lte(length, i_mod_length); + i_mod_length = needs_reduction.select(0, i_mod_length); + const uint8_t kb = key[i_mod_length]; + + auto in_range = CT::Mask<size_t>::is_lt(i, length); + m_ikey[i] = static_cast<uint8_t>(in_range.if_set_return(kb)); + i_mod_length += 1; + } + } + + for(size_t i = 0; i != m_hash_block_size; ++i) + { + m_ikey[i] ^= ipad; + m_okey[i] = m_ikey[i] ^ ipad ^ opad; + } + + m_hash->update(m_ikey); + } + +/* +* Clear memory of sensitive data +*/ +void HMAC::clear() + { + m_hash->clear(); + zap(m_ikey); + zap(m_okey); + } + +/* +* Return the name of this type +*/ +std::string HMAC::name() const + { + return "HMAC(" + m_hash->name() + ")"; + } + +/* +* Return a clone of this object +*/ +MessageAuthenticationCode* HMAC::clone() const + { + return new HMAC(m_hash->clone()); + } + +/* +* HMAC Constructor +*/ +HMAC::HMAC(HashFunction* hash) : + m_hash(hash), + m_hash_output_length(m_hash->output_length()), + m_hash_block_size(m_hash->hash_block_size()) + { + BOTAN_ARG_CHECK(m_hash_block_size >= m_hash_output_length, + "HMAC is not compatible with this hash function"); + } + +} diff --git a/comm/third_party/botan/src/lib/mac/hmac/hmac.h b/comm/third_party/botan/src/lib/mac/hmac/hmac.h new file mode 100644 index 0000000000..1f2f4227d4 --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/hmac/hmac.h @@ -0,0 +1,52 @@ +/* +* HMAC +* (C) 1999-2007,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_HMAC_H_ +#define BOTAN_HMAC_H_ + +#include <botan/mac.h> +#include <botan/hash.h> + +BOTAN_FUTURE_INTERNAL_HEADER(hmac.h) + +namespace Botan { + +/** +* HMAC +*/ +class BOTAN_PUBLIC_API(2,0) HMAC final : public MessageAuthenticationCode + { + public: + void clear() override; + std::string name() const override; + MessageAuthenticationCode* clone() const override; + + size_t output_length() const override; + + Key_Length_Specification key_spec() const override; + + /** + * @param hash the hash to use for HMACing + */ + explicit HMAC(HashFunction* hash); + + HMAC(const HMAC&) = delete; + HMAC& operator=(const HMAC&) = delete; + private: + void add_data(const uint8_t[], size_t) override; + void final_result(uint8_t[]) override; + void key_schedule(const uint8_t[], size_t) override; + + std::unique_ptr<HashFunction> m_hash; + secure_vector<uint8_t> m_ikey, m_okey; + size_t m_hash_output_length; + size_t m_hash_block_size; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/mac/hmac/info.txt b/comm/third_party/botan/src/lib/mac/hmac/info.txt new file mode 100644 index 0000000000..50dc665dc9 --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/hmac/info.txt @@ -0,0 +1,7 @@ +<defines> +HMAC -> 20131128 +</defines> + +<requires> +hash +</requires> diff --git a/comm/third_party/botan/src/lib/mac/info.txt b/comm/third_party/botan/src/lib/mac/info.txt new file mode 100644 index 0000000000..7aef92b879 --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/info.txt @@ -0,0 +1,7 @@ +<defines> +MAC -> 20150626 +</defines> + +<header:public> +mac.h +</header:public> diff --git a/comm/third_party/botan/src/lib/mac/mac.cpp b/comm/third_party/botan/src/lib/mac/mac.cpp new file mode 100644 index 0000000000..4c3fc5230e --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/mac.cpp @@ -0,0 +1,171 @@ +/* +* Message Authentication Code base class +* (C) 1999-2008 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/mac.h> +#include <botan/exceptn.h> +#include <botan/scan_name.h> +#include <botan/mem_ops.h> + +#if defined(BOTAN_HAS_CBC_MAC) + #include <botan/cbc_mac.h> +#endif + +#if defined(BOTAN_HAS_CMAC) + #include <botan/cmac.h> +#endif + +#if defined(BOTAN_HAS_GMAC) + #include <botan/gmac.h> + #include <botan/block_cipher.h> +#endif + +#if defined(BOTAN_HAS_HMAC) + #include <botan/hmac.h> + #include <botan/hash.h> +#endif + +#if defined(BOTAN_HAS_POLY1305) + #include <botan/poly1305.h> +#endif + +#if defined(BOTAN_HAS_SIPHASH) + #include <botan/siphash.h> +#endif + +#if defined(BOTAN_HAS_ANSI_X919_MAC) + #include <botan/x919_mac.h> +#endif + +namespace Botan { + +std::unique_ptr<MessageAuthenticationCode> +MessageAuthenticationCode::create(const std::string& algo_spec, + const std::string& provider) + { + const SCAN_Name req(algo_spec); + +#if defined(BOTAN_HAS_GMAC) + if(req.algo_name() == "GMAC" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + if(auto bc = BlockCipher::create(req.arg(0))) + return std::unique_ptr<MessageAuthenticationCode>(new GMAC(bc.release())); + } + } +#endif + +#if defined(BOTAN_HAS_HMAC) + if(req.algo_name() == "HMAC" && req.arg_count() == 1) + { + // TODO OpenSSL + if(provider.empty() || provider == "base") + { + if(auto h = HashFunction::create(req.arg(0))) + return std::unique_ptr<MessageAuthenticationCode>(new HMAC(h.release())); + } + } +#endif + +#if defined(BOTAN_HAS_POLY1305) + if(req.algo_name() == "Poly1305" && req.arg_count() == 0) + { + if(provider.empty() || provider == "base") + return std::unique_ptr<MessageAuthenticationCode>(new Poly1305); + } +#endif + +#if defined(BOTAN_HAS_SIPHASH) + if(req.algo_name() == "SipHash") + { + if(provider.empty() || provider == "base") + { + return std::unique_ptr<MessageAuthenticationCode>( + new SipHash(req.arg_as_integer(0, 2), req.arg_as_integer(1, 4))); + } + } +#endif + +#if defined(BOTAN_HAS_CMAC) + if((req.algo_name() == "CMAC" || req.algo_name() == "OMAC") && req.arg_count() == 1) + { + // TODO: OpenSSL CMAC + if(provider.empty() || provider == "base") + { + if(auto bc = BlockCipher::create(req.arg(0))) + return std::unique_ptr<MessageAuthenticationCode>(new CMAC(bc.release())); + } + } +#endif + + +#if defined(BOTAN_HAS_CBC_MAC) + if(req.algo_name() == "CBC-MAC" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + if(auto bc = BlockCipher::create(req.arg(0))) + return std::unique_ptr<MessageAuthenticationCode>(new CBC_MAC(bc.release())); + } + } +#endif + +#if defined(BOTAN_HAS_ANSI_X919_MAC) + if(req.algo_name() == "X9.19-MAC") + { + if(provider.empty() || provider == "base") + { + return std::unique_ptr<MessageAuthenticationCode>(new ANSI_X919_MAC); + } + } +#endif + + BOTAN_UNUSED(req); + BOTAN_UNUSED(provider); + + return nullptr; + } + +std::vector<std::string> +MessageAuthenticationCode::providers(const std::string& algo_spec) + { + return probe_providers_of<MessageAuthenticationCode>(algo_spec, {"base", "openssl"}); + } + +//static +std::unique_ptr<MessageAuthenticationCode> +MessageAuthenticationCode::create_or_throw(const std::string& algo, + const std::string& provider) + { + if(auto mac = MessageAuthenticationCode::create(algo, provider)) + { + return mac; + } + throw Lookup_Error("MAC", algo, provider); + } + +void MessageAuthenticationCode::start_msg(const uint8_t nonce[], size_t nonce_len) + { + BOTAN_UNUSED(nonce); + if(nonce_len > 0) + throw Invalid_IV_Length(name(), nonce_len); + } + +/* +* Default (deterministic) MAC verification operation +*/ +bool MessageAuthenticationCode::verify_mac(const uint8_t mac[], size_t length) + { + secure_vector<uint8_t> our_mac = final(); + + if(our_mac.size() != length) + return false; + + return constant_time_compare(our_mac.data(), mac, length); + } + +} diff --git a/comm/third_party/botan/src/lib/mac/mac.h b/comm/third_party/botan/src/lib/mac/mac.h new file mode 100644 index 0000000000..de30b7dbb2 --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/mac.h @@ -0,0 +1,143 @@ +/* +* Base class for message authentiction codes +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MESSAGE_AUTH_CODE_BASE_H_ +#define BOTAN_MESSAGE_AUTH_CODE_BASE_H_ + +#include <botan/buf_comp.h> +#include <botan/sym_algo.h> +#include <string> +#include <memory> + +namespace Botan { + +/** +* This class represents Message Authentication Code (MAC) objects. +*/ +class BOTAN_PUBLIC_API(2,0) MessageAuthenticationCode : public Buffered_Computation, + public SymmetricAlgorithm + { + public: + /** + * Create an instance based on a name + * If provider is empty then best available is chosen. + * @param algo_spec algorithm name + * @param provider provider implementation to use + * @return a null pointer if the algo/provider combination cannot be found + */ + static std::unique_ptr<MessageAuthenticationCode> + create(const std::string& algo_spec, + const std::string& provider = ""); + + /* + * Create an instance based on a name + * If provider is empty then best available is chosen. + * @param algo_spec algorithm name + * @param provider provider implementation to use + * Throws a Lookup_Error if algo/provider combination cannot be found + */ + static std::unique_ptr<MessageAuthenticationCode> + create_or_throw(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @return list of available providers for this algorithm, empty if not available + */ + static std::vector<std::string> providers(const std::string& algo_spec); + + virtual ~MessageAuthenticationCode() = default; + + /** + * Prepare for processing a message under the specified nonce + * + * Most MACs neither require nor support a nonce; for these algorithms + * calling `start_msg` is optional and calling it with anything other than + * an empty string is an error. One MAC which *requires* a per-message + * nonce be specified is GMAC. + * + * @param nonce the message nonce bytes + * @param nonce_len the size of len in bytes + * Default implementation simply rejects all non-empty nonces + * since most hash/MAC algorithms do not support randomization + */ + virtual void start_msg(const uint8_t nonce[], size_t nonce_len); + + /** + * Begin processing a message with a nonce + * + * @param nonce the per message nonce + */ + template<typename Alloc> + void start(const std::vector<uint8_t, Alloc>& nonce) + { + start_msg(nonce.data(), nonce.size()); + } + + /** + * Begin processing a message. + * @param nonce the per message nonce + * @param nonce_len length of nonce + */ + void start(const uint8_t nonce[], size_t nonce_len) + { + start_msg(nonce, nonce_len); + } + + /** + * Begin processing a message. + */ + void start() + { + return start_msg(nullptr, 0); + } + + /** + * Verify a MAC. + * @param in the MAC to verify as a byte array + * @param length the length of param in + * @return true if the MAC is valid, false otherwise + */ + virtual bool verify_mac(const uint8_t in[], size_t length); + + /** + * Verify a MAC. + * @param in the MAC to verify as a byte array + * @return true if the MAC is valid, false otherwise + */ + virtual bool verify_mac(const std::vector<uint8_t>& in) + { + return verify_mac(in.data(), in.size()); + } + + /** + * Verify a MAC. + * @param in the MAC to verify as a byte array + * @return true if the MAC is valid, false otherwise + */ + virtual bool verify_mac(const secure_vector<uint8_t>& in) + { + return verify_mac(in.data(), in.size()); + } + + /** + * Get a new object representing the same algorithm as *this + */ + virtual MessageAuthenticationCode* clone() const = 0; + + /** + * @return provider information about this implementation. Default is "base", + * might also return "sse2", "avx2", "openssl", or some other arbitrary string. + */ + virtual std::string provider() const { return "base"; } + + }; + +typedef MessageAuthenticationCode MAC; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/mac/poly1305/info.txt b/comm/third_party/botan/src/lib/mac/poly1305/info.txt new file mode 100644 index 0000000000..868f97241d --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/poly1305/info.txt @@ -0,0 +1,7 @@ +<defines> +POLY1305 -> 20141227 +</defines> + +<header:public> +poly1305.h +</header:public> diff --git a/comm/third_party/botan/src/lib/mac/poly1305/poly1305.cpp b/comm/third_party/botan/src/lib/mac/poly1305/poly1305.cpp new file mode 100644 index 0000000000..333a21a1a6 --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/poly1305/poly1305.cpp @@ -0,0 +1,211 @@ +/* +* Derived from poly1305-donna-64.h by Andrew Moon <liquidsun@gmail.com> +* in https://github.com/floodyberry/poly1305-donna +* +* (C) 2014 Andrew Moon +* (C) 2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/poly1305.h> +#include <botan/loadstor.h> +#include <botan/mul128.h> +#include <botan/internal/donna128.h> +#include <botan/internal/ct_utils.h> + +namespace Botan { + +namespace { + +void poly1305_init(secure_vector<uint64_t>& X, const uint8_t key[32]) + { + /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ + const uint64_t t0 = load_le<uint64_t>(key, 0); + const uint64_t t1 = load_le<uint64_t>(key, 1); + + X[0] = ( t0 ) & 0xffc0fffffff; + X[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff; + X[2] = ((t1 >> 24) ) & 0x00ffffffc0f; + + /* h = 0 */ + X[3] = 0; + X[4] = 0; + X[5] = 0; + + /* save pad for later */ + X[6] = load_le<uint64_t>(key, 2); + X[7] = load_le<uint64_t>(key, 3); + } + +void poly1305_blocks(secure_vector<uint64_t>& X, const uint8_t *m, size_t blocks, bool is_final = false) + { +#if !defined(BOTAN_TARGET_HAS_NATIVE_UINT128) + typedef donna128 uint128_t; +#endif + + const uint64_t hibit = is_final ? 0 : (static_cast<uint64_t>(1) << 40); /* 1 << 128 */ + + const uint64_t r0 = X[0]; + const uint64_t r1 = X[1]; + const uint64_t r2 = X[2]; + + const uint64_t M44 = 0xFFFFFFFFFFF; + const uint64_t M42 = 0x3FFFFFFFFFF; + + uint64_t h0 = X[3+0]; + uint64_t h1 = X[3+1]; + uint64_t h2 = X[3+2]; + + const uint64_t s1 = r1 * 20; + const uint64_t s2 = r2 * 20; + + for(size_t i = 0; i != blocks; ++i) + { + const uint64_t t0 = load_le<uint64_t>(m, 0); + const uint64_t t1 = load_le<uint64_t>(m, 1); + + h0 += (( t0 ) & M44); + h1 += (((t0 >> 44) | (t1 << 20)) & M44); + h2 += (((t1 >> 24) ) & M42) | hibit; + + const uint128_t d0 = uint128_t(h0) * r0 + uint128_t(h1) * s2 + uint128_t(h2) * s1; + const uint64_t c0 = carry_shift(d0, 44); + + const uint128_t d1 = uint128_t(h0) * r1 + uint128_t(h1) * r0 + uint128_t(h2) * s2 + c0; + const uint64_t c1 = carry_shift(d1, 44); + + const uint128_t d2 = uint128_t(h0) * r2 + uint128_t(h1) * r1 + uint128_t(h2) * r0 + c1; + const uint64_t c2 = carry_shift(d2, 42); + + h0 = d0 & M44; + h1 = d1 & M44; + h2 = d2 & M42; + + h0 += c2 * 5; + h1 += carry_shift(h0, 44); + h0 = h0 & M44; + + m += 16; + } + + X[3+0] = h0; + X[3+1] = h1; + X[3+2] = h2; + } + +void poly1305_finish(secure_vector<uint64_t>& X, uint8_t mac[16]) + { + const uint64_t M44 = 0xFFFFFFFFFFF; + const uint64_t M42 = 0x3FFFFFFFFFF; + + /* fully carry h */ + uint64_t h0 = X[3+0]; + uint64_t h1 = X[3+1]; + uint64_t h2 = X[3+2]; + + uint64_t c; + c = (h1 >> 44); h1 &= M44; + h2 += c; c = (h2 >> 42); h2 &= M42; + h0 += c * 5; c = (h0 >> 44); h0 &= M44; + h1 += c; c = (h1 >> 44); h1 &= M44; + h2 += c; c = (h2 >> 42); h2 &= M42; + h0 += c * 5; c = (h0 >> 44); h0 &= M44; + h1 += c; + + /* compute h + -p */ + uint64_t g0 = h0 + 5; c = (g0 >> 44); g0 &= M44; + uint64_t g1 = h1 + c; c = (g1 >> 44); g1 &= M44; + uint64_t g2 = h2 + c - (static_cast<uint64_t>(1) << 42); + + /* select h if h < p, or h + -p if h >= p */ + const auto c_mask = CT::Mask<uint64_t>::expand(c); + h0 = c_mask.select(g0, h0); + h1 = c_mask.select(g1, h1); + h2 = c_mask.select(g2, h2); + + /* h = (h + pad) */ + const uint64_t t0 = X[6]; + const uint64_t t1 = X[7]; + + h0 += (( t0 ) & M44) ; c = (h0 >> 44); h0 &= M44; + h1 += (((t0 >> 44) | (t1 << 20)) & M44) + c; c = (h1 >> 44); h1 &= M44; + h2 += (((t1 >> 24) ) & M42) + c; h2 &= M42; + + /* mac = h % (2^128) */ + h0 = ((h0 ) | (h1 << 44)); + h1 = ((h1 >> 20) | (h2 << 24)); + + store_le(mac, h0, h1); + + /* zero out the state */ + clear_mem(X.data(), X.size()); + } + +} + +void Poly1305::clear() + { + zap(m_poly); + zap(m_buf); + m_buf_pos = 0; + } + +void Poly1305::key_schedule(const uint8_t key[], size_t) + { + m_buf_pos = 0; + m_buf.resize(16); + m_poly.resize(8); + + poly1305_init(m_poly, key); + } + +void Poly1305::add_data(const uint8_t input[], size_t length) + { + verify_key_set(m_poly.size() == 8); + + if(m_buf_pos) + { + buffer_insert(m_buf, m_buf_pos, input, length); + + if(m_buf_pos + length >= m_buf.size()) + { + poly1305_blocks(m_poly, m_buf.data(), 1); + input += (m_buf.size() - m_buf_pos); + length -= (m_buf.size() - m_buf_pos); + m_buf_pos = 0; + } + } + + const size_t full_blocks = length / m_buf.size(); + const size_t remaining = length % m_buf.size(); + + if(full_blocks) + poly1305_blocks(m_poly, input, full_blocks); + + buffer_insert(m_buf, m_buf_pos, input + full_blocks * m_buf.size(), remaining); + m_buf_pos += remaining; + } + +void Poly1305::final_result(uint8_t out[]) + { + verify_key_set(m_poly.size() == 8); + + if(m_buf_pos != 0) + { + m_buf[m_buf_pos] = 1; + const size_t len = m_buf.size() - m_buf_pos - 1; + if (len > 0) + { + clear_mem(&m_buf[m_buf_pos+1], len); + } + poly1305_blocks(m_poly, m_buf.data(), 1, true); + } + + poly1305_finish(m_poly, out); + + m_poly.clear(); + m_buf_pos = 0; + } + +} diff --git a/comm/third_party/botan/src/lib/mac/poly1305/poly1305.h b/comm/third_party/botan/src/lib/mac/poly1305/poly1305.h new file mode 100644 index 0000000000..fdd01ecd1a --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/poly1305/poly1305.h @@ -0,0 +1,50 @@ +/* +* Poly1305 +* (C) 2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MAC_POLY1305_H_ +#define BOTAN_MAC_POLY1305_H_ + +#include <botan/mac.h> +#include <memory> + +BOTAN_FUTURE_INTERNAL_HEADER(poly1305.h) + +namespace Botan { + +/** +* DJB's Poly1305 +* Important note: each key can only be used once +*/ +class BOTAN_PUBLIC_API(2,0) Poly1305 final : public MessageAuthenticationCode + { + public: + std::string name() const override { return "Poly1305"; } + + MessageAuthenticationCode* clone() const override { return new Poly1305; } + + void clear() override; + + size_t output_length() const override { return 16; } + + Key_Length_Specification key_spec() const override + { + return Key_Length_Specification(32); + } + + private: + void add_data(const uint8_t[], size_t) override; + void final_result(uint8_t[]) override; + void key_schedule(const uint8_t[], size_t) override; + + secure_vector<uint64_t> m_poly; + secure_vector<uint8_t> m_buf; + size_t m_buf_pos = 0; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/mac/siphash/info.txt b/comm/third_party/botan/src/lib/mac/siphash/info.txt new file mode 100644 index 0000000000..8d4c20d1a8 --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/siphash/info.txt @@ -0,0 +1,3 @@ +<defines> +SIPHASH -> 20150110 +</defines> diff --git a/comm/third_party/botan/src/lib/mac/siphash/siphash.cpp b/comm/third_party/botan/src/lib/mac/siphash/siphash.cpp new file mode 100644 index 0000000000..566d5d5def --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/siphash/siphash.cpp @@ -0,0 +1,136 @@ +/* +* SipHash +* (C) 2014,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/siphash.h> +#include <botan/loadstor.h> +#include <botan/rotate.h> + +namespace Botan { + +namespace { + +void SipRounds(uint64_t M, secure_vector<uint64_t>& V, size_t r) + { + uint64_t V0 = V[0], V1 = V[1], V2 = V[2], V3 = V[3]; + + V3 ^= M; + for(size_t i = 0; i != r; ++i) + { + V0 += V1; V2 += V3; + V1 = rotl<13>(V1); + V3 = rotl<16>(V3); + V1 ^= V0; V3 ^= V2; + V0 = rotl<32>(V0); + + V2 += V1; V0 += V3; + V1 = rotl<17>(V1); + V3 = rotl<21>(V3); + V1 ^= V2; V3 ^= V0; + V2 = rotl<32>(V2); + } + V0 ^= M; + + V[0] = V0; V[1] = V1; V[2] = V2; V[3] = V3; + } + +} + +void SipHash::add_data(const uint8_t input[], size_t length) + { + verify_key_set(m_V.empty() == false); + + // SipHash counts the message length mod 256 + m_words += static_cast<uint8_t>(length); + + if(m_mbuf_pos) + { + while(length && m_mbuf_pos != 8) + { + m_mbuf = (m_mbuf >> 8) | (static_cast<uint64_t>(input[0]) << 56); + ++m_mbuf_pos; + ++input; + length--; + } + + if(m_mbuf_pos == 8) + { + SipRounds(m_mbuf, m_V, m_C); + m_mbuf_pos = 0; + m_mbuf = 0; + } + } + + while(length >= 8) + { + SipRounds(load_le<uint64_t>(input, 0), m_V, m_C); + input += 8; + length -= 8; + } + + for(size_t i = 0; i != length; ++i) + { + m_mbuf = (m_mbuf >> 8) | (static_cast<uint64_t>(input[i]) << 56); + m_mbuf_pos++; + } + } + +void SipHash::final_result(uint8_t mac[]) + { + verify_key_set(m_V.empty() == false); + + if(m_mbuf_pos == 0) + { + m_mbuf = (static_cast<uint64_t>(m_words) << 56); + } + else if(m_mbuf_pos < 8) + { + m_mbuf = (m_mbuf >> (64-m_mbuf_pos*8)) | (static_cast<uint64_t>(m_words) << 56); + } + + SipRounds(m_mbuf, m_V, m_C); + + m_V[2] ^= 0xFF; + SipRounds(0, m_V, m_D); + + const uint64_t X = m_V[0] ^ m_V[1] ^ m_V[2] ^ m_V[3]; + + store_le(X, mac); + + clear(); + } + +void SipHash::key_schedule(const uint8_t key[], size_t) + { + const uint64_t K0 = load_le<uint64_t>(key, 0); + const uint64_t K1 = load_le<uint64_t>(key, 1); + + m_V.resize(4); + m_V[0] = K0 ^ 0x736F6D6570736575; + m_V[1] = K1 ^ 0x646F72616E646F6D; + m_V[2] = K0 ^ 0x6C7967656E657261; + m_V[3] = K1 ^ 0x7465646279746573; + } + +void SipHash::clear() + { + zap(m_V); + m_mbuf = 0; + m_mbuf_pos = 0; + m_words = 0; + } + +std::string SipHash::name() const + { + return "SipHash(" + std::to_string(m_C) + "," + std::to_string(m_D) + ")"; + } + +MessageAuthenticationCode* SipHash::clone() const + { + return new SipHash(m_C, m_D); + } + +} diff --git a/comm/third_party/botan/src/lib/mac/siphash/siphash.h b/comm/third_party/botan/src/lib/mac/siphash/siphash.h new file mode 100644 index 0000000000..d60df8dfce --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/siphash/siphash.h @@ -0,0 +1,47 @@ +/* +* SipHash +* (C) 2014,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SIPHASH_H_ +#define BOTAN_SIPHASH_H_ + +#include <botan/mac.h> + +BOTAN_FUTURE_INTERNAL_HEADER(siphash.h) + +namespace Botan { + +class BOTAN_PUBLIC_API(2,0) SipHash final : public MessageAuthenticationCode + { + public: + SipHash(size_t c = 2, size_t d = 4) : m_C(c), m_D(d) {} + + void clear() override; + std::string name() const override; + + MessageAuthenticationCode* clone() const override; + + size_t output_length() const override { return 8; } + + Key_Length_Specification key_spec() const override + { + return Key_Length_Specification(16); + } + private: + void add_data(const uint8_t[], size_t) override; + void final_result(uint8_t[]) override; + void key_schedule(const uint8_t[], size_t) override; + + const size_t m_C, m_D; + secure_vector<uint64_t> m_V; + uint64_t m_mbuf = 0; + size_t m_mbuf_pos = 0; + uint8_t m_words = 0; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/mac/x919_mac/info.txt b/comm/third_party/botan/src/lib/mac/x919_mac/info.txt new file mode 100644 index 0000000000..65d6cee645 --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/x919_mac/info.txt @@ -0,0 +1,7 @@ +<defines> +ANSI_X919_MAC -> 20131128 +</defines> + +<requires> +des +</requires> diff --git a/comm/third_party/botan/src/lib/mac/x919_mac/x919_mac.cpp b/comm/third_party/botan/src/lib/mac/x919_mac/x919_mac.cpp new file mode 100644 index 0000000000..0cbf087959 --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/x919_mac/x919_mac.cpp @@ -0,0 +1,99 @@ +/* +* ANSI X9.19 MAC +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/x919_mac.h> + +namespace Botan { + +/* +* Update an ANSI X9.19 MAC Calculation +*/ +void ANSI_X919_MAC::add_data(const uint8_t input[], size_t length) + { + verify_key_set(m_state.empty() == false); + + size_t xored = std::min(8 - m_position, length); + xor_buf(&m_state[m_position], input, xored); + m_position += xored; + + if(m_position < 8) return; + + m_des1->encrypt(m_state); + input += xored; + length -= xored; + while(length >= 8) + { + xor_buf(m_state, input, 8); + m_des1->encrypt(m_state); + input += 8; + length -= 8; + } + + xor_buf(m_state, input, length); + m_position = length; + } + +/* +* Finalize an ANSI X9.19 MAC Calculation +*/ +void ANSI_X919_MAC::final_result(uint8_t mac[]) + { + if(m_position) + m_des1->encrypt(m_state); + m_des2->decrypt(m_state.data(), mac); + m_des1->encrypt(mac); + zeroise(m_state); + m_position = 0; + } + +/* +* ANSI X9.19 MAC Key Schedule +*/ +void ANSI_X919_MAC::key_schedule(const uint8_t key[], size_t length) + { + m_state.resize(8); + + m_des1->set_key(key, 8); + + if(length == 16) + key += 8; + + m_des2->set_key(key, 8); + } + +/* +* Clear memory of sensitive data +*/ +void ANSI_X919_MAC::clear() + { + m_des1->clear(); + m_des2->clear(); + zap(m_state); + m_position = 0; + } + +std::string ANSI_X919_MAC::name() const + { + return "X9.19-MAC"; + } + +MessageAuthenticationCode* ANSI_X919_MAC::clone() const + { + return new ANSI_X919_MAC; + } + +/* +* ANSI X9.19 MAC Constructor +*/ +ANSI_X919_MAC::ANSI_X919_MAC() : + m_des1(BlockCipher::create("DES")), + m_des2(m_des1->clone()), + m_position(0) + { + } + +} diff --git a/comm/third_party/botan/src/lib/mac/x919_mac/x919_mac.h b/comm/third_party/botan/src/lib/mac/x919_mac/x919_mac.h new file mode 100644 index 0000000000..3df38b9aa6 --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/x919_mac/x919_mac.h @@ -0,0 +1,51 @@ +/* +* ANSI X9.19 MAC +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ANSI_X919_MAC_H_ +#define BOTAN_ANSI_X919_MAC_H_ + +#include <botan/mac.h> +#include <botan/block_cipher.h> + +BOTAN_FUTURE_INTERNAL_HEADER(x919_mac.h) + +namespace Botan { + +/** +* DES/3DES-based MAC from ANSI X9.19 +*/ +class BOTAN_PUBLIC_API(2,0) ANSI_X919_MAC final : public MessageAuthenticationCode + { + public: + void clear() override; + std::string name() const override; + size_t output_length() const override { return 8; } + + MessageAuthenticationCode* clone() const override; + + Key_Length_Specification key_spec() const override + { + return Key_Length_Specification(8, 16, 8); + } + + ANSI_X919_MAC(); + + ANSI_X919_MAC(const ANSI_X919_MAC&) = delete; + ANSI_X919_MAC& operator=(const ANSI_X919_MAC&) = delete; + private: + void add_data(const uint8_t[], size_t) override; + void final_result(uint8_t[]) override; + void key_schedule(const uint8_t[], size_t) override; + + std::unique_ptr<BlockCipher> m_des1, m_des2; + secure_vector<uint8_t> m_state; + size_t m_position; + }; + +} + +#endif |