aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/stream
diff options
context:
space:
mode:
authorlloyd <[email protected]>2014-01-10 03:41:59 +0000
committerlloyd <[email protected]>2014-01-10 03:41:59 +0000
commit6894dca64c04936d07048c0e8cbf7e25858548c3 (patch)
tree5d572bfde9fe667dab14e3f04b5285a85d8acd95 /src/lib/stream
parent9efa3be92442afb3d0b69890a36c7f122df18eda (diff)
Move lib into src
Diffstat (limited to 'src/lib/stream')
-rw-r--r--src/lib/stream/ctr/ctr.cpp134
-rw-r--r--src/lib/stream/ctr/ctr.h61
-rw-r--r--src/lib/stream/ctr/info.txt6
-rw-r--r--src/lib/stream/info.txt5
-rw-r--r--src/lib/stream/ofb/info.txt6
-rw-r--r--src/lib/stream/ofb/ofb.cpp93
-rw-r--r--src/lib/stream/ofb/ofb.h56
-rw-r--r--src/lib/stream/rc4/info.txt1
-rw-r--r--src/lib/stream/rc4/rc4.cpp109
-rw-r--r--src/lib/stream/rc4/rc4.h55
-rw-r--r--src/lib/stream/salsa20/info.txt1
-rw-r--r--src/lib/stream/salsa20/salsa20.cpp243
-rw-r--r--src/lib/stream/salsa20/salsa20.h46
-rw-r--r--src/lib/stream/stream_cipher.cpp24
-rw-r--r--src/lib/stream/stream_cipher.h70
15 files changed, 910 insertions, 0 deletions
diff --git a/src/lib/stream/ctr/ctr.cpp b/src/lib/stream/ctr/ctr.cpp
new file mode 100644
index 000000000..87ec86c65
--- /dev/null
+++ b/src/lib/stream/ctr/ctr.cpp
@@ -0,0 +1,134 @@
+/*
+* Counter mode
+* (C) 1999-2011 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/ctr.h>
+#include <botan/internal/xor_buf.h>
+
+namespace Botan {
+
+/*
+* CTR-BE Constructor
+*/
+
+CTR_BE::CTR_BE(BlockCipher* ciph) :
+ permutation(ciph),
+ counter(256 * permutation->block_size()),
+ buffer(counter.size()),
+ position(0)
+ {
+ }
+
+/*
+* CTR_BE Destructor
+*/
+CTR_BE::~CTR_BE()
+ {
+ delete permutation;
+ }
+
+/*
+* Zeroize
+*/
+void CTR_BE::clear()
+ {
+ permutation->clear();
+ zeroise(buffer);
+ zeroise(counter);
+ position = 0;
+ }
+
+/*
+* Set the key
+*/
+void CTR_BE::key_schedule(const byte key[], size_t key_len)
+ {
+ permutation->set_key(key, key_len);
+
+ // Set a default all-zeros IV
+ set_iv(nullptr, 0);
+ }
+
+/*
+* Return the name of this type
+*/
+std::string CTR_BE::name() const
+ {
+ return ("CTR-BE(" + permutation->name() + ")");
+ }
+
+/*
+* CTR-BE Encryption/Decryption
+*/
+void CTR_BE::cipher(const byte in[], byte out[], size_t length)
+ {
+ while(length >= buffer.size() - position)
+ {
+ xor_buf(out, in, &buffer[position], buffer.size() - position);
+ length -= (buffer.size() - position);
+ in += (buffer.size() - position);
+ out += (buffer.size() - position);
+ increment_counter();
+ }
+ xor_buf(out, in, &buffer[position], length);
+ position += length;
+ }
+
+/*
+* Set CTR-BE IV
+*/
+void CTR_BE::set_iv(const byte iv[], size_t iv_len)
+ {
+ if(!valid_iv_length(iv_len))
+ throw Invalid_IV_Length(name(), iv_len);
+
+ const size_t bs = permutation->block_size();
+
+ zeroise(counter);
+
+ buffer_insert(counter, 0, iv, iv_len);
+
+ /*
+ * Set counter blocks to IV, IV + 1, ... IV + 255
+ */
+ for(size_t i = 1; i != 256; ++i)
+ {
+ buffer_insert(counter, i*bs, &counter[(i-1)*bs], bs);
+
+ for(size_t j = 0; j != bs; ++j)
+ if(++counter[i*bs + (bs - 1 - j)])
+ break;
+ }
+
+ permutation->encrypt_n(&counter[0], &buffer[0], 256);
+ position = 0;
+ }
+
+/*
+* Increment the counter and update the buffer
+*/
+void CTR_BE::increment_counter()
+ {
+ const size_t bs = permutation->block_size();
+
+ /*
+ * Each counter value always needs to be incremented by 256,
+ * so we don't touch the lowest byte and instead treat it as
+ * an increment of one starting with the next byte.
+ */
+ for(size_t i = 0; i != 256; ++i)
+ {
+ for(size_t j = 1; j != bs; ++j)
+ if(++counter[i*bs + (bs - 1 - j)])
+ break;
+ }
+
+ permutation->encrypt_n(&counter[0], &buffer[0], 256);
+
+ position = 0;
+ }
+
+}
diff --git a/src/lib/stream/ctr/ctr.h b/src/lib/stream/ctr/ctr.h
new file mode 100644
index 000000000..84cf9ed5d
--- /dev/null
+++ b/src/lib/stream/ctr/ctr.h
@@ -0,0 +1,61 @@
+/*
+* CTR-BE Mode
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_CTR_BE_H__
+#define BOTAN_CTR_BE_H__
+
+#include <botan/block_cipher.h>
+#include <botan/stream_cipher.h>
+
+namespace Botan {
+
+/**
+* CTR-BE (Counter mode, big-endian)
+*/
+class BOTAN_DLL CTR_BE : 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 <= permutation->block_size()); }
+
+ Key_Length_Specification key_spec() const
+ {
+ return permutation->key_spec();
+ }
+
+ std::string name() const;
+
+ CTR_BE* clone() const
+ { return new CTR_BE(permutation->clone()); }
+
+ void clear();
+
+ /**
+ * @param cipher the underlying block cipher to use
+ */
+ CTR_BE(BlockCipher* cipher);
+
+ CTR_BE(const CTR_BE&) = delete;
+ CTR_BE& operator=(const CTR_BE&) = delete;
+
+ ~CTR_BE();
+ private:
+ void key_schedule(const byte key[], size_t key_len);
+ void increment_counter();
+
+ BlockCipher* permutation;
+ secure_vector<byte> counter, buffer;
+ size_t position;
+ };
+
+}
+
+#endif
diff --git a/src/lib/stream/ctr/info.txt b/src/lib/stream/ctr/info.txt
new file mode 100644
index 000000000..84d90a76f
--- /dev/null
+++ b/src/lib/stream/ctr/info.txt
@@ -0,0 +1,6 @@
+define CTR_BE 20131128
+
+<requires>
+block
+stream
+</requires>
diff --git a/src/lib/stream/info.txt b/src/lib/stream/info.txt
new file mode 100644
index 000000000..faa2db215
--- /dev/null
+++ b/src/lib/stream/info.txt
@@ -0,0 +1,5 @@
+define STREAM_CIPHER 20131128
+
+<requires>
+algo_base
+</requires>
diff --git a/src/lib/stream/ofb/info.txt b/src/lib/stream/ofb/info.txt
new file mode 100644
index 000000000..11b6bfb27
--- /dev/null
+++ b/src/lib/stream/ofb/info.txt
@@ -0,0 +1,6 @@
+define OFB 20131128
+
+<requires>
+block
+stream
+</requires>
diff --git a/src/lib/stream/ofb/ofb.cpp b/src/lib/stream/ofb/ofb.cpp
new file mode 100644
index 000000000..1137a58af
--- /dev/null
+++ b/src/lib/stream/ofb/ofb.cpp
@@ -0,0 +1,93 @@
+/*
+* OFB Mode
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/ofb.h>
+#include <botan/internal/xor_buf.h>
+#include <algorithm>
+
+namespace Botan {
+
+/*
+* OFB Constructor
+*/
+OFB::OFB(BlockCipher* ciph) : permutation(ciph)
+ {
+ position = 0;
+ buffer.resize(permutation->block_size());
+ }
+
+/*
+* OFB Destructor
+*/
+OFB::~OFB()
+ {
+ delete permutation;
+ }
+
+/*
+* Zeroize
+*/
+void OFB::clear()
+ {
+ permutation->clear();
+ zeroise(buffer);
+ position = 0;
+ }
+
+/*
+* Set the key
+*/
+void OFB::key_schedule(const byte key[], size_t key_len)
+ {
+ permutation->set_key(key, key_len);
+
+ // Set a default all-zeros IV
+ set_iv(nullptr, 0);
+ }
+
+/*
+* Return the name of this type
+*/
+std::string OFB::name() const
+ {
+ return ("OFB(" + permutation->name() + ")");
+ }
+
+/*
+* CTR-BE Encryption/Decryption
+*/
+void OFB::cipher(const byte in[], byte out[], size_t length)
+ {
+ while(length >= buffer.size() - position)
+ {
+ xor_buf(out, in, &buffer[position], buffer.size() - position);
+ length -= (buffer.size() - position);
+ in += (buffer.size() - position);
+ out += (buffer.size() - position);
+ permutation->encrypt(buffer);
+ position = 0;
+ }
+ xor_buf(out, in, &buffer[position], length);
+ position += length;
+ }
+
+/*
+* Set CTR-BE IV
+*/
+void OFB::set_iv(const byte iv[], size_t iv_len)
+ {
+ if(!valid_iv_length(iv_len))
+ throw Invalid_IV_Length(name(), iv_len);
+
+ zeroise(buffer);
+ buffer_insert(buffer, 0, iv, iv_len);
+
+ permutation->encrypt(buffer);
+ position = 0;
+ }
+
+}
diff --git a/src/lib/stream/ofb/ofb.h b/src/lib/stream/ofb/ofb.h
new file mode 100644
index 000000000..9d4fd882f
--- /dev/null
+++ b/src/lib/stream/ofb/ofb.h
@@ -0,0 +1,56 @@
+/*
+* OFB Mode
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_OUTPUT_FEEDBACK_MODE_H__
+#define BOTAN_OUTPUT_FEEDBACK_MODE_H__
+
+#include <botan/stream_cipher.h>
+#include <botan/block_cipher.h>
+
+namespace Botan {
+
+/**
+* Output Feedback Mode
+*/
+class BOTAN_DLL OFB : 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 <= permutation->block_size()); }
+
+ Key_Length_Specification key_spec() const
+ {
+ return permutation->key_spec();
+ }
+
+ std::string name() const;
+
+ OFB* clone() const
+ { return new OFB(permutation->clone()); }
+
+ void clear();
+
+ /**
+ * @param cipher the underlying block cipher to use
+ */
+ OFB(BlockCipher* cipher);
+ ~OFB();
+ private:
+ void key_schedule(const byte key[], size_t key_len);
+
+ BlockCipher* permutation;
+ secure_vector<byte> buffer;
+ size_t position;
+ };
+
+}
+
+#endif
diff --git a/src/lib/stream/rc4/info.txt b/src/lib/stream/rc4/info.txt
new file mode 100644
index 000000000..f61b8a4cc
--- /dev/null
+++ b/src/lib/stream/rc4/info.txt
@@ -0,0 +1 @@
+define RC4 20131128
diff --git a/src/lib/stream/rc4/rc4.cpp b/src/lib/stream/rc4/rc4.cpp
new file mode 100644
index 000000000..df6976235
--- /dev/null
+++ b/src/lib/stream/rc4/rc4.cpp
@@ -0,0 +1,109 @@
+/*
+* RC4
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/rc4.h>
+#include <botan/internal/xor_buf.h>
+#include <botan/internal/rounding.h>
+
+namespace Botan {
+
+/*
+* Combine cipher stream with message
+*/
+void RC4::cipher(const byte in[], byte out[], size_t length)
+ {
+ while(length >= buffer.size() - position)
+ {
+ xor_buf(out, in, &buffer[position], buffer.size() - position);
+ length -= (buffer.size() - position);
+ in += (buffer.size() - position);
+ out += (buffer.size() - position);
+ generate();
+ }
+ xor_buf(out, in, &buffer[position], length);
+ position += length;
+ }
+
+/*
+* Generate cipher stream
+*/
+void RC4::generate()
+ {
+ byte SX, SY;
+ for(size_t i = 0; i != buffer.size(); i += 4)
+ {
+ SX = state[X+1]; Y = (Y + SX) % 256; SY = state[Y];
+ state[X+1] = SY; state[Y] = SX;
+ buffer[i] = state[(SX + SY) % 256];
+
+ SX = state[X+2]; Y = (Y + SX) % 256; SY = state[Y];
+ state[X+2] = SY; state[Y] = SX;
+ buffer[i+1] = state[(SX + SY) % 256];
+
+ SX = state[X+3]; Y = (Y + SX) % 256; SY = state[Y];
+ state[X+3] = SY; state[Y] = SX;
+ buffer[i+2] = state[(SX + SY) % 256];
+
+ X = (X + 4) % 256;
+ SX = state[X]; Y = (Y + SX) % 256; SY = state[Y];
+ state[X] = SY; state[Y] = SX;
+ buffer[i+3] = state[(SX + SY) % 256];
+ }
+ position = 0;
+ }
+
+/*
+* RC4 Key Schedule
+*/
+void RC4::key_schedule(const byte key[], size_t length)
+ {
+ state.resize(256);
+ buffer.resize(round_up<size_t>(DEFAULT_BUFFERSIZE, 4));
+
+ position = X = Y = 0;
+
+ for(size_t i = 0; i != 256; ++i)
+ state[i] = static_cast<byte>(i);
+
+ for(size_t i = 0, state_index = 0; i != 256; ++i)
+ {
+ state_index = (state_index + key[i % length] + state[i]) % 256;
+ std::swap(state[i], state[state_index]);
+ }
+
+ for(size_t i = 0; i <= SKIP; i += buffer.size())
+ generate();
+
+ position += (SKIP % buffer.size());
+ }
+
+/*
+* Return the name of this type
+*/
+std::string RC4::name() const
+ {
+ if(SKIP == 0) return "RC4";
+ if(SKIP == 256) return "MARK-4";
+ else return "RC4_skip(" + std::to_string(SKIP) + ")";
+ }
+
+/*
+* Clear memory of sensitive data
+*/
+void RC4::clear()
+ {
+ zap(state);
+ zap(buffer);
+ position = X = Y = 0;
+ }
+
+/*
+* RC4 Constructor
+*/
+RC4::RC4(size_t s) : SKIP(s) {}
+
+}
diff --git a/src/lib/stream/rc4/rc4.h b/src/lib/stream/rc4/rc4.h
new file mode 100644
index 000000000..c23f8c853
--- /dev/null
+++ b/src/lib/stream/rc4/rc4.h
@@ -0,0 +1,55 @@
+/*
+* RC4
+* (C) 1999-2008 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_RC4_H__
+#define BOTAN_RC4_H__
+
+#include <botan/stream_cipher.h>
+#include <botan/types.h>
+
+namespace Botan {
+
+/**
+* RC4 stream cipher
+*/
+class BOTAN_DLL RC4 : public StreamCipher
+ {
+ public:
+ void cipher(const byte in[], byte out[], size_t length);
+
+ void clear();
+ std::string name() const;
+
+ StreamCipher* clone() const { return new RC4(SKIP); }
+
+ Key_Length_Specification key_spec() const
+ {
+ return Key_Length_Specification(1, 256);
+ }
+
+ /**
+ * @param skip skip this many initial bytes in the keystream
+ */
+ RC4(size_t skip = 0);
+
+ ~RC4() { clear(); }
+ private:
+ void key_schedule(const byte[], size_t);
+ void generate();
+
+ const size_t SKIP;
+
+ byte X, Y;
+ secure_vector<byte> state;
+
+ secure_vector<byte> buffer;
+ size_t position;
+ };
+
+}
+
+#endif
diff --git a/src/lib/stream/salsa20/info.txt b/src/lib/stream/salsa20/info.txt
new file mode 100644
index 000000000..10f9a8cb2
--- /dev/null
+++ b/src/lib/stream/salsa20/info.txt
@@ -0,0 +1 @@
+define SALSA20 20131128
diff --git a/src/lib/stream/salsa20/salsa20.cpp b/src/lib/stream/salsa20/salsa20.cpp
new file mode 100644
index 000000000..d8db69ae6
--- /dev/null
+++ b/src/lib/stream/salsa20/salsa20.cpp
@@ -0,0 +1,243 @@
+/*
+* Salsa20 / XSalsa20
+* (C) 1999-2010 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/salsa20.h>
+#include <botan/loadstor.h>
+#include <botan/rotate.h>
+#include <botan/internal/xor_buf.h>
+
+namespace Botan {
+
+namespace {
+
+#define SALSA20_QUARTER_ROUND(x1, x2, x3, x4) \
+ do { \
+ x2 ^= rotate_left(x1 + x4, 7); \
+ x3 ^= rotate_left(x2 + x1, 9); \
+ x4 ^= rotate_left(x3 + x2, 13); \
+ x1 ^= rotate_left(x4 + x3, 18); \
+ } while(0)
+
+/*
+* Generate HSalsa20 cipher stream (for XSalsa20 IV setup)
+*/
+void hsalsa20(u32bit output[8], 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];
+
+ 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
+*/
+void salsa20(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];
+
+ 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);
+ }
+
+ 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 Salsa20::cipher(const byte in[], byte out[], size_t length)
+ {
+ while(length >= buffer.size() - 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]);
+
+ ++state[8];
+ if(!state[8]) // if overflow in state[8]
+ ++state[9]; // carry to state[9]
+
+ position = 0;
+ }
+
+ xor_buf(out, in, &buffer[position], length);
+
+ position += length;
+ }
+
+/*
+* Salsa20 Key Schedule
+*/
+void Salsa20::key_schedule(const byte key[], size_t length)
+ {
+ static const u32bit TAU[] =
+ { 0x61707865, 0x3120646e, 0x79622d36, 0x6b206574 };
+
+ static const u32bit SIGMA[] =
+ { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 };
+
+ state.resize(16);
+ buffer.resize(64);
+
+ 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];
+ }
+
+ position = 0;
+
+ const byte ZERO[8] = { 0 };
+ set_iv(ZERO, sizeof(ZERO));
+ }
+
+/*
+* Return the name of this type
+*/
+void Salsa20::set_iv(const byte iv[], size_t length)
+ {
+ if(!valid_iv_length(length))
+ throw Invalid_IV_Length(name(), length);
+
+ if(length == 8)
+ {
+ // Salsa20
+ state[6] = load_le<u32bit>(iv, 0);
+ 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);
+
+ 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];
+ }
+
+ state[8] = 0;
+ state[9] = 0;
+
+ salsa20(&buffer[0], &state[0]);
+ ++state[8];
+ if(!state[8]) // if overflow in state[8]
+ ++state[9]; // carry to state[9]
+
+ position = 0;
+ }
+
+/*
+* Return the name of this type
+*/
+std::string Salsa20::name() const
+ {
+ return "Salsa20";
+ }
+
+/*
+* Clear memory of sensitive data
+*/
+void Salsa20::clear()
+ {
+ zap(state);
+ zap(buffer);
+ position = 0;
+ }
+
+}
diff --git a/src/lib/stream/salsa20/salsa20.h b/src/lib/stream/salsa20/salsa20.h
new file mode 100644
index 000000000..b68bb979e
--- /dev/null
+++ b/src/lib/stream/salsa20/salsa20.h
@@ -0,0 +1,46 @@
+/*
+* Salsa20 / XSalsa20
+* (C) 1999-2010 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_SALSA20_H__
+#define BOTAN_SALSA20_H__
+
+#include <botan/stream_cipher.h>
+
+namespace Botan {
+
+/**
+* DJB's Salsa20 (and XSalsa20)
+*/
+class BOTAN_DLL Salsa20 : 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 || iv_len == 24); }
+
+ Key_Length_Specification key_spec() const
+ {
+ return Key_Length_Specification(16, 32, 16);
+ }
+
+ void clear();
+ std::string name() const;
+ StreamCipher* clone() const { return new Salsa20; }
+ private:
+ void key_schedule(const byte key[], size_t key_len);
+
+ secure_vector<u32bit> state;
+ secure_vector<byte> buffer;
+ size_t position;
+ };
+
+}
+
+#endif
diff --git a/src/lib/stream/stream_cipher.cpp b/src/lib/stream/stream_cipher.cpp
new file mode 100644
index 000000000..7dbd3e2e3
--- /dev/null
+++ b/src/lib/stream/stream_cipher.cpp
@@ -0,0 +1,24 @@
+/*
+* Stream Cipher
+* (C) 1999-2010 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/stream_cipher.h>
+
+namespace Botan {
+
+void StreamCipher::set_iv(const byte[], size_t iv_len)
+ {
+ if(iv_len)
+ throw Invalid_Argument("The stream cipher " + name() +
+ " does not support resyncronization");
+ }
+
+bool StreamCipher::valid_iv_length(size_t iv_len) const
+ {
+ return (iv_len == 0);
+ }
+
+}
diff --git a/src/lib/stream/stream_cipher.h b/src/lib/stream/stream_cipher.h
new file mode 100644
index 000000000..f3d3999f0
--- /dev/null
+++ b/src/lib/stream/stream_cipher.h
@@ -0,0 +1,70 @@
+/*
+* Stream Cipher
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_STREAM_CIPHER_H__
+#define BOTAN_STREAM_CIPHER_H__
+
+#include <botan/sym_algo.h>
+
+namespace Botan {
+
+/**
+* Base class for all stream ciphers
+*/
+class BOTAN_DLL StreamCipher : public SymmetricAlgorithm
+ {
+ public:
+ /**
+ * 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 byte in[], byte out[], size_t len) = 0;
+
+ /**
+ * Encrypt or decrypt a message
+ * @param buf the plaintext / ciphertext
+ * @param len the length of buf in bytes
+ */
+ void cipher1(byte buf[], size_t len)
+ { cipher(buf, buf, len); }
+
+ template<typename Alloc>
+ void encipher(std::vector<byte, Alloc>& inout)
+ { cipher(&inout[0], &inout[0], inout.size()); }
+
+ template<typename Alloc>
+ void encrypt(std::vector<byte, Alloc>& inout)
+ { cipher(&inout[0], &inout[0], inout.size()); }
+
+ template<typename Alloc>
+ void decrypt(std::vector<byte, Alloc>& inout)
+ { cipher(&inout[0], &inout[0], 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 byte iv[], size_t iv_len);
+
+ /**
+ * @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;
+
+ /**
+ * Get a new object representing the same algorithm as *this
+ */
+ virtual StreamCipher* clone() const = 0;
+ };
+
+}
+
+#endif