aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/stream
diff options
context:
space:
mode:
authorlloyd <lloyd@randombit.net>2014-01-31 22:30:50 +0000
committerlloyd <lloyd@randombit.net>2014-01-31 22:30:50 +0000
commite11024f26113189f45ca1759f6a045ca6989849e (patch)
tree33ea9eb4c4faabc899fa03aff5132e00a21f5d84 /src/lib/stream
parent9332870c160d7a02f1bef6f249fa1baae196dc51 (diff)
Add ChaCha
Diffstat (limited to 'src/lib/stream')
-rw-r--r--src/lib/stream/chacha/chacha.cpp166
-rw-r--r--src/lib/stream/chacha/chacha.h49
-rw-r--r--src/lib/stream/chacha/info.txt3
-rw-r--r--src/lib/stream/salsa20/salsa20.cpp138
-rw-r--r--src/lib/stream/salsa20/salsa20.h6
5 files changed, 285 insertions, 77 deletions
diff --git a/src/lib/stream/chacha/chacha.cpp b/src/lib/stream/chacha/chacha.cpp
new file mode 100644
index 000000000..33db7ac92
--- /dev/null
+++ b/src/lib/stream/chacha/chacha.cpp
@@ -0,0 +1,166 @@
+/*
+* ChaCha
+* (C) 2014 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/chacha.h>
+#include <botan/loadstor.h>
+#include <botan/rotate.h>
+#include <botan/internal/xor_buf.h>
+
+namespace Botan {
+
+void ChaCha::chacha(byte output[64], const u32bit input[16])
+ {
+ 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],
+ x12 = input[12], x13 = input[13], x14 = input[14], x15 = input[15];
+
+#define CHACHA_QUARTER_ROUND(a, b, c, d) \
+ do { \
+ a += b; d ^= a; d = rotate_left(d, 16); \
+ c += d; b ^= c; b = rotate_left(b, 12); \
+ a += b; d ^= a; d = rotate_left(d, 8); \
+ c += d; b ^= c; b = rotate_left(b, 7); \
+ } while(0)
+
+ for(size_t i = 0; i != 10; ++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);
+ }
+
+#undef CHACHA_QUARTER_ROUND
+
+ 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);
+ }
+
+/*
+* Combine cipher stream with message
+*/
+void ChaCha::cipher(const byte in[], byte out[], size_t length)
+ {
+ 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);
+ chacha(&m_buffer[0], &m_state[0]);
+
+ ++m_state[12];
+ m_state[13] += (m_state[12] == 0);
+
+ m_position = 0;
+ }
+
+ xor_buf(out, in, &m_buffer[m_position], length);
+
+ m_position += length;
+ }
+
+/*
+* ChaCha Key Schedule
+*/
+void ChaCha::key_schedule(const byte key[], size_t length)
+ {
+ static const u32bit TAU[] =
+ { 0x61707865, 0x3120646e, 0x79622d36, 0x6b206574 };
+
+ static const u32bit SIGMA[] =
+ { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 };
+
+ const u32bit* CONSTANTS = (length == 16) ? TAU : SIGMA;
+
+ m_state.resize(16);
+ m_buffer.resize(64);
+
+ m_state[0] = CONSTANTS[0];
+ m_state[1] = CONSTANTS[1];
+ m_state[2] = CONSTANTS[2];
+ m_state[3] = CONSTANTS[3];
+
+ m_state[4] = load_le<u32bit>(key, 0);
+ m_state[5] = load_le<u32bit>(key, 1);
+ m_state[6] = load_le<u32bit>(key, 2);
+ m_state[7] = load_le<u32bit>(key, 3);
+
+ if(length == 32)
+ key += 16;
+
+ m_state[8] = load_le<u32bit>(key, 0);
+ m_state[9] = load_le<u32bit>(key, 1);
+ m_state[10] = load_le<u32bit>(key, 2);
+ m_state[11] = load_le<u32bit>(key, 3);
+
+ m_position = 0;
+
+ const byte ZERO[8] = { 0 };
+ set_iv(ZERO, sizeof(ZERO));
+ }
+
+/*
+* Return the name of this type
+*/
+void ChaCha::set_iv(const byte iv[], size_t length)
+ {
+ if(!valid_iv_length(length))
+ throw Invalid_IV_Length(name(), length);
+
+ m_state[12] = 0;
+ m_state[13] = 0;
+
+ m_state[14] = load_le<u32bit>(iv, 0);
+ m_state[15] = load_le<u32bit>(iv, 1);
+
+ chacha(&m_buffer[0], &m_state[0]);
+ ++m_state[12];
+ m_state[13] += (m_state[12] == 0);
+
+ m_position = 0;
+ }
+
+/*
+* Return the name of this type
+*/
+std::string ChaCha::name() const
+ {
+ return "ChaCha";
+ }
+
+/*
+* Clear memory of sensitive data
+*/
+void ChaCha::clear()
+ {
+ zap(m_state);
+ zap(m_buffer);
+ m_position = 0;
+ }
+
+}
diff --git a/src/lib/stream/chacha/chacha.h b/src/lib/stream/chacha/chacha.h
new file mode 100644
index 000000000..b7d720685
--- /dev/null
+++ b/src/lib/stream/chacha/chacha.h
@@ -0,0 +1,49 @@
+/*
+* ChaCha20
+* (C) 2014 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_CHACHA_H__
+#define BOTAN_CHACHA_H__
+
+#include <botan/stream_cipher.h>
+
+namespace Botan {
+
+/**
+* DJB's ChaCha (http://cr.yp.to/chacha.html)
+*/
+class BOTAN_DLL ChaCha : public StreamCipher
+ {
+ public:
+ void cipher(const byte in[], byte out[], size_t length);
+
+ void set_iv(const byte iv[], size_t iv_len);
+
+ bool valid_iv_length(size_t iv_len) const
+ { return (iv_len == 8); }
+
+ Key_Length_Specification key_spec() const
+ {
+ return Key_Length_Specification(16, 32, 16);
+ }
+
+ void clear();
+ std::string name() const;
+
+ StreamCipher* clone() const { return new ChaCha; }
+ protected:
+ virtual void chacha(byte output[64], const u32bit input[16]);
+ private:
+ void key_schedule(const byte key[], size_t key_len);
+
+ secure_vector<u32bit> m_state;
+ secure_vector<byte> m_buffer;
+ size_t m_position = 0;
+ };
+
+}
+
+#endif
diff --git a/src/lib/stream/chacha/info.txt b/src/lib/stream/chacha/info.txt
new file mode 100644
index 000000000..666f14d53
--- /dev/null
+++ b/src/lib/stream/chacha/info.txt
@@ -0,0 +1,3 @@
+define CHACHA 20140103
+
+load_on auto
diff --git a/src/lib/stream/salsa20/salsa20.cpp b/src/lib/stream/salsa20/salsa20.cpp
index d8db69ae6..79426f0de 100644
--- a/src/lib/stream/salsa20/salsa20.cpp
+++ b/src/lib/stream/salsa20/salsa20.cpp
@@ -1,6 +1,6 @@
/*
* Salsa20 / XSalsa20
-* (C) 1999-2010 Jack Lloyd
+* (C) 1999-2010,2014 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/
@@ -9,6 +9,7 @@
#include <botan/loadstor.h>
#include <botan/rotate.h>
#include <botan/internal/xor_buf.h>
+#include <botan/internal/simd_32.h>
namespace Botan {
@@ -98,29 +99,30 @@ void salsa20(byte output[64], const u32bit input[16])
}
+#undef SALSA20_QUARTER_ROUND
+
/*
* Combine cipher stream with message
*/
void Salsa20::cipher(const byte in[], byte out[], size_t length)
{
- while(length >= buffer.size() - position)
+ while(length >= m_buffer.size() - m_position)
{
- xor_buf(out, in, &buffer[position], buffer.size() - position);
- length -= (buffer.size() - position);
- in += (buffer.size() - position);
- out += (buffer.size() - position);
- salsa20(&buffer[0], &state[0]);
+ 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);
+ salsa20(&m_buffer[0], &m_state[0]);
- ++state[8];
- if(!state[8]) // if overflow in state[8]
- ++state[9]; // carry to state[9]
+ ++m_state[8];
+ m_state[9] += (m_state[8] == 0);
- position = 0;
+ m_position = 0;
}
- xor_buf(out, in, &buffer[position], length);
+ xor_buf(out, in, &m_buffer[m_position], length);
- position += length;
+ m_position += length;
}
/*
@@ -134,41 +136,30 @@ void Salsa20::key_schedule(const byte key[], size_t length)
static const u32bit SIGMA[] =
{ 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 };
- state.resize(16);
- buffer.resize(64);
+ const u32bit* CONSTANTS = (length == 16) ? TAU : SIGMA;
- if(length == 16)
- {
- state[0] = TAU[0];
- state[1] = load_le<u32bit>(key, 0);
- state[2] = load_le<u32bit>(key, 1);
- state[3] = load_le<u32bit>(key, 2);
- state[4] = load_le<u32bit>(key, 3);
- state[5] = TAU[1];
- state[10] = TAU[2];
- state[11] = load_le<u32bit>(key, 0);
- state[12] = load_le<u32bit>(key, 1);
- state[13] = load_le<u32bit>(key, 2);
- state[14] = load_le<u32bit>(key, 3);
- state[15] = TAU[3];
- }
- else if(length == 32)
- {
- state[0] = SIGMA[0];
- state[1] = load_le<u32bit>(key, 0);
- state[2] = load_le<u32bit>(key, 1);
- state[3] = load_le<u32bit>(key, 2);
- state[4] = load_le<u32bit>(key, 3);
- state[5] = SIGMA[1];
- state[10] = SIGMA[2];
- state[11] = load_le<u32bit>(key, 4);
- state[12] = load_le<u32bit>(key, 5);
- state[13] = load_le<u32bit>(key, 6);
- state[14] = load_le<u32bit>(key, 7);
- state[15] = SIGMA[3];
- }
+ m_state.resize(16);
+ m_buffer.resize(64);
+
+ m_state[0] = CONSTANTS[0];
+ m_state[5] = CONSTANTS[1];
+ m_state[10] = CONSTANTS[2];
+ m_state[15] = CONSTANTS[3];
+
+ m_state[1] = load_le<u32bit>(key, 0);
+ m_state[2] = load_le<u32bit>(key, 1);
+ m_state[3] = load_le<u32bit>(key, 2);
+ m_state[4] = load_le<u32bit>(key, 3);
+
+ if(length == 32)
+ key += 16;
+
+ m_state[11] = load_le<u32bit>(key, 0);
+ m_state[12] = load_le<u32bit>(key, 1);
+ m_state[13] = load_le<u32bit>(key, 2);
+ m_state[14] = load_le<u32bit>(key, 3);
- position = 0;
+ m_position = 0;
const byte ZERO[8] = { 0 };
set_iv(ZERO, sizeof(ZERO));
@@ -185,41 +176,40 @@ void Salsa20::set_iv(const byte iv[], size_t length)
if(length == 8)
{
// Salsa20
- state[6] = load_le<u32bit>(iv, 0);
- state[7] = load_le<u32bit>(iv, 1);
+ m_state[6] = load_le<u32bit>(iv, 0);
+ m_state[7] = load_le<u32bit>(iv, 1);
}
else
{
// XSalsa20
- state[6] = load_le<u32bit>(iv, 0);
- state[7] = load_le<u32bit>(iv, 1);
- state[8] = load_le<u32bit>(iv, 2);
- state[9] = load_le<u32bit>(iv, 3);
+ m_state[6] = load_le<u32bit>(iv, 0);
+ m_state[7] = load_le<u32bit>(iv, 1);
+ m_state[8] = load_le<u32bit>(iv, 2);
+ m_state[9] = load_le<u32bit>(iv, 3);
secure_vector<u32bit> hsalsa(8);
- hsalsa20(&hsalsa[0], &state[0]);
-
- state[ 1] = hsalsa[0];
- state[ 2] = hsalsa[1];
- state[ 3] = hsalsa[2];
- state[ 4] = hsalsa[3];
- state[ 6] = load_le<u32bit>(iv, 4);
- state[ 7] = load_le<u32bit>(iv, 5);
- state[11] = hsalsa[4];
- state[12] = hsalsa[5];
- state[13] = hsalsa[6];
- state[14] = hsalsa[7];
+ hsalsa20(&hsalsa[0], &m_state[0]);
+
+ 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<u32bit>(iv, 4);
+ m_state[ 7] = load_le<u32bit>(iv, 5);
+ m_state[11] = hsalsa[4];
+ m_state[12] = hsalsa[5];
+ m_state[13] = hsalsa[6];
+ m_state[14] = hsalsa[7];
}
- state[8] = 0;
- state[9] = 0;
+ m_state[8] = 0;
+ m_state[9] = 0;
- salsa20(&buffer[0], &state[0]);
- ++state[8];
- if(!state[8]) // if overflow in state[8]
- ++state[9]; // carry to state[9]
+ salsa20(&m_buffer[0], &m_state[0]);
+ ++m_state[8];
+ m_state[9] += (m_state[8] == 0);
- position = 0;
+ m_position = 0;
}
/*
@@ -235,9 +225,9 @@ std::string Salsa20::name() const
*/
void Salsa20::clear()
{
- zap(state);
- zap(buffer);
- position = 0;
+ zap(m_state);
+ zap(m_buffer);
+ m_position = 0;
}
}
diff --git a/src/lib/stream/salsa20/salsa20.h b/src/lib/stream/salsa20/salsa20.h
index b68bb979e..69a9ea62f 100644
--- a/src/lib/stream/salsa20/salsa20.h
+++ b/src/lib/stream/salsa20/salsa20.h
@@ -36,9 +36,9 @@ class BOTAN_DLL Salsa20 : public StreamCipher
private:
void key_schedule(const byte key[], size_t key_len);
- secure_vector<u32bit> state;
- secure_vector<byte> buffer;
- size_t position;
+ secure_vector<u32bit> m_state;
+ secure_vector<byte> m_buffer;
+ size_t m_position;
};
}