aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/todo.rst1
-rw-r--r--src/lib/stream/chacha/chacha.cpp25
-rw-r--r--src/lib/stream/chacha/chacha.h15
-rw-r--r--src/lib/stream/stream_cipher.cpp2
-rw-r--r--src/tests/data/stream/chacha.vec17
5 files changed, 49 insertions, 11 deletions
diff --git a/doc/todo.rst b/doc/todo.rst
index 437501c02..52ee5c4a2 100644
--- a/doc/todo.rst
+++ b/doc/todo.rst
@@ -73,7 +73,6 @@ Symmetric Algorithms, Hashes, ...
* Serpent using AVX2
* Serpent using SSSE3 pshufb for sboxes
* ChaCha20 using SSE2 or AVX2
-* Modify ChaCha to support 12 or 20 rounds
* scrypt
* Argon2 (draft-irtf-cfrg-argon2)
* bcrypt PBKDF
diff --git a/src/lib/stream/chacha/chacha.cpp b/src/lib/stream/chacha/chacha.cpp
index 0a32c720b..ac81fd70d 100644
--- a/src/lib/stream/chacha/chacha.cpp
+++ b/src/lib/stream/chacha/chacha.cpp
@@ -10,8 +10,18 @@
namespace Botan {
-void ChaCha::chacha(byte output[64], const u32bit input[16])
+ChaCha::ChaCha(size_t rounds) : m_rounds(rounds)
{
+ if(m_rounds != 12 && m_rounds != 20)
+ throw Invalid_Argument("ChaCha only supports 12 or 20 rounds");
+ }
+
+namespace {
+
+void chacha(byte output[64], const u32bit input[16], size_t rounds)
+ {
+ BOTAN_ASSERT(rounds % 2 == 0, "Valid rounds");
+
u32bit 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],
@@ -25,7 +35,7 @@ void ChaCha::chacha(byte output[64], const u32bit input[16])
c += d; b ^= c; b = rotate_left(b, 7); \
} while(0)
- for(size_t i = 0; i != 10; ++i)
+ for(size_t i = 0; i != rounds / 2; ++i)
{
CHACHA_QUARTER_ROUND(x00, x04, x08, x12);
CHACHA_QUARTER_ROUND(x01, x05, x09, x13);
@@ -58,6 +68,8 @@ void ChaCha::chacha(byte output[64], const u32bit input[16])
store_le(x15 + input[15], output + 4 * 15);
}
+}
+
/*
* Combine cipher stream with message
*/
@@ -69,7 +81,7 @@ void ChaCha::cipher(const byte in[], byte out[], size_t length)
length -= (m_buffer.size() - m_position);
in += (m_buffer.size() - m_position);
out += (m_buffer.size() - m_position);
- chacha(m_buffer.data(), m_state.data());
+ chacha(m_buffer.data(), m_state.data(), m_rounds);
++m_state[12];
m_state[13] += (m_state[12] == 0);
@@ -142,7 +154,7 @@ void ChaCha::set_iv(const byte iv[], size_t length)
m_state[15] = load_le<u32bit>(iv, 2);
}
- chacha(m_buffer.data(), m_state.data());
+ chacha(m_buffer.data(), m_state.data(), m_rounds);
++m_state[12];
m_state[13] += (m_state[12] == 0);
@@ -156,4 +168,9 @@ void ChaCha::clear()
m_position = 0;
}
+std::string ChaCha::name() const
+ {
+ return "ChaCha(" + std::to_string(m_rounds) + ")";
+ }
+
}
diff --git a/src/lib/stream/chacha/chacha.h b/src/lib/stream/chacha/chacha.h
index 92f8ef035..ba93d6260 100644
--- a/src/lib/stream/chacha/chacha.h
+++ b/src/lib/stream/chacha/chacha.h
@@ -18,6 +18,14 @@ namespace Botan {
class BOTAN_DLL ChaCha final : public StreamCipher
{
public:
+ StreamCipher* clone() const override { return new ChaCha(m_rounds); }
+
+ /**
+ * Currently only 12 or 20 rounds are supported, all others
+ * will throw an exception
+ */
+ ChaCha(size_t rounds);
+
void cipher(const byte in[], byte out[], size_t length) override;
void set_iv(const byte iv[], size_t iv_len) override;
@@ -31,14 +39,13 @@ class BOTAN_DLL ChaCha final : public StreamCipher
}
void clear() override;
- std::string name() const override { return "ChaCha"; }
- StreamCipher* clone() const override { return new ChaCha; }
- protected:
- virtual void chacha(byte output[64], const u32bit input[16]);
+ std::string name() const override;
+
private:
void key_schedule(const byte key[], size_t key_len) override;
+ size_t m_rounds;
secure_vector<u32bit> m_state;
secure_vector<byte> m_buffer;
size_t m_position = 0;
diff --git a/src/lib/stream/stream_cipher.cpp b/src/lib/stream/stream_cipher.cpp
index 03ef5e329..6f98df1fb 100644
--- a/src/lib/stream/stream_cipher.cpp
+++ b/src/lib/stream/stream_cipher.cpp
@@ -51,7 +51,7 @@ void StreamCipher::set_iv(const byte[], size_t iv_len)
}
#if defined(BOTAN_HAS_CHACHA)
-BOTAN_REGISTER_T_NOARGS(StreamCipher, ChaCha);
+BOTAN_REGISTER_T_1LEN(StreamCipher, ChaCha, 20);
#endif
#if defined(BOTAN_HAS_SALSA20)
diff --git a/src/tests/data/stream/chacha.vec b/src/tests/data/stream/chacha.vec
index e4386cbd5..1c3c18c7c 100644
--- a/src/tests/data/stream/chacha.vec
+++ b/src/tests/data/stream/chacha.vec
@@ -1,5 +1,20 @@
-[ChaCha]
+[ChaCha(12)]
+
+# ChaCha(12) test vectors from
+# https://github.com/Yawning/sphincs256/blob/master/chacha/chacha_test.go
+
+Key = 80000000000000000000000000000000
+Nonce = 0000000000000000
+In = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+Out = 36CF0D56E9F7FBF287BC5460D95FBA94AA6CBF17D74E7C784DDCF7E0E882DDAE3B5A58243EF32B79A04575A8E2C2B73DC64A52AA15B9F88305A8F0CA0B5A1A25
+
+Key = 0F62B5085BAE0154A7FA4DA0F34699EC3F92E5388BDE3184D72A7DD02376C91C
+Nonce = 288FF65DC42B92F9
+In = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+Out = 49FD8FBF19EDCF3A198F5226AA480B97D9F16BA71A693C4ECB90C276094585DFA4FA259E1EC34DE444C92879BFE7F641EEAC480168DC8969A9C033151B1E9229
+
+[ChaCha(20)]
Key = 00000000000000000000000000000000
Nonce = 0000000000000000
In = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000