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/stream | |
parent | Initial commit. (diff) | |
download | thunderbird-upstream.tar.xz thunderbird-upstream.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/stream')
25 files changed, 2391 insertions, 0 deletions
diff --git a/comm/third_party/botan/src/lib/stream/chacha/chacha.cpp b/comm/third_party/botan/src/lib/stream/chacha/chacha.cpp new file mode 100644 index 0000000000..c8d567e5e0 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/chacha/chacha.cpp @@ -0,0 +1,384 @@ +/* +* ChaCha +* (C) 2014,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/chacha.h> +#include <botan/exceptn.h> +#include <botan/loadstor.h> +#include <botan/rotate.h> +#include <botan/cpuid.h> + +namespace Botan { + +namespace { + +#define CHACHA_QUARTER_ROUND(a, b, c, d) \ + do { \ + a += b; d ^= a; d = rotl<16>(d); \ + c += d; b ^= c; b = rotl<12>(b); \ + a += b; d ^= a; d = rotl<8>(d); \ + c += d; b ^= c; b = rotl<7>(b); \ + } while(0) + +/* +* Generate HChaCha cipher stream (for XChaCha IV setup) +*/ +void hchacha(uint32_t output[8], const uint32_t input[16], size_t rounds) + { + BOTAN_ASSERT(rounds % 2 == 0, "Valid rounds"); + + uint32_t x00 = input[ 0], x01 = input[ 1], x02 = input[ 2], x03 = input[ 3], + x04 = input[ 4], x05 = input[ 5], x06 = input[ 6], x07 = input[ 7], + x08 = input[ 8], x09 = input[ 9], x10 = input[10], x11 = input[11], + x12 = input[12], x13 = input[13], x14 = input[14], x15 = input[15]; + + for(size_t i = 0; i != rounds / 2; ++i) + { + CHACHA_QUARTER_ROUND(x00, x04, x08, x12); + CHACHA_QUARTER_ROUND(x01, x05, x09, x13); + CHACHA_QUARTER_ROUND(x02, x06, x10, x14); + CHACHA_QUARTER_ROUND(x03, x07, x11, x15); + + CHACHA_QUARTER_ROUND(x00, x05, x10, x15); + CHACHA_QUARTER_ROUND(x01, x06, x11, x12); + CHACHA_QUARTER_ROUND(x02, x07, x08, x13); + CHACHA_QUARTER_ROUND(x03, x04, x09, x14); + } + + output[0] = x00; + output[1] = x01; + output[2] = x02; + output[3] = x03; + output[4] = x12; + output[5] = x13; + output[6] = x14; + output[7] = x15; + } + +} + +ChaCha::ChaCha(size_t rounds) : m_rounds(rounds) + { + BOTAN_ARG_CHECK(m_rounds == 8 || m_rounds == 12 || m_rounds == 20, + "ChaCha only supports 8, 12 or 20 rounds"); + } + +std::string ChaCha::provider() const + { +#if defined(BOTAN_HAS_CHACHA_AVX2) + if(CPUID::has_avx2()) + { + return "avx2"; + } +#endif + +#if defined(BOTAN_HAS_CHACHA_SIMD32) + if(CPUID::has_simd_32()) + { + return "simd32"; + } +#endif + + return "base"; + } + +//static +void ChaCha::chacha_x8(uint8_t output[64*8], uint32_t input[16], size_t rounds) + { + BOTAN_ASSERT(rounds % 2 == 0, "Valid rounds"); + +#if defined(BOTAN_HAS_CHACHA_AVX2) + if(CPUID::has_avx2()) + { + return ChaCha::chacha_avx2_x8(output, input, rounds); + } +#endif + +#if defined(BOTAN_HAS_CHACHA_SIMD32) + if(CPUID::has_simd_32()) + { + ChaCha::chacha_simd32_x4(output, input, rounds); + ChaCha::chacha_simd32_x4(output + 4*64, input, rounds); + return; + } +#endif + + // TODO interleave rounds + for(size_t i = 0; i != 8; ++i) + { + uint32_t x00 = input[ 0], x01 = input[ 1], x02 = input[ 2], x03 = input[ 3], + x04 = input[ 4], x05 = input[ 5], x06 = input[ 6], x07 = input[ 7], + x08 = input[ 8], x09 = input[ 9], x10 = input[10], x11 = input[11], + x12 = input[12], x13 = input[13], x14 = input[14], x15 = input[15]; + + for(size_t r = 0; r != rounds / 2; ++r) + { + CHACHA_QUARTER_ROUND(x00, x04, x08, x12); + CHACHA_QUARTER_ROUND(x01, x05, x09, x13); + CHACHA_QUARTER_ROUND(x02, x06, x10, x14); + CHACHA_QUARTER_ROUND(x03, x07, x11, x15); + + CHACHA_QUARTER_ROUND(x00, x05, x10, x15); + CHACHA_QUARTER_ROUND(x01, x06, x11, x12); + CHACHA_QUARTER_ROUND(x02, x07, x08, x13); + CHACHA_QUARTER_ROUND(x03, x04, x09, x14); + } + + x00 += input[0]; + x01 += input[1]; + x02 += input[2]; + x03 += input[3]; + x04 += input[4]; + x05 += input[5]; + x06 += input[6]; + x07 += input[7]; + x08 += input[8]; + x09 += input[9]; + x10 += input[10]; + x11 += input[11]; + x12 += input[12]; + x13 += input[13]; + x14 += input[14]; + x15 += input[15]; + + store_le(x00, output + 64 * i + 4 * 0); + store_le(x01, output + 64 * i + 4 * 1); + store_le(x02, output + 64 * i + 4 * 2); + store_le(x03, output + 64 * i + 4 * 3); + store_le(x04, output + 64 * i + 4 * 4); + store_le(x05, output + 64 * i + 4 * 5); + store_le(x06, output + 64 * i + 4 * 6); + store_le(x07, output + 64 * i + 4 * 7); + store_le(x08, output + 64 * i + 4 * 8); + store_le(x09, output + 64 * i + 4 * 9); + store_le(x10, output + 64 * i + 4 * 10); + store_le(x11, output + 64 * i + 4 * 11); + store_le(x12, output + 64 * i + 4 * 12); + store_le(x13, output + 64 * i + 4 * 13); + store_le(x14, output + 64 * i + 4 * 14); + store_le(x15, output + 64 * i + 4 * 15); + + input[12]++; + input[13] += (input[12] == 0); + } + } + +#undef CHACHA_QUARTER_ROUND + +/* +* Combine cipher stream with message +*/ +void ChaCha::cipher(const uint8_t in[], uint8_t out[], size_t length) + { + verify_key_set(m_state.empty() == false); + + while(length >= m_buffer.size() - m_position) + { + const size_t available = m_buffer.size() - m_position; + + xor_buf(out, in, &m_buffer[m_position], available); + chacha_x8(m_buffer.data(), m_state.data(), m_rounds); + + length -= available; + in += available; + out += available; + m_position = 0; + } + + xor_buf(out, in, &m_buffer[m_position], length); + + m_position += length; + } + +void ChaCha::write_keystream(uint8_t out[], size_t length) + { + verify_key_set(m_state.empty() == false); + + while(length >= m_buffer.size() - m_position) + { + const size_t available = m_buffer.size() - m_position; + + copy_mem(out, &m_buffer[m_position], available); + chacha_x8(m_buffer.data(), m_state.data(), m_rounds); + + length -= available; + out += available; + m_position = 0; + } + + copy_mem(out, &m_buffer[m_position], length); + + m_position += length; + } + +void ChaCha::initialize_state() + { + static const uint32_t TAU[] = + { 0x61707865, 0x3120646e, 0x79622d36, 0x6b206574 }; + + static const uint32_t SIGMA[] = + { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 }; + + m_state[4] = m_key[0]; + m_state[5] = m_key[1]; + m_state[6] = m_key[2]; + m_state[7] = m_key[3]; + + if(m_key.size() == 4) + { + m_state[0] = TAU[0]; + m_state[1] = TAU[1]; + m_state[2] = TAU[2]; + m_state[3] = TAU[3]; + + m_state[8] = m_key[0]; + m_state[9] = m_key[1]; + m_state[10] = m_key[2]; + m_state[11] = m_key[3]; + } + else + { + m_state[0] = SIGMA[0]; + m_state[1] = SIGMA[1]; + m_state[2] = SIGMA[2]; + m_state[3] = SIGMA[3]; + + m_state[8] = m_key[4]; + m_state[9] = m_key[5]; + m_state[10] = m_key[6]; + m_state[11] = m_key[7]; + } + + m_state[12] = 0; + m_state[13] = 0; + m_state[14] = 0; + m_state[15] = 0; + + m_position = 0; + } + +/* +* ChaCha Key Schedule +*/ +void ChaCha::key_schedule(const uint8_t key[], size_t length) + { + m_key.resize(length / 4); + load_le<uint32_t>(m_key.data(), key, m_key.size()); + + m_state.resize(16); + + const size_t chacha_parallelism = 8; // chacha_x8 + const size_t chacha_block = 64; + m_buffer.resize(chacha_parallelism * chacha_block); + + set_iv(nullptr, 0); + } + +size_t ChaCha::default_iv_length() const + { + return 24; + } + +Key_Length_Specification ChaCha::key_spec() const + { + return Key_Length_Specification(16, 32, 16); + } + +StreamCipher* ChaCha::clone() const + { + return new ChaCha(m_rounds); + } + +bool ChaCha::valid_iv_length(size_t iv_len) const + { + return (iv_len == 0 || iv_len == 8 || iv_len == 12 || iv_len == 24); + } + +void ChaCha::set_iv(const uint8_t iv[], size_t length) + { + verify_key_set(m_state.empty() == false); + + if(!valid_iv_length(length)) + throw Invalid_IV_Length(name(), length); + + initialize_state(); + + if(length == 0) + { + // Treat zero length IV same as an all-zero IV + m_state[14] = 0; + m_state[15] = 0; + } + else if(length == 8) + { + m_state[14] = load_le<uint32_t>(iv, 0); + m_state[15] = load_le<uint32_t>(iv, 1); + } + else if(length == 12) + { + m_state[13] = load_le<uint32_t>(iv, 0); + m_state[14] = load_le<uint32_t>(iv, 1); + m_state[15] = load_le<uint32_t>(iv, 2); + } + else if(length == 24) + { + m_state[12] = load_le<uint32_t>(iv, 0); + m_state[13] = load_le<uint32_t>(iv, 1); + m_state[14] = load_le<uint32_t>(iv, 2); + m_state[15] = load_le<uint32_t>(iv, 3); + + secure_vector<uint32_t> hc(8); + hchacha(hc.data(), m_state.data(), m_rounds); + + m_state[ 4] = hc[0]; + m_state[ 5] = hc[1]; + m_state[ 6] = hc[2]; + m_state[ 7] = hc[3]; + m_state[ 8] = hc[4]; + m_state[ 9] = hc[5]; + m_state[10] = hc[6]; + m_state[11] = hc[7]; + m_state[12] = 0; + m_state[13] = 0; + m_state[14] = load_le<uint32_t>(iv, 4); + m_state[15] = load_le<uint32_t>(iv, 5); + } + + chacha_x8(m_buffer.data(), m_state.data(), m_rounds); + m_position = 0; + } + +void ChaCha::clear() + { + zap(m_key); + zap(m_state); + zap(m_buffer); + m_position = 0; + } + +std::string ChaCha::name() const + { + return "ChaCha(" + std::to_string(m_rounds) + ")"; + } + +void ChaCha::seek(uint64_t offset) + { + verify_key_set(m_state.empty() == false); + + // Find the block offset + const uint64_t counter = offset / 64; + + uint8_t out[8]; + + store_le(counter, out); + + m_state[12] = load_le<uint32_t>(out, 0); + m_state[13] += load_le<uint32_t>(out, 1); + + chacha_x8(m_buffer.data(), m_state.data(), m_rounds); + m_position = offset % 64; + } +} diff --git a/comm/third_party/botan/src/lib/stream/chacha/chacha.h b/comm/third_party/botan/src/lib/stream/chacha/chacha.h new file mode 100644 index 0000000000..1749127f28 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/chacha/chacha.h @@ -0,0 +1,82 @@ +/* +* ChaCha20 +* (C) 2014,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CHACHA_H_ +#define BOTAN_CHACHA_H_ + +#include <botan/stream_cipher.h> + +BOTAN_FUTURE_INTERNAL_HEADER(chacha.h) + +namespace Botan { + +/** +* DJB's ChaCha (https://cr.yp.to/chacha.html) +*/ +class BOTAN_PUBLIC_API(2,0) ChaCha final : public StreamCipher + { + public: + /** + * @param rounds number of rounds + * @note Currently only 8, 12 or 20 rounds are supported, all others + * will throw an exception + */ + explicit ChaCha(size_t rounds = 20); + + std::string provider() const override; + + void cipher(const uint8_t in[], uint8_t out[], size_t length) override; + + void write_keystream(uint8_t out[], size_t len) override; + + void set_iv(const uint8_t iv[], size_t iv_len) override; + + /* + * ChaCha accepts 0, 8, 12 or 24 byte IVs. + * The default IV is a 8 zero bytes. + * An IV of length 0 is treated the same as the default zero IV. + * An IV of length 24 selects XChaCha mode + */ + bool valid_iv_length(size_t iv_len) const override; + + size_t default_iv_length() const override; + + Key_Length_Specification key_spec() const override; + + void clear() override; + + StreamCipher* clone() const override; + + std::string name() const override; + + void seek(uint64_t offset) override; + + private: + void key_schedule(const uint8_t key[], size_t key_len) override; + + void initialize_state(); + + void chacha_x8(uint8_t output[64*8], uint32_t state[16], size_t rounds); + +#if defined(BOTAN_HAS_CHACHA_SIMD32) + void chacha_simd32_x4(uint8_t output[64*4], uint32_t state[16], size_t rounds); +#endif + +#if defined(BOTAN_HAS_CHACHA_AVX2) + void chacha_avx2_x8(uint8_t output[64*8], uint32_t state[16], size_t rounds); +#endif + + size_t m_rounds; + secure_vector<uint32_t> m_key; + secure_vector<uint32_t> m_state; + secure_vector<uint8_t> m_buffer; + size_t m_position = 0; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/stream/chacha/chacha_avx2/chacha_avx2.cpp b/comm/third_party/botan/src/lib/stream/chacha/chacha_avx2/chacha_avx2.cpp new file mode 100644 index 0000000000..78d2365214 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/chacha/chacha_avx2/chacha_avx2.cpp @@ -0,0 +1,207 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/chacha.h> +#include <botan/internal/simd_avx2.h> + +namespace Botan { + +//static +BOTAN_FUNC_ISA("avx2") +void ChaCha::chacha_avx2_x8(uint8_t output[64*8], uint32_t state[16], size_t rounds) + { + SIMD_8x32::reset_registers(); + + BOTAN_ASSERT(rounds % 2 == 0, "Valid rounds"); + const SIMD_8x32 CTR0 = SIMD_8x32(0, 1, 2, 3, 4, 5, 6, 7); + + const uint32_t C = 0xFFFFFFFF - state[12]; + const SIMD_8x32 CTR1 = SIMD_8x32(0, C < 1, C < 2, C < 3, C < 4, C < 5, C < 6, C < 7); + + SIMD_8x32 R00 = SIMD_8x32::splat(state[ 0]); + SIMD_8x32 R01 = SIMD_8x32::splat(state[ 1]); + SIMD_8x32 R02 = SIMD_8x32::splat(state[ 2]); + SIMD_8x32 R03 = SIMD_8x32::splat(state[ 3]); + SIMD_8x32 R04 = SIMD_8x32::splat(state[ 4]); + SIMD_8x32 R05 = SIMD_8x32::splat(state[ 5]); + SIMD_8x32 R06 = SIMD_8x32::splat(state[ 6]); + SIMD_8x32 R07 = SIMD_8x32::splat(state[ 7]); + SIMD_8x32 R08 = SIMD_8x32::splat(state[ 8]); + SIMD_8x32 R09 = SIMD_8x32::splat(state[ 9]); + SIMD_8x32 R10 = SIMD_8x32::splat(state[10]); + SIMD_8x32 R11 = SIMD_8x32::splat(state[11]); + SIMD_8x32 R12 = SIMD_8x32::splat(state[12]) + CTR0; + SIMD_8x32 R13 = SIMD_8x32::splat(state[13]) + CTR1; + SIMD_8x32 R14 = SIMD_8x32::splat(state[14]); + SIMD_8x32 R15 = SIMD_8x32::splat(state[15]); + + for(size_t r = 0; r != rounds / 2; ++r) + { + R00 += R04; + R01 += R05; + R02 += R06; + R03 += R07; + + R12 ^= R00; + R13 ^= R01; + R14 ^= R02; + R15 ^= R03; + + R12 = R12.rotl<16>(); + R13 = R13.rotl<16>(); + R14 = R14.rotl<16>(); + R15 = R15.rotl<16>(); + + R08 += R12; + R09 += R13; + R10 += R14; + R11 += R15; + + R04 ^= R08; + R05 ^= R09; + R06 ^= R10; + R07 ^= R11; + + R04 = R04.rotl<12>(); + R05 = R05.rotl<12>(); + R06 = R06.rotl<12>(); + R07 = R07.rotl<12>(); + + R00 += R04; + R01 += R05; + R02 += R06; + R03 += R07; + + R12 ^= R00; + R13 ^= R01; + R14 ^= R02; + R15 ^= R03; + + R12 = R12.rotl<8>(); + R13 = R13.rotl<8>(); + R14 = R14.rotl<8>(); + R15 = R15.rotl<8>(); + + R08 += R12; + R09 += R13; + R10 += R14; + R11 += R15; + + R04 ^= R08; + R05 ^= R09; + R06 ^= R10; + R07 ^= R11; + + R04 = R04.rotl<7>(); + R05 = R05.rotl<7>(); + R06 = R06.rotl<7>(); + R07 = R07.rotl<7>(); + + R00 += R05; + R01 += R06; + R02 += R07; + R03 += R04; + + R15 ^= R00; + R12 ^= R01; + R13 ^= R02; + R14 ^= R03; + + R15 = R15.rotl<16>(); + R12 = R12.rotl<16>(); + R13 = R13.rotl<16>(); + R14 = R14.rotl<16>(); + + R10 += R15; + R11 += R12; + R08 += R13; + R09 += R14; + + R05 ^= R10; + R06 ^= R11; + R07 ^= R08; + R04 ^= R09; + + R05 = R05.rotl<12>(); + R06 = R06.rotl<12>(); + R07 = R07.rotl<12>(); + R04 = R04.rotl<12>(); + + R00 += R05; + R01 += R06; + R02 += R07; + R03 += R04; + + R15 ^= R00; + R12 ^= R01; + R13 ^= R02; + R14 ^= R03; + + R15 = R15.rotl<8>(); + R12 = R12.rotl<8>(); + R13 = R13.rotl<8>(); + R14 = R14.rotl<8>(); + + R10 += R15; + R11 += R12; + R08 += R13; + R09 += R14; + + R05 ^= R10; + R06 ^= R11; + R07 ^= R08; + R04 ^= R09; + + R05 = R05.rotl<7>(); + R06 = R06.rotl<7>(); + R07 = R07.rotl<7>(); + R04 = R04.rotl<7>(); + } + + R00 += SIMD_8x32::splat(state[0]); + R01 += SIMD_8x32::splat(state[1]); + R02 += SIMD_8x32::splat(state[2]); + R03 += SIMD_8x32::splat(state[3]); + R04 += SIMD_8x32::splat(state[4]); + R05 += SIMD_8x32::splat(state[5]); + R06 += SIMD_8x32::splat(state[6]); + R07 += SIMD_8x32::splat(state[7]); + R08 += SIMD_8x32::splat(state[8]); + R09 += SIMD_8x32::splat(state[9]); + R10 += SIMD_8x32::splat(state[10]); + R11 += SIMD_8x32::splat(state[11]); + R12 += SIMD_8x32::splat(state[12]) + CTR0; + R13 += SIMD_8x32::splat(state[13]) + CTR1; + R14 += SIMD_8x32::splat(state[14]); + R15 += SIMD_8x32::splat(state[15]); + + SIMD_8x32::transpose(R00, R01, R02, R03, R04, R05, R06, R07); + SIMD_8x32::transpose(R08, R09, R10, R11, R12, R13, R14, R15); + + R00.store_le(output); + R08.store_le(output + 32*1); + R01.store_le(output + 32*2); + R09.store_le(output + 32*3); + R02.store_le(output + 32*4); + R10.store_le(output + 32*5); + R03.store_le(output + 32*6); + R11.store_le(output + 32*7); + R04.store_le(output + 32*8); + R12.store_le(output + 32*9); + R05.store_le(output + 32*10); + R13.store_le(output + 32*11); + R06.store_le(output + 32*12); + R14.store_le(output + 32*13); + R07.store_le(output + 32*14); + R15.store_le(output + 32*15); + + SIMD_8x32::zero_registers(); + + state[12] += 8; + if(state[12] < 8) + state[13]++; + } +} diff --git a/comm/third_party/botan/src/lib/stream/chacha/chacha_avx2/info.txt b/comm/third_party/botan/src/lib/stream/chacha/chacha_avx2/info.txt new file mode 100644 index 0000000000..64f102cc58 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/chacha/chacha_avx2/info.txt @@ -0,0 +1,11 @@ +<defines> +CHACHA_AVX2 -> 20180418 +</defines> + +<isa> +avx2 +</isa> + +<requires> +simd_avx2 +</requires> diff --git a/comm/third_party/botan/src/lib/stream/chacha/chacha_simd32/chacha_simd32.cpp b/comm/third_party/botan/src/lib/stream/chacha/chacha_simd32/chacha_simd32.cpp new file mode 100644 index 0000000000..6cd6acd0d8 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/chacha/chacha_simd32/chacha_simd32.cpp @@ -0,0 +1,205 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/chacha.h> +#include <botan/internal/simd_32.h> + +namespace Botan { + +//static +void ChaCha::chacha_simd32_x4(uint8_t output[64*4], uint32_t state[16], size_t rounds) + { + BOTAN_ASSERT(rounds % 2 == 0, "Valid rounds"); + const SIMD_4x32 CTR0 = SIMD_4x32(0, 1, 2, 3); + + const uint32_t C = 0xFFFFFFFF - state[12]; + const SIMD_4x32 CTR1 = SIMD_4x32(0, C < 1, C < 2, C < 3); + + SIMD_4x32 R00 = SIMD_4x32::splat(state[ 0]); + SIMD_4x32 R01 = SIMD_4x32::splat(state[ 1]); + SIMD_4x32 R02 = SIMD_4x32::splat(state[ 2]); + SIMD_4x32 R03 = SIMD_4x32::splat(state[ 3]); + SIMD_4x32 R04 = SIMD_4x32::splat(state[ 4]); + SIMD_4x32 R05 = SIMD_4x32::splat(state[ 5]); + SIMD_4x32 R06 = SIMD_4x32::splat(state[ 6]); + SIMD_4x32 R07 = SIMD_4x32::splat(state[ 7]); + SIMD_4x32 R08 = SIMD_4x32::splat(state[ 8]); + SIMD_4x32 R09 = SIMD_4x32::splat(state[ 9]); + SIMD_4x32 R10 = SIMD_4x32::splat(state[10]); + SIMD_4x32 R11 = SIMD_4x32::splat(state[11]); + SIMD_4x32 R12 = SIMD_4x32::splat(state[12]) + CTR0; + SIMD_4x32 R13 = SIMD_4x32::splat(state[13]) + CTR1; + SIMD_4x32 R14 = SIMD_4x32::splat(state[14]); + SIMD_4x32 R15 = SIMD_4x32::splat(state[15]); + + for(size_t r = 0; r != rounds / 2; ++r) + { + R00 += R04; + R01 += R05; + R02 += R06; + R03 += R07; + + R12 ^= R00; + R13 ^= R01; + R14 ^= R02; + R15 ^= R03; + + R12 = R12.rotl<16>(); + R13 = R13.rotl<16>(); + R14 = R14.rotl<16>(); + R15 = R15.rotl<16>(); + + R08 += R12; + R09 += R13; + R10 += R14; + R11 += R15; + + R04 ^= R08; + R05 ^= R09; + R06 ^= R10; + R07 ^= R11; + + R04 = R04.rotl<12>(); + R05 = R05.rotl<12>(); + R06 = R06.rotl<12>(); + R07 = R07.rotl<12>(); + + R00 += R04; + R01 += R05; + R02 += R06; + R03 += R07; + + R12 ^= R00; + R13 ^= R01; + R14 ^= R02; + R15 ^= R03; + + R12 = R12.rotl<8>(); + R13 = R13.rotl<8>(); + R14 = R14.rotl<8>(); + R15 = R15.rotl<8>(); + + R08 += R12; + R09 += R13; + R10 += R14; + R11 += R15; + + R04 ^= R08; + R05 ^= R09; + R06 ^= R10; + R07 ^= R11; + + R04 = R04.rotl<7>(); + R05 = R05.rotl<7>(); + R06 = R06.rotl<7>(); + R07 = R07.rotl<7>(); + + R00 += R05; + R01 += R06; + R02 += R07; + R03 += R04; + + R15 ^= R00; + R12 ^= R01; + R13 ^= R02; + R14 ^= R03; + + R15 = R15.rotl<16>(); + R12 = R12.rotl<16>(); + R13 = R13.rotl<16>(); + R14 = R14.rotl<16>(); + + R10 += R15; + R11 += R12; + R08 += R13; + R09 += R14; + + R05 ^= R10; + R06 ^= R11; + R07 ^= R08; + R04 ^= R09; + + R05 = R05.rotl<12>(); + R06 = R06.rotl<12>(); + R07 = R07.rotl<12>(); + R04 = R04.rotl<12>(); + + R00 += R05; + R01 += R06; + R02 += R07; + R03 += R04; + + R15 ^= R00; + R12 ^= R01; + R13 ^= R02; + R14 ^= R03; + + R15 = R15.rotl<8>(); + R12 = R12.rotl<8>(); + R13 = R13.rotl<8>(); + R14 = R14.rotl<8>(); + + R10 += R15; + R11 += R12; + R08 += R13; + R09 += R14; + + R05 ^= R10; + R06 ^= R11; + R07 ^= R08; + R04 ^= R09; + + R05 = R05.rotl<7>(); + R06 = R06.rotl<7>(); + R07 = R07.rotl<7>(); + R04 = R04.rotl<7>(); + } + + R00 += SIMD_4x32::splat(state[0]); + R01 += SIMD_4x32::splat(state[1]); + R02 += SIMD_4x32::splat(state[2]); + R03 += SIMD_4x32::splat(state[3]); + R04 += SIMD_4x32::splat(state[4]); + R05 += SIMD_4x32::splat(state[5]); + R06 += SIMD_4x32::splat(state[6]); + R07 += SIMD_4x32::splat(state[7]); + R08 += SIMD_4x32::splat(state[8]); + R09 += SIMD_4x32::splat(state[9]); + R10 += SIMD_4x32::splat(state[10]); + R11 += SIMD_4x32::splat(state[11]); + R12 += SIMD_4x32::splat(state[12]) + CTR0; + R13 += SIMD_4x32::splat(state[13]) + CTR1; + R14 += SIMD_4x32::splat(state[14]); + R15 += SIMD_4x32::splat(state[15]); + + SIMD_4x32::transpose(R00, R01, R02, R03); + SIMD_4x32::transpose(R04, R05, R06, R07); + SIMD_4x32::transpose(R08, R09, R10, R11); + SIMD_4x32::transpose(R12, R13, R14, R15); + + R00.store_le(output + 0*16); + R04.store_le(output + 1*16); + R08.store_le(output + 2*16); + R12.store_le(output + 3*16); + R01.store_le(output + 4*16); + R05.store_le(output + 5*16); + R09.store_le(output + 6*16); + R13.store_le(output + 7*16); + R02.store_le(output + 8*16); + R06.store_le(output + 9*16); + R10.store_le(output + 10*16); + R14.store_le(output + 11*16); + R03.store_le(output + 12*16); + R07.store_le(output + 13*16); + R11.store_le(output + 14*16); + R15.store_le(output + 15*16); + + state[12] += 4; + if(state[12] < 4) + state[13]++; + } + +} diff --git a/comm/third_party/botan/src/lib/stream/chacha/chacha_simd32/info.txt b/comm/third_party/botan/src/lib/stream/chacha/chacha_simd32/info.txt new file mode 100644 index 0000000000..1ec932f811 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/chacha/chacha_simd32/info.txt @@ -0,0 +1,7 @@ +<defines> +CHACHA_SIMD32 -> 20181104 +</defines> + +<requires> +simd +</requires> diff --git a/comm/third_party/botan/src/lib/stream/chacha/info.txt b/comm/third_party/botan/src/lib/stream/chacha/info.txt new file mode 100644 index 0000000000..ba9c3da341 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/chacha/info.txt @@ -0,0 +1,3 @@ +<defines> +CHACHA -> 20180807 +</defines> diff --git a/comm/third_party/botan/src/lib/stream/ctr/ctr.cpp b/comm/third_party/botan/src/lib/stream/ctr/ctr.cpp new file mode 100644 index 0000000000..e2ed0e7126 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/ctr/ctr.cpp @@ -0,0 +1,256 @@ +/* +* Counter mode +* (C) 1999-2011,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/ctr.h> +#include <botan/exceptn.h> +#include <botan/loadstor.h> +#include <botan/internal/bit_ops.h> + +namespace Botan { + +CTR_BE::CTR_BE(BlockCipher* ciph) : + m_cipher(ciph), + m_block_size(m_cipher->block_size()), + m_ctr_size(m_block_size), + m_ctr_blocks(m_cipher->parallel_bytes() / m_block_size), + m_counter(m_cipher->parallel_bytes()), + m_pad(m_counter.size()), + m_pad_pos(0) + { + } + +CTR_BE::CTR_BE(BlockCipher* cipher, size_t ctr_size) : + m_cipher(cipher), + m_block_size(m_cipher->block_size()), + m_ctr_size(ctr_size), + m_ctr_blocks(m_cipher->parallel_bytes() / m_block_size), + m_counter(m_cipher->parallel_bytes()), + m_pad(m_counter.size()), + m_pad_pos(0) + { + BOTAN_ARG_CHECK(m_ctr_size >= 4 && m_ctr_size <= m_block_size, + "Invalid CTR-BE counter size"); + } + +void CTR_BE::clear() + { + m_cipher->clear(); + zeroise(m_pad); + zeroise(m_counter); + zap(m_iv); + m_pad_pos = 0; + } + +size_t CTR_BE::default_iv_length() const + { + return m_block_size; + } + +bool CTR_BE::valid_iv_length(size_t iv_len) const + { + return (iv_len <= m_block_size); + } + +Key_Length_Specification CTR_BE::key_spec() const + { + return m_cipher->key_spec(); + } + +CTR_BE* CTR_BE::clone() const + { + return new CTR_BE(m_cipher->clone(), m_ctr_size); + } + +void CTR_BE::key_schedule(const uint8_t key[], size_t key_len) + { + m_cipher->set_key(key, key_len); + + // Set a default all-zeros IV + set_iv(nullptr, 0); + } + +std::string CTR_BE::name() const + { + if(m_ctr_size == m_block_size) + return ("CTR-BE(" + m_cipher->name() + ")"); + else + return ("CTR-BE(" + m_cipher->name() + "," + std::to_string(m_ctr_size) + ")"); + + } + +void CTR_BE::cipher(const uint8_t in[], uint8_t out[], size_t length) + { + verify_key_set(m_iv.empty() == false); + + const uint8_t* pad_bits = &m_pad[0]; + const size_t pad_size = m_pad.size(); + + if(m_pad_pos > 0) + { + const size_t avail = pad_size - m_pad_pos; + const size_t take = std::min(length, avail); + xor_buf(out, in, pad_bits + m_pad_pos, take); + length -= take; + in += take; + out += take; + m_pad_pos += take; + + if(take == avail) + { + add_counter(m_ctr_blocks); + m_cipher->encrypt_n(m_counter.data(), m_pad.data(), m_ctr_blocks); + m_pad_pos = 0; + } + } + + while(length >= pad_size) + { + xor_buf(out, in, pad_bits, pad_size); + length -= pad_size; + in += pad_size; + out += pad_size; + + add_counter(m_ctr_blocks); + m_cipher->encrypt_n(m_counter.data(), m_pad.data(), m_ctr_blocks); + } + + xor_buf(out, in, pad_bits, length); + m_pad_pos += length; + } + +void CTR_BE::set_iv(const uint8_t iv[], size_t iv_len) + { + if(!valid_iv_length(iv_len)) + throw Invalid_IV_Length(name(), iv_len); + + m_iv.resize(m_block_size); + zeroise(m_iv); + buffer_insert(m_iv, 0, iv, iv_len); + + seek(0); + } + +void CTR_BE::add_counter(const uint64_t counter) + { + const size_t ctr_size = m_ctr_size; + const size_t ctr_blocks = m_ctr_blocks; + const size_t BS = m_block_size; + + if(ctr_size == 4) + { + const size_t off = (BS - 4); + const uint32_t low32 = static_cast<uint32_t>(counter + load_be<uint32_t>(&m_counter[off], 0)); + + for(size_t i = 0; i != ctr_blocks; ++i) + { + store_be(uint32_t(low32 + i), &m_counter[i*BS+off]); + } + } + else if(ctr_size == 8) + { + const size_t off = (BS - 8); + const uint64_t low64 = counter + load_be<uint64_t>(&m_counter[off], 0); + + for(size_t i = 0; i != ctr_blocks; ++i) + { + store_be(uint64_t(low64 + i), &m_counter[i*BS+off]); + } + } + else if(ctr_size == 16) + { + const size_t off = (BS - 16); + uint64_t b0 = load_be<uint64_t>(&m_counter[off], 0); + uint64_t b1 = load_be<uint64_t>(&m_counter[off], 1); + b1 += counter; + b0 += (b1 < counter) ? 1 : 0; // carry + + for(size_t i = 0; i != ctr_blocks; ++i) + { + store_be(b0, &m_counter[i*BS+off]); + store_be(b1, &m_counter[i*BS+off+8]); + b1 += 1; + b0 += (b1 == 0); // carry + } + } + else + { + for(size_t i = 0; i != ctr_blocks; ++i) + { + uint64_t local_counter = counter; + uint16_t carry = static_cast<uint8_t>(local_counter); + for(size_t j = 0; (carry || local_counter) && j != ctr_size; ++j) + { + const size_t off = i*BS + (BS-1-j); + const uint16_t cnt = static_cast<uint16_t>(m_counter[off]) + carry; + m_counter[off] = static_cast<uint8_t>(cnt); + local_counter = (local_counter >> 8); + carry = (cnt >> 8) + static_cast<uint8_t>(local_counter); + } + } + } + } + +void CTR_BE::seek(uint64_t offset) + { + verify_key_set(m_iv.empty() == false); + + const uint64_t base_counter = m_ctr_blocks * (offset / m_counter.size()); + + zeroise(m_counter); + buffer_insert(m_counter, 0, m_iv); + + const size_t BS = m_block_size; + + // Set m_counter blocks to IV, IV + 1, ... IV + n + + if(m_ctr_size == 4 && BS >= 8) + { + const uint32_t low32 = load_be<uint32_t>(&m_counter[BS-4], 0); + + if(m_ctr_blocks >= 4 && is_power_of_2(m_ctr_blocks)) + { + size_t written = 1; + while(written < m_ctr_blocks) + { + copy_mem(&m_counter[written*BS], &m_counter[0], BS*written); + written *= 2; + } + } + else + { + for(size_t i = 1; i != m_ctr_blocks; ++i) + { + copy_mem(&m_counter[i*BS], &m_counter[0], BS - 4); + } + } + + for(size_t i = 1; i != m_ctr_blocks; ++i) + { + const uint32_t c = static_cast<uint32_t>(low32 + i); + store_be(c, &m_counter[(BS-4)+i*BS]); + } + } + else + { + // do everything sequentially: + for(size_t i = 1; i != m_ctr_blocks; ++i) + { + buffer_insert(m_counter, i*BS, &m_counter[(i-1)*BS], BS); + + for(size_t j = 0; j != m_ctr_size; ++j) + if(++m_counter[i*BS + (BS - 1 - j)]) + break; + } + } + + if(base_counter > 0) + add_counter(base_counter); + + m_cipher->encrypt_n(m_counter.data(), m_pad.data(), m_ctr_blocks); + m_pad_pos = offset % m_counter.size(); + } +} diff --git a/comm/third_party/botan/src/lib/stream/ctr/ctr.h b/comm/third_party/botan/src/lib/stream/ctr/ctr.h new file mode 100644 index 0000000000..0687c606e1 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/ctr/ctr.h @@ -0,0 +1,65 @@ +/* +* CTR-BE Mode +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CTR_BE_H_ +#define BOTAN_CTR_BE_H_ + +#include <botan/block_cipher.h> +#include <botan/stream_cipher.h> + +BOTAN_FUTURE_INTERNAL_HEADER(ctr.h) + +namespace Botan { + +/** +* CTR-BE (Counter mode, big-endian) +*/ +class BOTAN_PUBLIC_API(2,0) CTR_BE final : public StreamCipher + { + public: + void cipher(const uint8_t in[], uint8_t out[], size_t length) override; + + void set_iv(const uint8_t iv[], size_t iv_len) override; + + size_t default_iv_length() const override; + + bool valid_iv_length(size_t iv_len) const override; + + Key_Length_Specification key_spec() const override; + + std::string name() const override; + + CTR_BE* clone() const override; + + void clear() override; + + /** + * @param cipher the block cipher to use + */ + explicit CTR_BE(BlockCipher* cipher); + + CTR_BE(BlockCipher* cipher, size_t ctr_size); + + void seek(uint64_t offset) override; + private: + void key_schedule(const uint8_t key[], size_t key_len) override; + void add_counter(const uint64_t counter); + + std::unique_ptr<BlockCipher> m_cipher; + + const size_t m_block_size; + const size_t m_ctr_size; + const size_t m_ctr_blocks; + + secure_vector<uint8_t> m_counter, m_pad; + std::vector<uint8_t> m_iv; + size_t m_pad_pos; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/stream/ctr/info.txt b/comm/third_party/botan/src/lib/stream/ctr/info.txt new file mode 100644 index 0000000000..270ceecf8b --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/ctr/info.txt @@ -0,0 +1,7 @@ +<defines> +CTR_BE -> 20131128 +</defines> + +<requires> +block +</requires> diff --git a/comm/third_party/botan/src/lib/stream/info.txt b/comm/third_party/botan/src/lib/stream/info.txt new file mode 100644 index 0000000000..4f62c5a7c1 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/info.txt @@ -0,0 +1,7 @@ +<defines> +STREAM_CIPHER -> 20131128 +</defines> + +<header:public> +stream_cipher.h +</header:public> diff --git a/comm/third_party/botan/src/lib/stream/ofb/info.txt b/comm/third_party/botan/src/lib/stream/ofb/info.txt new file mode 100644 index 0000000000..2675e78573 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/ofb/info.txt @@ -0,0 +1,7 @@ +<defines> +OFB -> 20131128 +</defines> + +<requires> +block +</requires> diff --git a/comm/third_party/botan/src/lib/stream/ofb/ofb.cpp b/comm/third_party/botan/src/lib/stream/ofb/ofb.cpp new file mode 100644 index 0000000000..dde4681171 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/ofb/ofb.cpp @@ -0,0 +1,92 @@ +/* +* OFB Mode +* (C) 1999-2007,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/ofb.h> +#include <botan/exceptn.h> + +namespace Botan { + +OFB::OFB(BlockCipher* cipher) : + m_cipher(cipher), + m_buffer(m_cipher->block_size()), + m_buf_pos(0) + { + } + +void OFB::clear() + { + m_cipher->clear(); + zeroise(m_buffer); + m_buf_pos = 0; + } + +void OFB::key_schedule(const uint8_t key[], size_t key_len) + { + m_cipher->set_key(key, key_len); + + // Set a default all-zeros IV + set_iv(nullptr, 0); + } + +std::string OFB::name() const + { + return "OFB(" + m_cipher->name() + ")"; + } + +size_t OFB::default_iv_length() const + { + return m_cipher->block_size(); + } + +bool OFB::valid_iv_length(size_t iv_len) const + { + return (iv_len <= m_cipher->block_size()); + } + +Key_Length_Specification OFB::key_spec() const + { + return m_cipher->key_spec(); + } + +OFB* OFB::clone() const + { + return new OFB(m_cipher->clone()); + } + +void OFB::cipher(const uint8_t in[], uint8_t out[], size_t length) + { + while(length >= m_buffer.size() - m_buf_pos) + { + xor_buf(out, in, &m_buffer[m_buf_pos], m_buffer.size() - m_buf_pos); + length -= (m_buffer.size() - m_buf_pos); + in += (m_buffer.size() - m_buf_pos); + out += (m_buffer.size() - m_buf_pos); + m_cipher->encrypt(m_buffer); + m_buf_pos = 0; + } + xor_buf(out, in, &m_buffer[m_buf_pos], length); + m_buf_pos += length; + } + +void OFB::set_iv(const uint8_t iv[], size_t iv_len) + { + if(!valid_iv_length(iv_len)) + throw Invalid_IV_Length(name(), iv_len); + + zeroise(m_buffer); + buffer_insert(m_buffer, 0, iv, iv_len); + + m_cipher->encrypt(m_buffer); + m_buf_pos = 0; + } + + +void OFB::seek(uint64_t) + { + throw Not_Implemented("OFB does not support seeking"); + } +} diff --git a/comm/third_party/botan/src/lib/stream/ofb/ofb.h b/comm/third_party/botan/src/lib/stream/ofb/ofb.h new file mode 100644 index 0000000000..994d3d198d --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/ofb/ofb.h @@ -0,0 +1,56 @@ +/* +* OFB Mode +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_OUTPUT_FEEDBACK_MODE_H_ +#define BOTAN_OUTPUT_FEEDBACK_MODE_H_ + +#include <botan/stream_cipher.h> +#include <botan/block_cipher.h> + +BOTAN_FUTURE_INTERNAL_HEADER(ofb.h) + +namespace Botan { + +/** +* Output Feedback Mode +*/ +class BOTAN_PUBLIC_API(2,0) OFB final : public StreamCipher + { + public: + void cipher(const uint8_t in[], uint8_t out[], size_t length) override; + + void set_iv(const uint8_t iv[], size_t iv_len) override; + + size_t default_iv_length() const override; + + bool valid_iv_length(size_t iv_len) const override; + + Key_Length_Specification key_spec() const override; + + std::string name() const override; + + OFB* clone() const override; + + void clear() override; + + /** + * @param cipher the block cipher to use + */ + explicit OFB(BlockCipher* cipher); + + void seek(uint64_t offset) override; + private: + void key_schedule(const uint8_t key[], size_t key_len) override; + + std::unique_ptr<BlockCipher> m_cipher; + secure_vector<uint8_t> m_buffer; + size_t m_buf_pos; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/stream/rc4/info.txt b/comm/third_party/botan/src/lib/stream/rc4/info.txt new file mode 100644 index 0000000000..97cc227602 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/rc4/info.txt @@ -0,0 +1,3 @@ +<defines> +RC4 -> 20131128 +</defines> diff --git a/comm/third_party/botan/src/lib/stream/rc4/rc4.cpp b/comm/third_party/botan/src/lib/stream/rc4/rc4.cpp new file mode 100644 index 0000000000..8bb01a2387 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/rc4/rc4.cpp @@ -0,0 +1,133 @@ +/* +* RC4 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/rc4.h> +#include <botan/exceptn.h> + +namespace Botan { + +/* +* Combine cipher stream with message +*/ +void RC4::cipher(const uint8_t in[], uint8_t out[], size_t length) + { + verify_key_set(m_state.empty() == false); + + while(length >= m_buffer.size() - m_position) + { + xor_buf(out, in, &m_buffer[m_position], m_buffer.size() - m_position); + length -= (m_buffer.size() - m_position); + in += (m_buffer.size() - m_position); + out += (m_buffer.size() - m_position); + generate(); + } + xor_buf(out, in, &m_buffer[m_position], length); + m_position += length; + } + +StreamCipher* RC4::clone() const + { + return new RC4(m_SKIP); + } + +Key_Length_Specification RC4::key_spec() const + { + return Key_Length_Specification(1, 256); + } + +void RC4::set_iv(const uint8_t*, size_t length) + { + if(length > 0) + throw Invalid_IV_Length("RC4", length); + } + +/* +* Generate cipher stream +*/ +void RC4::generate() + { + uint8_t SX, SY; + for(size_t i = 0; i != m_buffer.size(); i += 4) + { + SX = m_state[m_X+1]; m_Y = (m_Y + SX) % 256; SY = m_state[m_Y]; + m_state[m_X+1] = SY; m_state[m_Y] = SX; + m_buffer[i] = m_state[(SX + SY) % 256]; + + SX = m_state[m_X+2]; m_Y = (m_Y + SX) % 256; SY = m_state[m_Y]; + m_state[m_X+2] = SY; m_state[m_Y] = SX; + m_buffer[i+1] = m_state[(SX + SY) % 256]; + + SX = m_state[m_X+3]; m_Y = (m_Y + SX) % 256; SY = m_state[m_Y]; + m_state[m_X+3] = SY; m_state[m_Y] = SX; + m_buffer[i+2] = m_state[(SX + SY) % 256]; + + m_X = (m_X + 4) % 256; + SX = m_state[m_X]; m_Y = (m_Y + SX) % 256; SY = m_state[m_Y]; + m_state[m_X] = SY; m_state[m_Y] = SX; + m_buffer[i+3] = m_state[(SX + SY) % 256]; + } + m_position = 0; + } + +/* +* RC4 Key Schedule +*/ +void RC4::key_schedule(const uint8_t key[], size_t length) + { + m_state.resize(256); + m_buffer.resize(256); + + m_position = m_X = m_Y = 0; + + for(size_t i = 0; i != 256; ++i) + m_state[i] = static_cast<uint8_t>(i); + + for(size_t i = 0, state_index = 0; i != 256; ++i) + { + state_index = (state_index + key[i % length] + m_state[i]) % 256; + std::swap(m_state[i], m_state[state_index]); + } + + for(size_t i = 0; i <= m_SKIP; i += m_buffer.size()) + generate(); + + m_position += (m_SKIP % m_buffer.size()); + } + +/* +* Return the name of this type +*/ +std::string RC4::name() const + { + if(m_SKIP == 0) + return "RC4"; + else if(m_SKIP == 256) + return "MARK-4"; + else + return "RC4(" + std::to_string(m_SKIP) + ")"; + } + +/* +* Clear memory of sensitive data +*/ +void RC4::clear() + { + zap(m_state); + zap(m_buffer); + m_position = m_X = m_Y = 0; + } + +/* +* RC4 Constructor +*/ +RC4::RC4(size_t s) : m_SKIP(s) {} + +void RC4::seek(uint64_t) + { + throw Not_Implemented("RC4 does not support seeking"); + } +} diff --git a/comm/third_party/botan/src/lib/stream/rc4/rc4.h b/comm/third_party/botan/src/lib/stream/rc4/rc4.h new file mode 100644 index 0000000000..eff3c568db --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/rc4/rc4.h @@ -0,0 +1,57 @@ +/* +* RC4 +* (C) 1999-2008 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_RC4_H_ +#define BOTAN_RC4_H_ + +#include <botan/stream_cipher.h> +#include <botan/types.h> + +BOTAN_FUTURE_INTERNAL_HEADER(rc4.h) + +namespace Botan { + +/** +* RC4 stream cipher +*/ +class BOTAN_PUBLIC_API(2,0) RC4 final : public StreamCipher + { + public: + void cipher(const uint8_t in[], uint8_t out[], size_t length) override; + + void set_iv(const uint8_t iv[], size_t iv_len) override; + + void clear() override; + std::string name() const override; + + StreamCipher* clone() const override; + + Key_Length_Specification key_spec() const override; + + /** + * @param skip skip this many initial bytes in the keystream + */ + explicit RC4(size_t skip = 0); + + ~RC4() { clear(); } + + void seek(uint64_t offset) override; + private: + void key_schedule(const uint8_t[], size_t) override; + void generate(); + + const size_t m_SKIP; + uint8_t m_X = 0; + uint8_t m_Y = 0; + secure_vector<uint8_t> m_state; + secure_vector<uint8_t> m_buffer; + size_t m_position = 0; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/stream/salsa20/info.txt b/comm/third_party/botan/src/lib/stream/salsa20/info.txt new file mode 100644 index 0000000000..8e9bfa5683 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/salsa20/info.txt @@ -0,0 +1,3 @@ +<defines> +SALSA20 -> 20171114 +</defines> diff --git a/comm/third_party/botan/src/lib/stream/salsa20/salsa20.cpp b/comm/third_party/botan/src/lib/stream/salsa20/salsa20.cpp new file mode 100644 index 0000000000..1e30391d21 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/salsa20/salsa20.cpp @@ -0,0 +1,302 @@ +/* +* Salsa20 / XSalsa20 +* (C) 1999-2010,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/salsa20.h> +#include <botan/exceptn.h> +#include <botan/loadstor.h> +#include <botan/rotate.h> + +namespace Botan { + +#define SALSA20_QUARTER_ROUND(x1, x2, x3, x4) \ + do { \ + x2 ^= rotl<7>(x1 + x4); \ + x3 ^= rotl<9>(x2 + x1); \ + x4 ^= rotl<13>(x3 + x2); \ + x1 ^= rotl<18>(x4 + x3); \ + } while(0) + +/* +* Generate HSalsa20 cipher stream (for XSalsa20 IV setup) +*/ +//static +void Salsa20::hsalsa20(uint32_t output[8], const uint32_t input[16]) + { + uint32_t x00 = input[ 0], x01 = input[ 1], x02 = input[ 2], x03 = input[ 3], + x04 = input[ 4], x05 = input[ 5], x06 = input[ 6], x07 = input[ 7], + x08 = input[ 8], x09 = input[ 9], x10 = input[10], x11 = input[11], + x12 = input[12], x13 = input[13], x14 = input[14], x15 = input[15]; + + for(size_t i = 0; i != 10; ++i) + { + SALSA20_QUARTER_ROUND(x00, x04, x08, x12); + SALSA20_QUARTER_ROUND(x05, x09, x13, x01); + SALSA20_QUARTER_ROUND(x10, x14, x02, x06); + SALSA20_QUARTER_ROUND(x15, x03, x07, x11); + + SALSA20_QUARTER_ROUND(x00, x01, x02, x03); + SALSA20_QUARTER_ROUND(x05, x06, x07, x04); + SALSA20_QUARTER_ROUND(x10, x11, x08, x09); + SALSA20_QUARTER_ROUND(x15, x12, x13, x14); + } + + output[0] = x00; + output[1] = x05; + output[2] = x10; + output[3] = x15; + output[4] = x06; + output[5] = x07; + output[6] = x08; + output[7] = x09; + } + +/* +* Generate Salsa20 cipher stream +*/ +//static +void Salsa20::salsa_core(uint8_t output[64], const uint32_t input[16], size_t rounds) + { + BOTAN_ASSERT_NOMSG(rounds % 2 == 0); + + uint32_t x00 = input[ 0], x01 = input[ 1], x02 = input[ 2], x03 = input[ 3], + x04 = input[ 4], x05 = input[ 5], x06 = input[ 6], x07 = input[ 7], + x08 = input[ 8], x09 = input[ 9], x10 = input[10], x11 = input[11], + x12 = input[12], x13 = input[13], x14 = input[14], x15 = input[15]; + + for(size_t i = 0; i != rounds / 2; ++i) + { + SALSA20_QUARTER_ROUND(x00, x04, x08, x12); + SALSA20_QUARTER_ROUND(x05, x09, x13, x01); + SALSA20_QUARTER_ROUND(x10, x14, x02, x06); + SALSA20_QUARTER_ROUND(x15, x03, x07, x11); + + SALSA20_QUARTER_ROUND(x00, x01, x02, x03); + SALSA20_QUARTER_ROUND(x05, x06, x07, x04); + SALSA20_QUARTER_ROUND(x10, x11, x08, x09); + SALSA20_QUARTER_ROUND(x15, x12, x13, x14); + } + + store_le(x00 + input[ 0], output + 4 * 0); + store_le(x01 + input[ 1], output + 4 * 1); + store_le(x02 + input[ 2], output + 4 * 2); + store_le(x03 + input[ 3], output + 4 * 3); + store_le(x04 + input[ 4], output + 4 * 4); + store_le(x05 + input[ 5], output + 4 * 5); + store_le(x06 + input[ 6], output + 4 * 6); + store_le(x07 + input[ 7], output + 4 * 7); + store_le(x08 + input[ 8], output + 4 * 8); + store_le(x09 + input[ 9], output + 4 * 9); + store_le(x10 + input[10], output + 4 * 10); + store_le(x11 + input[11], output + 4 * 11); + store_le(x12 + input[12], output + 4 * 12); + store_le(x13 + input[13], output + 4 * 13); + store_le(x14 + input[14], output + 4 * 14); + store_le(x15 + input[15], output + 4 * 15); + } + +#undef SALSA20_QUARTER_ROUND + +/* +* Combine cipher stream with message +*/ +void Salsa20::cipher(const uint8_t in[], uint8_t out[], size_t length) + { + verify_key_set(m_state.empty() == false); + + while(length >= m_buffer.size() - m_position) + { + const size_t available = m_buffer.size() - m_position; + + xor_buf(out, in, &m_buffer[m_position], available); + salsa_core(m_buffer.data(), m_state.data(), 20); + + ++m_state[8]; + m_state[9] += (m_state[8] == 0); + + length -= available; + in += available; + out += available; + + m_position = 0; + } + + xor_buf(out, in, &m_buffer[m_position], length); + + m_position += length; + } + +void Salsa20::initialize_state() + { + static const uint32_t TAU[] = + { 0x61707865, 0x3120646e, 0x79622d36, 0x6b206574 }; + + static const uint32_t SIGMA[] = + { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 }; + + m_state[1] = m_key[0]; + m_state[2] = m_key[1]; + m_state[3] = m_key[2]; + m_state[4] = m_key[3]; + + if(m_key.size() == 4) + { + m_state[0] = TAU[0]; + m_state[5] = TAU[1]; + m_state[10] = TAU[2]; + m_state[15] = TAU[3]; + m_state[11] = m_key[0]; + m_state[12] = m_key[1]; + m_state[13] = m_key[2]; + m_state[14] = m_key[3]; + } + else + { + m_state[0] = SIGMA[0]; + m_state[5] = SIGMA[1]; + m_state[10] = SIGMA[2]; + m_state[15] = SIGMA[3]; + m_state[11] = m_key[4]; + m_state[12] = m_key[5]; + m_state[13] = m_key[6]; + m_state[14] = m_key[7]; + } + + m_state[6] = 0; + m_state[7] = 0; + m_state[8] = 0; + m_state[9] = 0; + + m_position = 0; + } + +/* +* Salsa20 Key Schedule +*/ +void Salsa20::key_schedule(const uint8_t key[], size_t length) + { + m_key.resize(length / 4); + load_le<uint32_t>(m_key.data(), key, m_key.size()); + + m_state.resize(16); + m_buffer.resize(64); + + set_iv(nullptr, 0); + } + +/* +* Set the Salsa IV +*/ +void Salsa20::set_iv(const uint8_t iv[], size_t length) + { + verify_key_set(m_state.empty() == false); + + if(!valid_iv_length(length)) + throw Invalid_IV_Length(name(), length); + + initialize_state(); + + if(length == 0) + { + // Salsa20 null IV + m_state[6] = 0; + m_state[7] = 0; + } + else if(length == 8) + { + // Salsa20 + m_state[6] = load_le<uint32_t>(iv, 0); + m_state[7] = load_le<uint32_t>(iv, 1); + } + else + { + // XSalsa20 + m_state[6] = load_le<uint32_t>(iv, 0); + m_state[7] = load_le<uint32_t>(iv, 1); + m_state[8] = load_le<uint32_t>(iv, 2); + m_state[9] = load_le<uint32_t>(iv, 3); + + secure_vector<uint32_t> hsalsa(8); + hsalsa20(hsalsa.data(), m_state.data()); + + m_state[ 1] = hsalsa[0]; + m_state[ 2] = hsalsa[1]; + m_state[ 3] = hsalsa[2]; + m_state[ 4] = hsalsa[3]; + m_state[ 6] = load_le<uint32_t>(iv, 4); + m_state[ 7] = load_le<uint32_t>(iv, 5); + m_state[11] = hsalsa[4]; + m_state[12] = hsalsa[5]; + m_state[13] = hsalsa[6]; + m_state[14] = hsalsa[7]; + } + + m_state[8] = 0; + m_state[9] = 0; + + salsa_core(m_buffer.data(), m_state.data(), 20); + ++m_state[8]; + m_state[9] += (m_state[8] == 0); + + m_position = 0; + } + +bool Salsa20::valid_iv_length(size_t iv_len) const + { + return (iv_len == 0 || iv_len == 8 || iv_len == 24); + } + +size_t Salsa20::default_iv_length() const + { + return 24; + } + +Key_Length_Specification Salsa20::key_spec() const + { + return Key_Length_Specification(16, 32, 16); + } + +StreamCipher* Salsa20::clone() const + { + return new Salsa20; + } + +std::string Salsa20::name() const + { + return "Salsa20"; + } + +/* +* Clear memory of sensitive data +*/ +void Salsa20::clear() + { + zap(m_key); + zap(m_state); + zap(m_buffer); + m_position = 0; + } + +void Salsa20::seek(uint64_t offset) + { + verify_key_set(m_state.empty() == false); + + // Find the block offset + const uint64_t counter = offset / 64; + uint8_t counter8[8]; + store_le(counter, counter8); + + m_state[8] = load_le<uint32_t>(counter8, 0); + m_state[9] += load_le<uint32_t>(counter8, 1); + + salsa_core(m_buffer.data(), m_state.data(), 20); + + ++m_state[8]; + m_state[9] += (m_state[8] == 0); + + m_position = offset % 64; + } +} diff --git a/comm/third_party/botan/src/lib/stream/salsa20/salsa20.h b/comm/third_party/botan/src/lib/stream/salsa20/salsa20.h new file mode 100644 index 0000000000..6ad0da7709 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/salsa20/salsa20.h @@ -0,0 +1,54 @@ +/* +* Salsa20 / XSalsa20 +* (C) 1999-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SALSA20_H_ +#define BOTAN_SALSA20_H_ + +#include <botan/stream_cipher.h> + +BOTAN_FUTURE_INTERNAL_HEADER(salsa20.h) + +namespace Botan { + +/** +* DJB's Salsa20 (and XSalsa20) +*/ +class BOTAN_PUBLIC_API(2,0) Salsa20 final : public StreamCipher + { + public: + void cipher(const uint8_t in[], uint8_t out[], size_t length) override; + + void set_iv(const uint8_t iv[], size_t iv_len) override; + + bool valid_iv_length(size_t iv_len) const override; + + size_t default_iv_length() const override; + + Key_Length_Specification key_spec() const override; + + void clear() override; + std::string name() const override; + StreamCipher* clone() const override; + + static void salsa_core(uint8_t output[64], const uint32_t input[16], size_t rounds); + static void hsalsa20(uint32_t output[8], const uint32_t input[16]); + + void seek(uint64_t offset) override; + private: + void key_schedule(const uint8_t key[], size_t key_len) override; + + void initialize_state(); + + secure_vector<uint32_t> m_key; + secure_vector<uint32_t> m_state; + secure_vector<uint8_t> m_buffer; + size_t m_position = 0; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/stream/shake_cipher/info.txt b/comm/third_party/botan/src/lib/stream/shake_cipher/info.txt new file mode 100644 index 0000000000..ca2a0c079c --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/shake_cipher/info.txt @@ -0,0 +1,7 @@ +<defines> +SHAKE_CIPHER -> 20161018 +</defines> + +<requires> +sha3 +</requires> diff --git a/comm/third_party/botan/src/lib/stream/shake_cipher/shake_cipher.cpp b/comm/third_party/botan/src/lib/stream/shake_cipher/shake_cipher.cpp new file mode 100644 index 0000000000..f1920959e3 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/shake_cipher/shake_cipher.cpp @@ -0,0 +1,90 @@ +/* +* SHAKE-128 +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/shake_cipher.h> +#include <botan/exceptn.h> +#include <botan/sha3.h> +#include <botan/loadstor.h> + +namespace Botan { + +SHAKE_128_Cipher::SHAKE_128_Cipher() : + m_buf_pos(0) + {} + +void SHAKE_128_Cipher::cipher(const uint8_t in[], uint8_t out[], size_t length) + { + const size_t SHAKE_128_BYTERATE = (1600-256)/8; + + verify_key_set(m_state.empty() == false); + + while(length >= SHAKE_128_BYTERATE - m_buf_pos) + { + xor_buf(out, in, &m_buffer[m_buf_pos], SHAKE_128_BYTERATE - m_buf_pos); + length -= (SHAKE_128_BYTERATE - m_buf_pos); + in += (SHAKE_128_BYTERATE - m_buf_pos); + out += (SHAKE_128_BYTERATE - m_buf_pos); + + SHA_3::permute(m_state.data()); + copy_out_le(m_buffer.data(), SHAKE_128_BYTERATE, m_state.data()); + + m_buf_pos = 0; + } + xor_buf(out, in, &m_buffer[m_buf_pos], length); + m_buf_pos += length; + } + +void SHAKE_128_Cipher::key_schedule(const uint8_t key[], size_t length) + { + const size_t SHAKE_128_BITRATE = (1600-256); + m_state.resize(25); + m_buffer.resize(SHAKE_128_BITRATE/8); + zeroise(m_state); + + const size_t S_pos = SHA_3::absorb(SHAKE_128_BITRATE, m_state, 0, key, length); + SHA_3::finish(SHAKE_128_BITRATE, m_state, S_pos, 0x1F, 0x80); + copy_out_le(m_buffer.data(), m_buffer.size(), m_state.data()); + } + +void SHAKE_128_Cipher::clear() + { + zap(m_state); + zap(m_buffer); + m_buf_pos = 0; + } + +void SHAKE_128_Cipher::set_iv(const uint8_t[], size_t length) + { + /* + * This could be supported in some way (say, by treating iv as + * a prefix or suffix of the key). + */ + if(length != 0) + throw Invalid_IV_Length(name(), length); + } + +void SHAKE_128_Cipher::seek(uint64_t) + { + throw Not_Implemented("SHAKE_128_Cipher::seek"); + } + +Key_Length_Specification SHAKE_128_Cipher::key_spec() const + { + return Key_Length_Specification(1, 160); + } + +std::string SHAKE_128_Cipher::name() const + { + return "SHAKE-128"; + } + +StreamCipher* SHAKE_128_Cipher::clone() const + { + return new SHAKE_128_Cipher; + } + +} diff --git a/comm/third_party/botan/src/lib/stream/shake_cipher/shake_cipher.h b/comm/third_party/botan/src/lib/stream/shake_cipher/shake_cipher.h new file mode 100644 index 0000000000..85eaec2a85 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/shake_cipher/shake_cipher.h @@ -0,0 +1,57 @@ +/* +* SHAKE-128 as a stream cipher +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SHAKE128_CIPHER_H_ +#define BOTAN_SHAKE128_CIPHER_H_ + +#include <botan/stream_cipher.h> +#include <botan/secmem.h> + +BOTAN_FUTURE_INTERNAL_HEADER(shake_cipher.h) + +namespace Botan { + +/** +* SHAKE-128 XOF presented as a stream cipher +*/ +class BOTAN_PUBLIC_API(2,0) SHAKE_128_Cipher final : public StreamCipher + { + public: + SHAKE_128_Cipher(); + + /** + * Produce more XOF output + */ + void cipher(const uint8_t in[], uint8_t out[], size_t length) override; + + /** + * Seeking is not supported, this function will throw + */ + void seek(uint64_t offset) override; + + /** + * IV not supported, this function will throw unless iv_len == 0 + */ + void set_iv(const uint8_t iv[], size_t iv_len) override; + + Key_Length_Specification key_spec() const override; + + void clear() override; + std::string name() const override; + StreamCipher* clone() const override; + + private: + void key_schedule(const uint8_t key[], size_t key_len) override; + + secure_vector<uint64_t> m_state; // internal state + secure_vector<uint8_t> m_buffer; // ciphertext buffer + size_t m_buf_pos; // position in m_buffer + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/stream/stream_cipher.cpp b/comm/third_party/botan/src/lib/stream/stream_cipher.cpp new file mode 100644 index 0000000000..340682ce25 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/stream_cipher.cpp @@ -0,0 +1,149 @@ +/* +* Stream Ciphers +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/stream_cipher.h> +#include <botan/scan_name.h> +#include <botan/exceptn.h> + +#if defined(BOTAN_HAS_CHACHA) + #include <botan/chacha.h> +#endif + +#if defined(BOTAN_HAS_SALSA20) + #include <botan/salsa20.h> +#endif + +#if defined(BOTAN_HAS_SHAKE_CIPHER) + #include <botan/shake_cipher.h> +#endif + +#if defined(BOTAN_HAS_CTR_BE) + #include <botan/ctr.h> +#endif + +#if defined(BOTAN_HAS_OFB) + #include <botan/ofb.h> +#endif + +#if defined(BOTAN_HAS_RC4) + #include <botan/rc4.h> +#endif + +#if defined(BOTAN_HAS_OPENSSL) + #include <botan/internal/openssl.h> +#endif + +namespace Botan { + +std::unique_ptr<StreamCipher> StreamCipher::create(const std::string& algo_spec, + const std::string& provider) + { + const SCAN_Name req(algo_spec); + +#if defined(BOTAN_HAS_CTR_BE) + if((req.algo_name() == "CTR-BE" || req.algo_name() == "CTR") && req.arg_count_between(1,2)) + { + if(provider.empty() || provider == "base") + { + auto cipher = BlockCipher::create(req.arg(0)); + if(cipher) + { + size_t ctr_size = req.arg_as_integer(1, cipher->block_size()); + return std::unique_ptr<StreamCipher>(new CTR_BE(cipher.release(), ctr_size)); + } + } + } +#endif + +#if defined(BOTAN_HAS_CHACHA) + if(req.algo_name() == "ChaCha") + { + if(provider.empty() || provider == "base") + return std::unique_ptr<StreamCipher>(new ChaCha(req.arg_as_integer(0, 20))); + } + + if(req.algo_name() == "ChaCha20") + { + if(provider.empty() || provider == "base") + return std::unique_ptr<StreamCipher>(new ChaCha(20)); + } +#endif + +#if defined(BOTAN_HAS_SALSA20) + if(req.algo_name() == "Salsa20") + { + if(provider.empty() || provider == "base") + return std::unique_ptr<StreamCipher>(new Salsa20); + } +#endif + +#if defined(BOTAN_HAS_SHAKE_CIPHER) + if(req.algo_name() == "SHAKE-128" || req.algo_name() == "SHAKE-128-XOF") + { + if(provider.empty() || provider == "base") + return std::unique_ptr<StreamCipher>(new SHAKE_128_Cipher); + } +#endif + +#if defined(BOTAN_HAS_OFB) + if(req.algo_name() == "OFB" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + if(auto c = BlockCipher::create(req.arg(0))) + return std::unique_ptr<StreamCipher>(new OFB(c.release())); + } + } +#endif + +#if defined(BOTAN_HAS_RC4) + + if(req.algo_name() == "RC4" || + req.algo_name() == "ARC4" || + req.algo_name() == "MARK-4") + { + const size_t skip = (req.algo_name() == "MARK-4") ? 256 : req.arg_as_integer(0, 0); + +#if defined(BOTAN_HAS_OPENSSL) + if(provider.empty() || provider == "openssl") + { + return std::unique_ptr<StreamCipher>(make_openssl_rc4(skip)); + } +#endif + + if(provider.empty() || provider == "base") + { + return std::unique_ptr<StreamCipher>(new RC4(skip)); + } + } + +#endif + + BOTAN_UNUSED(req); + BOTAN_UNUSED(provider); + + return nullptr; + } + +//static +std::unique_ptr<StreamCipher> +StreamCipher::create_or_throw(const std::string& algo, + const std::string& provider) + { + if(auto sc = StreamCipher::create(algo, provider)) + { + return sc; + } + throw Lookup_Error("Stream cipher", algo, provider); + } + +std::vector<std::string> StreamCipher::providers(const std::string& algo_spec) + { + return probe_providers_of<StreamCipher>(algo_spec, {"base", "openssl"}); + } + +} diff --git a/comm/third_party/botan/src/lib/stream/stream_cipher.h b/comm/third_party/botan/src/lib/stream/stream_cipher.h new file mode 100644 index 0000000000..a07f210413 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/stream_cipher.h @@ -0,0 +1,147 @@ +/* +* Stream Cipher +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_STREAM_CIPHER_H_ +#define BOTAN_STREAM_CIPHER_H_ + +#include <botan/sym_algo.h> +#include <string> +#include <memory> +#include <vector> + +namespace Botan { + +/** +* Base class for all stream ciphers +*/ +class BOTAN_PUBLIC_API(2,0) StreamCipher : public SymmetricAlgorithm + { + public: + virtual ~StreamCipher() = default; + + /** + * 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<StreamCipher> + 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 the algo/provider combination cannot be found + */ + static std::unique_ptr<StreamCipher> + 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); + + /** + * Encrypt or decrypt a message + * @param in the plaintext + * @param out the byte array to hold the output, i.e. the ciphertext + * @param len the length of both in and out in bytes + */ + virtual void cipher(const uint8_t in[], uint8_t out[], size_t len) = 0; + + /** + * Write keystream bytes to a buffer + * @param out the byte array to hold the keystream + * @param len the length of out in bytes + */ + virtual void write_keystream(uint8_t out[], size_t len) + { + clear_mem(out, len); + cipher1(out, len); + } + + /** + * Encrypt or decrypt a message + * The message is encrypted/decrypted in place. + * @param buf the plaintext / ciphertext + * @param len the length of buf in bytes + */ + void cipher1(uint8_t buf[], size_t len) + { cipher(buf, buf, len); } + + /** + * Encrypt a message + * The message is encrypted/decrypted in place. + * @param inout the plaintext / ciphertext + */ + template<typename Alloc> + void encipher(std::vector<uint8_t, Alloc>& inout) + { cipher(inout.data(), inout.data(), inout.size()); } + + /** + * Encrypt a message + * The message is encrypted in place. + * @param inout the plaintext / ciphertext + */ + template<typename Alloc> + void encrypt(std::vector<uint8_t, Alloc>& inout) + { cipher(inout.data(), inout.data(), inout.size()); } + + /** + * Decrypt a message in place + * The message is decrypted in place. + * @param inout the plaintext / ciphertext + */ + template<typename Alloc> + void decrypt(std::vector<uint8_t, Alloc>& inout) + { cipher(inout.data(), inout.data(), inout.size()); } + + /** + * Resync the cipher using the IV + * @param iv the initialization vector + * @param iv_len the length of the IV in bytes + */ + virtual void set_iv(const uint8_t iv[], size_t iv_len) = 0; + + /** + * Return the default (preferred) nonce length + * If this function returns 0, then this cipher does not support nonces + */ + virtual size_t default_iv_length() const { return 0; } + + /** + * @param iv_len the length of the IV in bytes + * @return if the length is valid for this algorithm + */ + virtual bool valid_iv_length(size_t iv_len) const { return (iv_len == 0); } + + /** + * @return a new object representing the same algorithm as *this + */ + virtual StreamCipher* clone() const = 0; + + /** + * Set the offset and the state used later to generate the keystream + * @param offset the offset where we begin to generate the keystream + */ + virtual void seek(uint64_t offset) = 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"; } + }; + +} + +#endif |