summaryrefslogtreecommitdiffstats
path: root/comm/third_party/botan/src/lib/stream
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
commit6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /comm/third_party/botan/src/lib/stream
parentInitial commit. (diff)
downloadthunderbird-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')
-rw-r--r--comm/third_party/botan/src/lib/stream/chacha/chacha.cpp384
-rw-r--r--comm/third_party/botan/src/lib/stream/chacha/chacha.h82
-rw-r--r--comm/third_party/botan/src/lib/stream/chacha/chacha_avx2/chacha_avx2.cpp207
-rw-r--r--comm/third_party/botan/src/lib/stream/chacha/chacha_avx2/info.txt11
-rw-r--r--comm/third_party/botan/src/lib/stream/chacha/chacha_simd32/chacha_simd32.cpp205
-rw-r--r--comm/third_party/botan/src/lib/stream/chacha/chacha_simd32/info.txt7
-rw-r--r--comm/third_party/botan/src/lib/stream/chacha/info.txt3
-rw-r--r--comm/third_party/botan/src/lib/stream/ctr/ctr.cpp256
-rw-r--r--comm/third_party/botan/src/lib/stream/ctr/ctr.h65
-rw-r--r--comm/third_party/botan/src/lib/stream/ctr/info.txt7
-rw-r--r--comm/third_party/botan/src/lib/stream/info.txt7
-rw-r--r--comm/third_party/botan/src/lib/stream/ofb/info.txt7
-rw-r--r--comm/third_party/botan/src/lib/stream/ofb/ofb.cpp92
-rw-r--r--comm/third_party/botan/src/lib/stream/ofb/ofb.h56
-rw-r--r--comm/third_party/botan/src/lib/stream/rc4/info.txt3
-rw-r--r--comm/third_party/botan/src/lib/stream/rc4/rc4.cpp133
-rw-r--r--comm/third_party/botan/src/lib/stream/rc4/rc4.h57
-rw-r--r--comm/third_party/botan/src/lib/stream/salsa20/info.txt3
-rw-r--r--comm/third_party/botan/src/lib/stream/salsa20/salsa20.cpp302
-rw-r--r--comm/third_party/botan/src/lib/stream/salsa20/salsa20.h54
-rw-r--r--comm/third_party/botan/src/lib/stream/shake_cipher/info.txt7
-rw-r--r--comm/third_party/botan/src/lib/stream/shake_cipher/shake_cipher.cpp90
-rw-r--r--comm/third_party/botan/src/lib/stream/shake_cipher/shake_cipher.h57
-rw-r--r--comm/third_party/botan/src/lib/stream/stream_cipher.cpp149
-rw-r--r--comm/third_party/botan/src/lib/stream/stream_cipher.h147
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