aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/hash/hash.cpp8
-rw-r--r--src/lib/hash/keccak/info.txt4
-rw-r--r--src/lib/hash/keccak/keccak.cpp89
-rw-r--r--src/lib/hash/keccak/keccak.h5
-rw-r--r--src/lib/hash/sha3/info.txt1
-rw-r--r--src/lib/hash/sha3/sha3.cpp202
-rw-r--r--src/lib/hash/sha3/sha3.h97
-rw-r--r--src/lib/pubkey/newhope/info.txt9
-rw-r--r--src/lib/pubkey/newhope/newhope.cpp165
-rw-r--r--src/lib/pubkey/newhope/newhope.h33
-rw-r--r--src/lib/stream/salsa20/salsa20.cpp2
-rw-r--r--src/lib/stream/shake_cipher/info.txt1
-rw-r--r--src/lib/stream/shake_cipher/shake_cipher.cpp75
-rw-r--r--src/lib/stream/shake_cipher/shake_cipher.h64
-rw-r--r--src/lib/stream/stream_cipher.cpp8
15 files changed, 554 insertions, 209 deletions
diff --git a/src/lib/hash/hash.cpp b/src/lib/hash/hash.cpp
index 5a31763d1..016f60df1 100644
--- a/src/lib/hash/hash.cpp
+++ b/src/lib/hash/hash.cpp
@@ -53,6 +53,10 @@
#include <botan/sha2_64.h>
#endif
+#if defined(BOTAN_HAS_SHA3)
+ #include <botan/sha3.h>
+#endif
+
#if defined(BOTAN_HAS_SKEIN_512)
#include <botan/skein_512.h>
#endif
@@ -135,6 +139,10 @@ BOTAN_REGISTER_HASH_NAMED_NOARGS(GOST_34_11, "GOST-R-34.11-94");
BOTAN_REGISTER_HASH_NAMED_1LEN(Keccak_1600, "Keccak-1600", 512);
#endif
+#if defined(BOTAN_HAS_SHA3)
+BOTAN_REGISTER_HASH_NAMED_1LEN(SHA_3, "SHA-3", 512);
+#endif
+
#if defined(BOTAN_HAS_MD4)
BOTAN_REGISTER_HASH_NOARGS(MD4);
#endif
diff --git a/src/lib/hash/keccak/info.txt b/src/lib/hash/keccak/info.txt
index 6fcd286a3..712a99c76 100644
--- a/src/lib/hash/keccak/info.txt
+++ b/src/lib/hash/keccak/info.txt
@@ -1 +1,5 @@
define KECCAK 20131128
+
+<requires>
+sha3
+</requires>
diff --git a/src/lib/hash/keccak/keccak.cpp b/src/lib/hash/keccak/keccak.cpp
index e8bda068d..60cb20696 100644
--- a/src/lib/hash/keccak/keccak.cpp
+++ b/src/lib/hash/keccak/keccak.cpp
@@ -1,100 +1,17 @@
/*
* Keccak
-* (C) 2010 Jack Lloyd
+* (C) 2010,2016 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include <botan/keccak.h>
+#include <botan/sha3.h>
#include <botan/parsing.h>
#include <botan/exceptn.h>
namespace Botan {
-//static
-void Keccak_1600::permute(u64bit A[25])
- {
- static const u64bit RC[24] = {
- 0x0000000000000001, 0x0000000000008082, 0x800000000000808A,
- 0x8000000080008000, 0x000000000000808B, 0x0000000080000001,
- 0x8000000080008081, 0x8000000000008009, 0x000000000000008A,
- 0x0000000000000088, 0x0000000080008009, 0x000000008000000A,
- 0x000000008000808B, 0x800000000000008B, 0x8000000000008089,
- 0x8000000000008003, 0x8000000000008002, 0x8000000000000080,
- 0x000000000000800A, 0x800000008000000A, 0x8000000080008081,
- 0x8000000000008080, 0x0000000080000001, 0x8000000080008008
- };
-
- for(size_t i = 0; i != 24; ++i)
- {
- const u64bit C0 = A[0] ^ A[5] ^ A[10] ^ A[15] ^ A[20];
- const u64bit C1 = A[1] ^ A[6] ^ A[11] ^ A[16] ^ A[21];
- const u64bit C2 = A[2] ^ A[7] ^ A[12] ^ A[17] ^ A[22];
- const u64bit C3 = A[3] ^ A[8] ^ A[13] ^ A[18] ^ A[23];
- const u64bit C4 = A[4] ^ A[9] ^ A[14] ^ A[19] ^ A[24];
-
- const u64bit D0 = rotate_left(C0, 1) ^ C3;
- const u64bit D1 = rotate_left(C1, 1) ^ C4;
- const u64bit D2 = rotate_left(C2, 1) ^ C0;
- const u64bit D3 = rotate_left(C3, 1) ^ C1;
- const u64bit D4 = rotate_left(C4, 1) ^ C2;
-
- const u64bit B00 = A[ 0] ^ D1;
- const u64bit B10 = rotate_left(A[ 1] ^ D2, 1);
- const u64bit B20 = rotate_left(A[ 2] ^ D3, 62);
- const u64bit B05 = rotate_left(A[ 3] ^ D4, 28);
- const u64bit B15 = rotate_left(A[ 4] ^ D0, 27);
- const u64bit B16 = rotate_left(A[ 5] ^ D1, 36);
- const u64bit B01 = rotate_left(A[ 6] ^ D2, 44);
- const u64bit B11 = rotate_left(A[ 7] ^ D3, 6);
- const u64bit B21 = rotate_left(A[ 8] ^ D4, 55);
- const u64bit B06 = rotate_left(A[ 9] ^ D0, 20);
- const u64bit B07 = rotate_left(A[10] ^ D1, 3);
- const u64bit B17 = rotate_left(A[11] ^ D2, 10);
- const u64bit B02 = rotate_left(A[12] ^ D3, 43);
- const u64bit B12 = rotate_left(A[13] ^ D4, 25);
- const u64bit B22 = rotate_left(A[14] ^ D0, 39);
- const u64bit B23 = rotate_left(A[15] ^ D1, 41);
- const u64bit B08 = rotate_left(A[16] ^ D2, 45);
- const u64bit B18 = rotate_left(A[17] ^ D3, 15);
- const u64bit B03 = rotate_left(A[18] ^ D4, 21);
- const u64bit B13 = rotate_left(A[19] ^ D0, 8);
- const u64bit B14 = rotate_left(A[20] ^ D1, 18);
- const u64bit B24 = rotate_left(A[21] ^ D2, 2);
- const u64bit B09 = rotate_left(A[22] ^ D3, 61);
- const u64bit B19 = rotate_left(A[23] ^ D4, 56);
- const u64bit B04 = rotate_left(A[24] ^ D0, 14);
-
- A[ 0] = B00 ^ (~B01 & B02);
- A[ 1] = B01 ^ (~B02 & B03);
- A[ 2] = B02 ^ (~B03 & B04);
- A[ 3] = B03 ^ (~B04 & B00);
- A[ 4] = B04 ^ (~B00 & B01);
- A[ 5] = B05 ^ (~B06 & B07);
- A[ 6] = B06 ^ (~B07 & B08);
- A[ 7] = B07 ^ (~B08 & B09);
- A[ 8] = B08 ^ (~B09 & B05);
- A[ 9] = B09 ^ (~B05 & B06);
- A[10] = B10 ^ (~B11 & B12);
- A[11] = B11 ^ (~B12 & B13);
- A[12] = B12 ^ (~B13 & B14);
- A[13] = B13 ^ (~B14 & B10);
- A[14] = B14 ^ (~B10 & B11);
- A[15] = B15 ^ (~B16 & B17);
- A[16] = B16 ^ (~B17 & B18);
- A[17] = B17 ^ (~B18 & B19);
- A[18] = B18 ^ (~B19 & B15);
- A[19] = B19 ^ (~B15 & B16);
- A[20] = B20 ^ (~B21 & B22);
- A[21] = B21 ^ (~B22 & B23);
- A[22] = B22 ^ (~B23 & B24);
- A[23] = B23 ^ (~B24 & B20);
- A[24] = B24 ^ (~B20 & B21);
-
- A[0] ^= RC[i];
- }
- }
-
Keccak_1600::Keccak_1600(size_t output_bits) :
m_output_bits(output_bits),
m_bitrate(1600 - 2*output_bits),
@@ -164,7 +81,7 @@ void Keccak_1600::add_data(const byte input[], size_t length)
if(m_S_pos == m_bitrate / 8)
{
- Keccak_1600::permute(m_S.data());
+ SHA_3::permute(m_S.data());
m_S_pos = 0;
}
}
diff --git a/src/lib/hash/keccak/keccak.h b/src/lib/hash/keccak/keccak.h
index a66142d8c..ac50d4c52 100644
--- a/src/lib/hash/keccak/keccak.h
+++ b/src/lib/hash/keccak/keccak.h
@@ -34,11 +34,6 @@ class BOTAN_DLL Keccak_1600 final : public HashFunction
std::string name() const override;
void clear() override;
- /**
- * The bare Keccak-1600 permutation
- */
- static void permute(u64bit A[25]);
-
private:
void add_data(const byte input[], size_t length) override;
void final_result(byte out[]) override;
diff --git a/src/lib/hash/sha3/info.txt b/src/lib/hash/sha3/info.txt
new file mode 100644
index 000000000..f755e9ea5
--- /dev/null
+++ b/src/lib/hash/sha3/info.txt
@@ -0,0 +1 @@
+define SHA3 20161018
diff --git a/src/lib/hash/sha3/sha3.cpp b/src/lib/hash/sha3/sha3.cpp
new file mode 100644
index 000000000..3897f0588
--- /dev/null
+++ b/src/lib/hash/sha3/sha3.cpp
@@ -0,0 +1,202 @@
+/*
+* SHA-3
+* (C) 2010,2016 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/sha3.h>
+#include <botan/parsing.h>
+#include <botan/exceptn.h>
+
+namespace Botan {
+
+//static
+void SHA_3::permute(u64bit A[25])
+ {
+ static const u64bit RC[24] = {
+ 0x0000000000000001, 0x0000000000008082, 0x800000000000808A,
+ 0x8000000080008000, 0x000000000000808B, 0x0000000080000001,
+ 0x8000000080008081, 0x8000000000008009, 0x000000000000008A,
+ 0x0000000000000088, 0x0000000080008009, 0x000000008000000A,
+ 0x000000008000808B, 0x800000000000008B, 0x8000000000008089,
+ 0x8000000000008003, 0x8000000000008002, 0x8000000000000080,
+ 0x000000000000800A, 0x800000008000000A, 0x8000000080008081,
+ 0x8000000000008080, 0x0000000080000001, 0x8000000080008008
+ };
+
+ for(size_t i = 0; i != 24; ++i)
+ {
+ const u64bit C0 = A[0] ^ A[5] ^ A[10] ^ A[15] ^ A[20];
+ const u64bit C1 = A[1] ^ A[6] ^ A[11] ^ A[16] ^ A[21];
+ const u64bit C2 = A[2] ^ A[7] ^ A[12] ^ A[17] ^ A[22];
+ const u64bit C3 = A[3] ^ A[8] ^ A[13] ^ A[18] ^ A[23];
+ const u64bit C4 = A[4] ^ A[9] ^ A[14] ^ A[19] ^ A[24];
+
+ const u64bit D0 = rotate_left(C0, 1) ^ C3;
+ const u64bit D1 = rotate_left(C1, 1) ^ C4;
+ const u64bit D2 = rotate_left(C2, 1) ^ C0;
+ const u64bit D3 = rotate_left(C3, 1) ^ C1;
+ const u64bit D4 = rotate_left(C4, 1) ^ C2;
+
+ const u64bit B00 = A[ 0] ^ D1;
+ const u64bit B10 = rotate_left(A[ 1] ^ D2, 1);
+ const u64bit B20 = rotate_left(A[ 2] ^ D3, 62);
+ const u64bit B05 = rotate_left(A[ 3] ^ D4, 28);
+ const u64bit B15 = rotate_left(A[ 4] ^ D0, 27);
+ const u64bit B16 = rotate_left(A[ 5] ^ D1, 36);
+ const u64bit B01 = rotate_left(A[ 6] ^ D2, 44);
+ const u64bit B11 = rotate_left(A[ 7] ^ D3, 6);
+ const u64bit B21 = rotate_left(A[ 8] ^ D4, 55);
+ const u64bit B06 = rotate_left(A[ 9] ^ D0, 20);
+ const u64bit B07 = rotate_left(A[10] ^ D1, 3);
+ const u64bit B17 = rotate_left(A[11] ^ D2, 10);
+ const u64bit B02 = rotate_left(A[12] ^ D3, 43);
+ const u64bit B12 = rotate_left(A[13] ^ D4, 25);
+ const u64bit B22 = rotate_left(A[14] ^ D0, 39);
+ const u64bit B23 = rotate_left(A[15] ^ D1, 41);
+ const u64bit B08 = rotate_left(A[16] ^ D2, 45);
+ const u64bit B18 = rotate_left(A[17] ^ D3, 15);
+ const u64bit B03 = rotate_left(A[18] ^ D4, 21);
+ const u64bit B13 = rotate_left(A[19] ^ D0, 8);
+ const u64bit B14 = rotate_left(A[20] ^ D1, 18);
+ const u64bit B24 = rotate_left(A[21] ^ D2, 2);
+ const u64bit B09 = rotate_left(A[22] ^ D3, 61);
+ const u64bit B19 = rotate_left(A[23] ^ D4, 56);
+ const u64bit B04 = rotate_left(A[24] ^ D0, 14);
+
+ A[ 0] = B00 ^ (~B01 & B02);
+ A[ 1] = B01 ^ (~B02 & B03);
+ A[ 2] = B02 ^ (~B03 & B04);
+ A[ 3] = B03 ^ (~B04 & B00);
+ A[ 4] = B04 ^ (~B00 & B01);
+ A[ 5] = B05 ^ (~B06 & B07);
+ A[ 6] = B06 ^ (~B07 & B08);
+ A[ 7] = B07 ^ (~B08 & B09);
+ A[ 8] = B08 ^ (~B09 & B05);
+ A[ 9] = B09 ^ (~B05 & B06);
+ A[10] = B10 ^ (~B11 & B12);
+ A[11] = B11 ^ (~B12 & B13);
+ A[12] = B12 ^ (~B13 & B14);
+ A[13] = B13 ^ (~B14 & B10);
+ A[14] = B14 ^ (~B10 & B11);
+ A[15] = B15 ^ (~B16 & B17);
+ A[16] = B16 ^ (~B17 & B18);
+ A[17] = B17 ^ (~B18 & B19);
+ A[18] = B18 ^ (~B19 & B15);
+ A[19] = B19 ^ (~B15 & B16);
+ A[20] = B20 ^ (~B21 & B22);
+ A[21] = B21 ^ (~B22 & B23);
+ A[22] = B22 ^ (~B23 & B24);
+ A[23] = B23 ^ (~B24 & B20);
+ A[24] = B24 ^ (~B20 & B21);
+
+ A[0] ^= RC[i];
+ }
+ }
+
+SHA_3::SHA_3(size_t output_bits) :
+ m_output_bits(output_bits),
+ m_bitrate(1600 - 2*output_bits),
+ m_S(25),
+ m_S_pos(0)
+ {
+ // We only support the parameters for SHA-3 in this constructor
+
+ if(output_bits != 224 && output_bits != 256 &&
+ output_bits != 384 && output_bits != 512)
+ throw Invalid_Argument("SHA_3: Invalid output length " +
+ std::to_string(output_bits));
+ }
+
+SHA_3::SHA_3(size_t output_bits, size_t capacity) :
+ m_output_bits(output_bits),
+ m_bitrate(1600 - capacity),
+ m_S(25),
+ m_S_pos(0)
+ {
+ if(capacity == 0 || capacity >= 1600)
+ throw Invalid_Argument("Impossible SHA-3 capacity specified");
+ }
+
+std::string SHA_3::name() const
+ {
+ return "SHA-3(" + std::to_string(m_output_bits) + ")";
+ }
+
+HashFunction* SHA_3::clone() const
+ {
+ return new SHA_3(m_output_bits);
+ }
+
+void SHA_3::clear()
+ {
+ zeroise(m_S);
+ m_S_pos = 0;
+ }
+
+void SHA_3::add_data(const byte input[], size_t length)
+ {
+ if(length == 0)
+ return;
+
+ while(length)
+ {
+ size_t to_take = std::min(length, m_bitrate / 8 - m_S_pos);
+
+ length -= to_take;
+
+ while(to_take && m_S_pos % 8)
+ {
+ m_S[m_S_pos / 8] ^= static_cast<u64bit>(input[0]) << (8 * (m_S_pos % 8));
+
+ ++m_S_pos;
+ ++input;
+ --to_take;
+ }
+
+ while(to_take && to_take % 8 == 0)
+ {
+ m_S[m_S_pos / 8] ^= load_le<u64bit>(input, 0);
+ m_S_pos += 8;
+ input += 8;
+ to_take -= 8;
+ }
+
+ while(to_take)
+ {
+ m_S[m_S_pos / 8] ^= static_cast<u64bit>(input[0]) << (8 * (m_S_pos % 8));
+
+ ++m_S_pos;
+ ++input;
+ --to_take;
+ }
+
+ if(m_S_pos == m_bitrate / 8)
+ {
+ SHA_3::permute(m_S.data());
+ m_S_pos = 0;
+ }
+ }
+ }
+
+void SHA_3::final_result(byte output[])
+ {
+ std::vector<byte> padding(m_bitrate / 8 - m_S_pos);
+
+ padding[0] = 0x06;
+ padding[padding.size()-1] |= 0x80;
+
+ add_data(padding.data(), padding.size());
+
+ /*
+ * We never have to run the permutation again because we only support
+ * limited output lengths
+ */
+ for(size_t i = 0; i != m_output_bits/8; ++i)
+ output[i] = get_byte(7 - (i % 8), m_S[i/8]);
+
+ clear();
+ }
+
+}
diff --git a/src/lib/hash/sha3/sha3.h b/src/lib/hash/sha3/sha3.h
new file mode 100644
index 000000000..c877bd938
--- /dev/null
+++ b/src/lib/hash/sha3/sha3.h
@@ -0,0 +1,97 @@
+/*
+* SHA-3
+* (C) 2010,2016 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_SHA3_H__
+#define BOTAN_SHA3_H__
+
+#include <botan/hash.h>
+#include <botan/secmem.h>
+#include <string>
+
+namespace Botan {
+
+/**
+* SHA-3
+*/
+class BOTAN_DLL SHA_3 : public HashFunction
+ {
+ public:
+
+ /**
+ * @param output_bits the size of the hash output; must be one of
+ * 224, 256, 384, or 512
+ */
+ SHA_3(size_t output_bits);
+
+ /**
+ * @param output_bits the size of the hash output; must be a
+ * multiple of 8 (ie, byte-wide outputs)
+ * @param capacity the capacity of the spong, normally always
+ * 2*output_bits with SHA-3.
+ */
+ SHA_3(size_t output_bits, size_t capacity);
+
+ size_t hash_block_size() const override { return m_bitrate / 8; }
+ size_t output_length() const override { return m_output_bits / 8; }
+
+ HashFunction* clone() const override;
+ std::string name() const override;
+ void clear() override;
+
+ /**
+ * The bare Keccak-1600 permutation
+ */
+ static void permute(u64bit A[25]);
+
+ private:
+ void add_data(const byte input[], size_t length) override;
+ void final_result(byte out[]) override;
+
+ size_t m_output_bits, m_bitrate;
+ secure_vector<u64bit> m_S;
+ size_t m_S_pos;
+ };
+
+/**
+* SHA-3-224
+*/
+class BOTAN_DLL SHA_3_224 final : public SHA_3
+ {
+ public:
+ SHA_3_224() : SHA_3(224) {}
+ };
+
+/**
+* SHA-3-256
+*/
+class BOTAN_DLL SHA_3_256 final : public SHA_3
+ {
+ public:
+ SHA_3_256() : SHA_3(256) {}
+ };
+
+/**
+* SHA-3-384
+*/
+class BOTAN_DLL SHA_3_384 final : public SHA_3
+ {
+ public:
+ SHA_3_384() : SHA_3(384) {}
+ };
+
+/**
+* SHA-3-512
+*/
+class BOTAN_DLL SHA_3_512 final : public SHA_3
+ {
+ public:
+ SHA_3_512() : SHA_3(512) {}
+ };
+
+}
+
+#endif
diff --git a/src/lib/pubkey/newhope/info.txt b/src/lib/pubkey/newhope/info.txt
index 8019b6a7c..74ceef989 100644
--- a/src/lib/pubkey/newhope/info.txt
+++ b/src/lib/pubkey/newhope/info.txt
@@ -1,5 +1,10 @@
-define NEWHOPE 20160829
+define NEWHOPE 20161018
<requires>
-keccak
+sha3
+shake_cipher
+
+sha2_32
+ctr
+aes
</requires>
diff --git a/src/lib/pubkey/newhope/newhope.cpp b/src/lib/pubkey/newhope/newhope.cpp
index 8436457b4..35645e93c 100644
--- a/src/lib/pubkey/newhope/newhope.cpp
+++ b/src/lib/pubkey/newhope/newhope.cpp
@@ -10,7 +10,8 @@
*/
#include <botan/newhope.h>
-#include <botan/keccak.h>
+#include <botan/hash.h>
+#include <botan/stream_cipher.h>
#include <botan/loadstor.h>
namespace Botan {
@@ -24,8 +25,6 @@ typedef newhope_poly poly;
#define NEWHOPE_POLY_BYTES 1792
#define NEWHOPE_SEED_BYTES 32
-#define SHAKE128_RATE 168
-
namespace {
/* Incomplete-reduction routines; for details on allowed input ranges
@@ -422,121 +421,57 @@ inline void rec(uint8_t *key, const poly *v, const poly *c)
}
}
-/* Based on the public domain implementation in
- * crypto_hash/keccakc512/simple/ from http://bench.cr.yp.to/supercop.html
- * by Ronny Van Keer
- * and the public domain "TweetFips202" implementation
- * from https://twitter.com/tweetfips202
- * by Gilles Van Assche, Daniel J. Bernstein, and Peter Schwabe */
-
-void keccak_absorb(uint64_t *s,
- unsigned int r,
- const uint8_t *m, size_t mlen,
- uint8_t p)
-{
- size_t i;
- uint8_t t[200];
-
- for (i = 0; i < 25; ++i)
- s[i] = 0;
-
- while (mlen >= r)
- {
- for (i = 0; i < r / 8; ++i)
- s[i] ^= load_le<u64bit>(m, i);
-
- Keccak_1600::permute(s);
- mlen -= r;
- m += r;
- }
-
- for (i = 0; i < r; ++i)
- t[i] = 0;
- for (i = 0; i < mlen; ++i)
- t[i] = m[i];
- t[i] = p;
- t[r - 1] |= 128;
- for (i = 0; i < r / 8; ++i)
- s[i] ^= load_le<u64bit>(t, i);
-}
-
-inline void keccak_squeezeblocks(uint8_t *h, size_t nblocks,
- uint64_t *s, unsigned int r)
-{
- while(nblocks > 0)
- {
- Keccak_1600::permute(s);
+void gen_a(poly *a, const uint8_t *seed, Newhope_Mode mode)
+ {
+ std::vector<uint8_t> buf(168*16);
- copy_out_le(h, r, s);
+ std::unique_ptr<StreamCipher> xof;
- h += r;
- nblocks--;
- }
-}
-
-inline void shake128_absorb(uint64_t *s, const uint8_t *input, size_t inputByteLen)
-{
- keccak_absorb(s, SHAKE128_RATE, input, inputByteLen, 0x1F);
-}
-
-inline void shake128_squeezeblocks(uint8_t *output, size_t nblocks, uint64_t *s)
-{
- keccak_squeezeblocks(output, nblocks, s, SHAKE128_RATE);
-}
-
-void gen_a(poly *a, const uint8_t *seed)
-{
- unsigned int pos=0, ctr=0;
- uint16_t val;
- uint64_t state[25];
- unsigned int nblocks=16;
- uint8_t buf[SHAKE128_RATE*16];
+ if(mode == Newhope_Mode::BoringSSL)
+ {
+ xof = StreamCipher::create("CTR(AES-128)");
+ xof->set_key(seed, 16);
+ xof->set_iv(seed + 16, 16);
+ }
+ else
+ {
+ xof = StreamCipher::create("SHAKE-128");
+ xof->set_key(seed, NEWHOPE_SEED_BYTES);
+ }
- shake128_absorb(state, seed, NEWHOPE_SEED_BYTES);
+ zeroise(buf);
+ xof->encrypt(buf);
- shake128_squeezeblocks((uint8_t *) buf, nblocks, state);
+ unsigned int pos=0, ctr=0;
- while(ctr < PARAM_N)
- {
- val = (buf[pos] | ((uint16_t) buf[pos+1] << 8)) & 0x3fff; // Specialized for q = 12889
- if(val < PARAM_Q)
- a->coeffs[ctr++] = val;
- pos += 2;
- if(pos > SHAKE128_RATE*nblocks-2)
- {
- nblocks=1;
- shake128_squeezeblocks((uint8_t *) buf,nblocks,state);
- pos = 0;
- }
- }
-}
+ while(ctr < PARAM_N)
+ {
+ uint16_t val = (buf[pos] | ((uint16_t) buf[pos+1] << 8)) & 0x3fff; // Specialized for q = 12889
+ if(val < PARAM_Q)
+ a->coeffs[ctr++] = val;
+ pos += 2;
+ if(pos >= buf.size())
+ {
+ zeroise(buf);
+ xof->encrypt(buf);
+ pos = 0;
+ }
+ }
+ }
}
// API FUNCTIONS
-void newhope_hash(uint8_t *output, const uint8_t *input, size_t inputByteLen)
-{
-const size_t SHA3_256_RATE = 136;
-
- uint64_t s[25];
- uint8_t t[SHA3_256_RATE];
- int i;
-
- keccak_absorb(s, SHA3_256_RATE, input, inputByteLen, 0x06);
- keccak_squeezeblocks(t, 1, s, SHA3_256_RATE);
- for(i=0;i<32;i++)
- output[i] = t[i];
-}
-
-void newhope_keygen(uint8_t *send, poly *sk, RandomNumberGenerator& rng)
+void newhope_keygen(uint8_t *send, poly *sk, RandomNumberGenerator& rng,
+ Newhope_Mode mode)
{
poly a, e, r, pk;
uint8_t seed[NEWHOPE_SEED_BYTES];
rng.randomize(seed, NEWHOPE_SEED_BYTES);
- gen_a(&a, seed);
+ gen_a(&a, seed, mode);
poly_getnoise(rng, sk);
poly_ntt(sk);
@@ -551,13 +486,14 @@ void newhope_keygen(uint8_t *send, poly *sk, RandomNumberGenerator& rng)
}
void newhope_sharedb(uint8_t *sharedkey, uint8_t *send, const uint8_t *received,
- RandomNumberGenerator& rng)
+ RandomNumberGenerator& rng,
+ Newhope_Mode mode)
{
poly sp, ep, v, a, pka, c, epp, bp;
uint8_t seed[NEWHOPE_SEED_BYTES];
decode_a(&pka, seed, received);
- gen_a(&a, seed);
+ gen_a(&a, seed, mode);
poly_getnoise(rng, &sp);
poly_ntt(&sp);
@@ -579,11 +515,19 @@ void newhope_sharedb(uint8_t *sharedkey, uint8_t *send, const uint8_t *received,
rec(sharedkey, &v, &c);
- newhope_hash(sharedkey, sharedkey, 32);
+ std::unique_ptr<HashFunction> hash(HashFunction::create(
+ (mode == Newhope_Mode::SHA3) ? "SHA-3(256)" : "SHA-256"));
+
+ if(!hash)
+ throw Exception("NewHope hash function not available");
+
+ hash->update(sharedkey, 32);
+ hash->final(sharedkey);
}
-void newhope_shareda(uint8_t *sharedkey, const poly *sk, const uint8_t *received)
+void newhope_shareda(uint8_t *sharedkey, const poly *sk, const uint8_t *received,
+ Newhope_Mode mode)
{
poly v,bp, c;
@@ -594,7 +538,14 @@ void newhope_shareda(uint8_t *sharedkey, const poly *sk, const uint8_t *received
rec(sharedkey, &v, &c);
- newhope_hash(sharedkey, sharedkey, 32);
+ std::unique_ptr<HashFunction> hash(HashFunction::create(
+ (mode == Newhope_Mode::SHA3) ? "SHA-3(256)" : "SHA-256"));
+
+ if(!hash)
+ throw Exception("NewHope hash function not available");
+
+ hash->update(sharedkey, 32);
+ hash->final(sharedkey);
}
}
diff --git a/src/lib/pubkey/newhope/newhope.h b/src/lib/pubkey/newhope/newhope.h
index 794f0750f..667f1c4cf 100644
--- a/src/lib/pubkey/newhope/newhope.h
+++ b/src/lib/pubkey/newhope/newhope.h
@@ -28,16 +28,33 @@ typedef struct {
uint16_t coeffs[1024];
} newhope_poly;
-void BOTAN_DLL newhope_keygen(uint8_t *send, newhope_poly *sk, RandomNumberGenerator& rng);
-void BOTAN_DLL newhope_sharedb(uint8_t *sharedkey, uint8_t *send, const uint8_t *received, RandomNumberGenerator& rng);
-void BOTAN_DLL newhope_shareda(uint8_t *sharedkey, const newhope_poly *ska, const uint8_t *received);
+/**
+* This chooses the XOF + hash for NewHope
-
-/*
-* This is just exposed for testing
+* The official NewHope specification and reference implementation use
+* SHA-3 and SHAKE-128. BoringSSL instead uses SHA-256 and AES-128 in
+* CTR mode.
*/
-void BOTAN_DLL newhope_hash(uint8_t *output, const uint8_t *input, size_t inputByteLen);
-
+enum class Newhope_Mode {
+ SHA3,
+ BoringSSL
+};
+
+void BOTAN_DLL newhope_keygen(uint8_t *send,
+ newhope_poly *sk,
+ RandomNumberGenerator& rng,
+ Newhope_Mode = Newhope_Mode::SHA3);
+
+void BOTAN_DLL newhope_sharedb(uint8_t *sharedkey,
+ uint8_t *send,
+ const uint8_t *received,
+ RandomNumberGenerator& rng,
+ Newhope_Mode mode = Newhope_Mode::SHA3);
+
+void BOTAN_DLL newhope_shareda(uint8_t *sharedkey,
+ const newhope_poly *ska,
+ const uint8_t *received,
+ Newhope_Mode mode = Newhope_Mode::SHA3);
}
diff --git a/src/lib/stream/salsa20/salsa20.cpp b/src/lib/stream/salsa20/salsa20.cpp
index f11fe5e59..0d8942789 100644
--- a/src/lib/stream/salsa20/salsa20.cpp
+++ b/src/lib/stream/salsa20/salsa20.cpp
@@ -163,7 +163,7 @@ void Salsa20::key_schedule(const byte key[], size_t length)
}
/*
-* Return the name of this type
+* Set the Salsa IV
*/
void Salsa20::set_iv(const byte iv[], size_t length)
{
diff --git a/src/lib/stream/shake_cipher/info.txt b/src/lib/stream/shake_cipher/info.txt
new file mode 100644
index 000000000..53e6f5012
--- /dev/null
+++ b/src/lib/stream/shake_cipher/info.txt
@@ -0,0 +1 @@
+define SHAKE_CIPHER 20161018
diff --git a/src/lib/stream/shake_cipher/shake_cipher.cpp b/src/lib/stream/shake_cipher/shake_cipher.cpp
new file mode 100644
index 000000000..5701e7802
--- /dev/null
+++ b/src/lib/stream/shake_cipher/shake_cipher.cpp
@@ -0,0 +1,75 @@
+/*
+* SHAKE-128
+* (C) 2016 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/shake_cipher.h>
+#include <botan/sha3.h>
+#include <botan/loadstor.h>
+
+namespace Botan {
+
+SHAKE_128::SHAKE_128() :
+ m_state(25),
+ m_buffer((1600 - 256) / 8),
+ m_buf_pos(0)
+ {}
+
+void SHAKE_128::cipher(const byte in[], byte 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);
+
+ SHA_3::permute(m_state.data());
+ copy_out_le(m_buffer.data(), m_buffer.size(), m_state.data());
+
+ m_buf_pos = 0;
+ }
+ xor_buf(out, in, &m_buffer[m_buf_pos], length);
+ m_buf_pos += length;
+ }
+
+void SHAKE_128::key_schedule(const byte key[], size_t length)
+ {
+ zeroise(m_state);
+
+ for(size_t i = 0; i < length/8; ++i)
+ {
+ m_state[i] ^= load_le<uint64_t>(key, i);
+ }
+
+ m_state[length/8] ^= 0x000000000000001F;
+ m_state[20] ^= 0x8000000000000000;
+
+ SHA_3::permute(m_state.data());
+ copy_out_le(m_buffer.data(), m_buffer.size(), m_state.data());
+ }
+
+void SHAKE_128::clear()
+ {
+ zeroise(m_state);
+ zeroise(m_buffer);
+ m_buf_pos = 0;
+ }
+
+void SHAKE_128::set_iv(const byte[], 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::seek(u64bit)
+ {
+ throw Not_Implemented("SHAKE_128::seek");
+ }
+}
diff --git a/src/lib/stream/shake_cipher/shake_cipher.h b/src/lib/stream/shake_cipher/shake_cipher.h
new file mode 100644
index 000000000..57eda58a4
--- /dev/null
+++ b/src/lib/stream/shake_cipher/shake_cipher.h
@@ -0,0 +1,64 @@
+/*
+* 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>
+
+namespace Botan {
+
+/**
+* SHAKE-128 XOF presented as a stream cipher
+*/
+class BOTAN_DLL SHAKE_128 final : public StreamCipher
+ {
+ public:
+ SHAKE_128();
+
+ /**
+ * Produce more XOF output
+ */
+ void cipher(const byte in[], byte out[], size_t length) override;
+
+ /**
+ * Seeking is not supported, this function will throw
+ */
+ void seek(u64bit offset) override;
+
+ /**
+ * IV not supported, this function will throw unless iv_len == 0
+ */
+ void set_iv(const byte iv[], size_t iv_len) override;
+
+ bool valid_iv_length(size_t iv_len) const override { return (iv_len == 0); }
+
+ /**
+ * In principle SHAKE can accept arbitrary length inputs, but this
+ * does not seem required for a stream cipher.
+ */
+ Key_Length_Specification key_spec() const override
+ {
+ return Key_Length_Specification(16, 160, 8);
+ }
+
+ void clear() override;
+ std::string name() const override { return "SHAKE-128"; }
+ StreamCipher* clone() const override { return new SHAKE_128; }
+
+ private:
+ void key_schedule(const byte key[], size_t key_len) override;
+
+ secure_vector<uint64_t> m_state; // internal state
+ secure_vector<byte> m_buffer; // ciphertext buffer
+ size_t m_buf_pos; // position in m_buffer
+ };
+
+}
+
+#endif
diff --git a/src/lib/stream/stream_cipher.cpp b/src/lib/stream/stream_cipher.cpp
index cd6400d8f..7c41722a0 100644
--- a/src/lib/stream/stream_cipher.cpp
+++ b/src/lib/stream/stream_cipher.cpp
@@ -16,6 +16,10 @@
#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
@@ -52,6 +56,10 @@ BOTAN_REGISTER_T_1LEN(StreamCipher, ChaCha, 20);
BOTAN_REGISTER_T_NOARGS(StreamCipher, Salsa20);
#endif
+#if defined(BOTAN_HAS_SHAKE_CIPHER)
+BOTAN_REGISTER_NAMED_T(StreamCipher, "SHAKE-128", SHAKE_128, make_new_T<SHAKE_128>);
+#endif
+
#if defined(BOTAN_HAS_CTR_BE)
BOTAN_REGISTER_NAMED_T(StreamCipher, "CTR-BE", CTR_BE, CTR_BE::make);
#endif