add Salsa20 cipher

pull/2/head
weidai 2006-12-09 17:18:13 +00:00
parent d5a0764683
commit 28c392e082
15 changed files with 716 additions and 465 deletions

View File

@ -1,5 +1,5 @@
Crypto++: a C++ Class Library of Cryptographic Schemes Crypto++: a C++ Class Library of Cryptographic Schemes
Version 5.3 (in development) Version 5.4 (in development)
This library includes: This library includes:
@ -354,4 +354,7 @@ the mailing list.
- Added defense against AES timing attacks, and more AES test vectors - Added defense against AES timing attacks, and more AES test vectors
- Changed StaticAlgorithmName() of Rijndael to "AES", CTR to "CTR" - Changed StaticAlgorithmName() of Rijndael to "AES", CTR to "CTR"
5.4 - added Salsa20
- updated Whirlpool to version 3.0
Written by Wei Dai Written by Wei Dai

View File

@ -54,6 +54,7 @@ Plaintext - encoded string
Ciphertext - encoded string Ciphertext - encoded string
Digest - encoded string Digest - encoded string
TruncatedSize - int, size of truncated digest in bytes TruncatedSize - int, size of truncated digest in bytes
Seek - int, seek location for random access ciphers
(more to come here) (more to come here)
Possible Tests Possible Tests

View File

@ -19,3 +19,4 @@ Test: seal.txt
Test: sha.txt Test: sha.txt
Test: panama.txt Test: panama.txt
Test: aes.txt Test: aes.txt
Test: salsa.txt

33
TestVectors/salsa.txt Executable file
View File

@ -0,0 +1,33 @@
AlgorithmType: SymmetricCipher
Name: Salsa20
Source: http://www.ecrypt.eu.org/stream/svn/viewcvs.cgi/ecrypt/trunk/submissions/salsa20/full/verified.test-vectors?rev=161&view=markup
Comment: Set 1, vector# 0
Key: 80000000000000000000000000000000
IV: 0000000000000000
Plaintext: r16 00000000
Seek: 0
Ciphertext: 4DFA5E481DA23EA09A31022050859936DA52FCEE218005164F267CB65F5CFD7F2B4F97E0FF16924A52DF269515110A07F9E460BC65EF95DA58F740B7D1DBB0AA
Test: Encrypt
Seek: 448
Ciphertext: B375703739DACED4DD4059FD71C3C47FC2F9939670FAD4A46066ADCC6A5645783308B90FFB72BE04A6B147CBE38CC0C3B9267C296A92A7C69873F9F263BE9703
Test: Encrypt
Seek: 192
Plaintext: r32 00000000
Ciphertext: DA9C1581F429E0A00F7D67E23B730676783B262E8EB43A25F55FB90B3E753AEF8C6713EC66C51881111593CCB3E8CB8F8DE124080501EEEB389C4BCB6977CF95\
7D5789631EB4554400E1E025935DFA7B3E9039D61BDC58A8697D36815BF1985CEFDF7AE112E5BB81E37ECF0616CE7147FC08A93A367E08631F23C03B00A8DA2F
Test: Encrypt
Comment: Set 3, vector#243
Key: F3F4F5F6F7F8F9FAFBFCFDFEFF000102030405060708090A0B0C0D0E0F101112
IV: 0000000000000000
Plaintext: r16 00000000
Seek: 0
Ciphertext: B4C0AFA503BE7FC29A62058166D56F8F5D27DC246F75B9AD8760C8C39DFD87492D3B76D5D9637F009EADA14458A52DFB09815337E72672681DDDC24633750D83
Test: Encrypt
Seek: 448
Ciphertext: 5A5FB5C8F0AFEA471F0318A4A2792F7AA5C67B6D6E0F0DDB79961C34E3A564BA2EECE78D9AFF45E510FEAB1030B102D39DFCECB77F5798F7D2793C0AB09C7A04
Test: Encrypt
Seek: 192
Plaintext: r32 00000000
Ciphertext: DBBA0683DF48C335A9802EEF0252256354C9F763C3FDE19131A6BB7B85040624B1D6CD4BF66D16F7482236C8602A6D58505EEDCCA0B77AED574AB583115124B9\
F0C5F98BAE05E019764EF6B65E0694A904CB9EC9C10C297B1AB1A6052365BB78E55D3C6CB9F06184BA7D425A92E7E987757FC5D9AFD7082418DD64125CA6F2B6
Test: Encrypt

View File

@ -49,6 +49,7 @@
#include "mdc.h" #include "mdc.h"
#include "lubyrack.h" #include "lubyrack.h"
#include "tea.h" #include "tea.h"
#include "salsa.h"
#include <time.h> #include <time.h>
#include <math.h> #include <math.h>
@ -184,19 +185,19 @@ void BenchMark(const char *name, BufferedTransformation &bt, double timeTotal)
//VC60 workaround: compiler bug triggered without the extra dummy parameters //VC60 workaround: compiler bug triggered without the extra dummy parameters
template <class T> template <class T>
void BenchMarkKeyed(const char *name, double timeTotal, T *x=NULL) void BenchMarkKeyed(const char *name, double timeTotal, const NameValuePairs &params = g_nullNameValuePairs, T *x=NULL)
{ {
T c; T c;
c.SetKey(key, c.DefaultKeyLength(), MakeParameters(Name::IV(), key, false)); c.SetKey(key, c.DefaultKeyLength(), CombinedNameValuePairs(params, MakeParameters(Name::IV(), key, false)));
BenchMark(name, c, timeTotal); BenchMark(name, c, timeTotal);
} }
//VC60 workaround: compiler bug triggered without the extra dummy parameters //VC60 workaround: compiler bug triggered without the extra dummy parameters
template <class T> template <class T>
void BenchMarkKeyedVariable(const char *name, double timeTotal, unsigned int keyLength, T *x=NULL) void BenchMarkKeyedVariable(const char *name, double timeTotal, unsigned int keyLength, const NameValuePairs &params = g_nullNameValuePairs, T *x=NULL)
{ {
T c; T c;
c.SetKey(key, keyLength, MakeParameters(Name::IV(), key, false)); c.SetKey(key, keyLength, CombinedNameValuePairs(params, MakeParameters(Name::IV(), key, false)));
BenchMark(name, c, timeTotal); BenchMark(name, c, timeTotal);
} }
@ -287,6 +288,10 @@ void BenchmarkAll(double t)
BenchMarkKeyedVariable<Camellia::Encryption>("Camellia (128-bit key)", t, 16); BenchMarkKeyedVariable<Camellia::Encryption>("Camellia (128-bit key)", t, 16);
BenchMarkKeyedVariable<Camellia::Encryption>("Camellia (256-bit key)", t, 32); BenchMarkKeyedVariable<Camellia::Encryption>("Camellia (256-bit key)", t, 32);
#endif #endif
BenchMarkKeyed<Salsa20::Encryption>("Salsa20", t);
BenchMarkKeyed<Salsa20::Encryption>("Salsa20/12", t, MakeParameters(Name::Rounds(), 12));
BenchMarkKeyed<Salsa20::Encryption>("Salsa20/8", t, MakeParameters(Name::Rounds(), 8));
BenchMarkKeyed<MD5MAC>("MD5-MAC", t); BenchMarkKeyed<MD5MAC>("MD5-MAC", t);
BenchMarkKeyed<XMACC<MD5> >("XMACC/MD5", t); BenchMarkKeyed<XMACC<MD5> >("XMACC/MD5", t);
BenchMarkKeyed<HMAC<MD5> >("HMAC/MD5", t); BenchMarkKeyed<HMAC<MD5> >("HMAC/MD5", t);

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="gb2312"?>
<VisualStudioProject <VisualStudioProject
ProjectType="Visual C++" ProjectType="Visual C++"
Version="8.00" Version="8.00"
@ -7074,6 +7074,10 @@
/> />
</FileConfiguration> </FileConfiguration>
</File> </File>
<File
RelativePath=".\salsa.cpp"
>
</File>
<File <File
RelativePath="seal.cpp" RelativePath="seal.cpp"
> >
@ -9567,6 +9571,10 @@
RelativePath="safer.h" RelativePath="safer.h"
> >
</File> </File>
<File
RelativePath=".\salsa.h"
>
</File>
<File <File
RelativePath="seal.h" RelativePath="seal.h"
> >

View File

@ -265,6 +265,9 @@ void TestSymmetricCipher(TestData &v)
{ {
std::auto_ptr<SymmetricCipher> encryptor(ObjectFactoryRegistry<SymmetricCipher, ENCRYPTION>::Registry().CreateObject(name.c_str())); std::auto_ptr<SymmetricCipher> encryptor(ObjectFactoryRegistry<SymmetricCipher, ENCRYPTION>::Registry().CreateObject(name.c_str()));
encryptor->SetKey((const byte *)key.data(), key.size(), pairs); encryptor->SetKey((const byte *)key.data(), key.size(), pairs);
int seek = pairs.GetIntValueWithDefault("Seek", 0);
if (seek)
encryptor->Seek(seek);
std::string encrypted; std::string encrypted;
StringSource ss(plaintext, true, new StreamTransformationFilter(*encryptor, new StringSink(encrypted), StreamTransformationFilter::NO_PADDING)); StringSource ss(plaintext, true, new StreamTransformationFilter(*encryptor, new StringSink(encrypted), StreamTransformationFilter::NO_PADDING));
if (encrypted != ciphertext) if (encrypted != ciphertext)
@ -274,6 +277,9 @@ void TestSymmetricCipher(TestData &v)
{ {
std::auto_ptr<SymmetricCipher> decryptor(ObjectFactoryRegistry<SymmetricCipher, DECRYPTION>::Registry().CreateObject(name.c_str())); std::auto_ptr<SymmetricCipher> decryptor(ObjectFactoryRegistry<SymmetricCipher, DECRYPTION>::Registry().CreateObject(name.c_str()));
decryptor->SetKey((const byte *)key.data(), key.size(), pairs); decryptor->SetKey((const byte *)key.data(), key.size(), pairs);
int seek = pairs.GetIntValueWithDefault("Seek", 0);
if (seek)
decryptor->Seek(seek);
std::string decrypted; std::string decrypted;
StringSource ss(ciphertext, true, new StreamTransformationFilter(*decryptor, new StringSink(decrypted), StreamTransformationFilter::NO_PADDING)); StringSource ss(ciphertext, true, new StreamTransformationFilter(*decryptor, new StringSink(decrypted), StreamTransformationFilter::NO_PADDING));
if (decrypted != plaintext) if (decrypted != plaintext)

View File

@ -19,6 +19,7 @@
#include "panama.h" #include "panama.h"
#include "pssr.h" #include "pssr.h"
#include "aes.h" #include "aes.h"
#include "salsa.h"
USING_NAMESPACE(CryptoPP) USING_NAMESPACE(CryptoPP)
@ -69,6 +70,7 @@ void RegisterFactories()
RegisterSymmetricCipherDefaultFactories<CFB_Mode<AES> >(); RegisterSymmetricCipherDefaultFactories<CFB_Mode<AES> >();
RegisterSymmetricCipherDefaultFactories<OFB_Mode<AES> >(); RegisterSymmetricCipherDefaultFactories<OFB_Mode<AES> >();
RegisterSymmetricCipherDefaultFactories<CTR_Mode<AES> >(); RegisterSymmetricCipherDefaultFactories<CTR_Mode<AES> >();
RegisterSymmetricCipherDefaultFactories<Salsa20>();
s_registered = true; s_registered = true;
} }

139
salsa.cpp Executable file
View File

@ -0,0 +1,139 @@
// salsa.cpp - written and placed in the public domain by Wei Dai
#include "pch.h"
#include "salsa.h"
#include "misc.h"
#include "argnames.h"
NAMESPACE_BEGIN(CryptoPP)
void Salsa20_TestInstantiations()
{
Salsa20::Encryption x;
}
void Salsa20_Policy::GetNextIV(byte *IV) const
{
word32 j6 = m_state[6] + 1;
word32 j7 = m_state[7] + (j6 == 0);
UnalignedPutWord(LITTLE_ENDIAN_ORDER, IV, j6);
UnalignedPutWord(LITTLE_ENDIAN_ORDER, IV+4, j7);
}
void Salsa20_Policy::CipherSetKey(const NameValuePairs &params, const byte *key, size_t length)
{
m_rounds = params.GetIntValueWithDefault(Name::Rounds(), 20);
if (!(m_rounds == 8 || m_rounds == 12 || m_rounds == 20))
throw InvalidRounds(StaticAlgorithmName(), m_rounds);
GetUserKey(LITTLE_ENDIAN_ORDER, m_state+1, 4, key, 16);
GetUserKey(LITTLE_ENDIAN_ORDER, m_state+11, 4, key + length - 16, 16);
// m_state[0,5,10,15] forms "expand 16-byte k" or "expand 32-byte k"
m_state[0] = 0x61707865;
m_state[5] = (length == 16) ? 0x3120646e : 0x3320646e;
m_state[10] = (length == 16) ? 0x79622d36 : 0x79622d32;
m_state[15] = 0x6b206574;
}
void Salsa20_Policy::CipherResynchronize(byte *keystreamBuffer, const byte *IV)
{
GetUserKey(LITTLE_ENDIAN_ORDER, m_state+6, 4, IV, 8);
}
void Salsa20_Policy::SeekToIteration(lword iterationCount)
{
m_state[8] = (word32)iterationCount;
m_state[9] = (word32)SafeRightShift<32>(iterationCount);
}
void Salsa20_Policy::OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount)
{
KeystreamOutput<LittleEndian> keystreamOutput(operation, output, input);
word32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
word32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
j0 = m_state[0];
j1 = m_state[1];
j2 = m_state[2];
j3 = m_state[3];
j4 = m_state[4];
j5 = m_state[5];
j6 = m_state[6];
j7 = m_state[7];
j8 = m_state[8];
j9 = m_state[9];
j10 = m_state[10];
j11 = m_state[11];
j12 = m_state[12];
j13 = m_state[13];
j14 = m_state[14];
j15 = m_state[15];
for (size_t iteration = 0; iteration < iterationCount; ++iteration)
{
x0 = j0;
x1 = j1;
x2 = j2;
x3 = j3;
x4 = j4;
x5 = j5;
x6 = j6;
x7 = j7;
x8 = j8;
x9 = j9;
x10 = j10;
x11 = j11;
x12 = j12;
x13 = j13;
x14 = j14;
x15 = j15;
for (int i=m_rounds; i>0; i-=2)
{
#define QUARTER_ROUND(a, b, c, d) \
b = b ^ rotlFixed(a + d, 7); \
c = c ^ rotlFixed(b + a, 9); \
d = d ^ rotlFixed(c + b, 13); \
a = a ^ rotlFixed(d + c, 18);
QUARTER_ROUND(x0, x4, x8, x12)
QUARTER_ROUND(x5, x9, x13, x1)
QUARTER_ROUND(x10, x14, x2, x6)
QUARTER_ROUND(x15, x3, x7, x11)
QUARTER_ROUND(x0, x1, x2, x3)
QUARTER_ROUND(x5, x6, x7, x4)
QUARTER_ROUND(x10, x11, x8, x9)
QUARTER_ROUND(x15, x12, x13, x14)
}
keystreamOutput (x0 + j0)
(x1 + j1)
(x2 + j2)
(x3 + j3)
(x4 + j4)
(x5 + j5)
(x6 + j6)
(x7 + j7)
(x8 + j8)
(x9 + j9)
(x10 + j10)
(x11 + j11)
(x12 + j12)
(x13 + j13)
(x14 + j14)
(x15 + j15);
if (++j8 == 0)
++j9;
}
m_state[8] = j8;
m_state[9] = j9;
}
NAMESPACE_END

43
salsa.h Executable file
View File

@ -0,0 +1,43 @@
// salsa.h - written and placed in the public domain by Wei Dai
#ifndef CRYPTOPP_SALSA_H
#define CRYPTOPP_SALSA_H
#include "strciphr.h"
NAMESPACE_BEGIN(CryptoPP)
//! _
struct Salsa20_Info : public VariableKeyLength<32, 16, 32, 16, SimpleKeyingInterface::STRUCTURED_IV>
{
static const char *StaticAlgorithmName() {return "Salsa20";}
};
class CRYPTOPP_NO_VTABLE Salsa20_Policy : public AdditiveCipherConcretePolicy<word32, 16>, public Salsa20_Info
{
public:
unsigned int IVSize() const {return 8;}
void GetNextIV(byte *IV) const;
protected:
void CipherSetKey(const NameValuePairs &params, const byte *key, size_t length);
void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount);
void CipherResynchronize(byte *keystreamBuffer, const byte *IV);
bool IsRandomAccess() const {return true;}
void SeekToIteration(lword iterationCount);
private:
int m_rounds;
FixedSizeSecBlock<word32, 16> m_state;
};
//! Salsa20, variable rounds: 8, 12 or 20 (default 20)
struct Salsa20 : public Salsa20_Info, public SymmetricCipherDocumentation
{
typedef SymmetricCipherFinal<ConcretePolicyHolder<Salsa20_Policy, AdditiveCipherTemplate<> >, Salsa20_Info> Encryption;
typedef Encryption Decryption;
};
NAMESPACE_END
#endif

View File

@ -811,6 +811,7 @@ bool Validate(int alg, bool thorough, const char *seed)
case 61: result = ValidateCamellia(); break; case 61: result = ValidateCamellia(); break;
case 62: result = ValidateWhirlpool(); break; case 62: result = ValidateWhirlpool(); break;
case 63: result = ValidateTTMAC(); break; case 63: result = ValidateTTMAC(); break;
case 64: result = ValidateSalsa(); break;
default: result = ValidateAll(thorough); break; default: result = ValidateAll(thorough); break;
} }

View File

@ -91,6 +91,7 @@ bool ValidateAll(bool thorough)
pass=ValidateSerpent() && pass; pass=ValidateSerpent() && pass;
pass=ValidateSHACAL2() && pass; pass=ValidateSHACAL2() && pass;
pass=ValidateCamellia() && pass; pass=ValidateCamellia() && pass;
pass=ValidateSalsa() && pass;
pass=ValidateBBS() && pass; pass=ValidateBBS() && pass;
pass=ValidateDH() && pass; pass=ValidateDH() && pass;
@ -1307,3 +1308,10 @@ bool ValidateCamellia()
return true; return true;
#endif #endif
} }
bool ValidateSalsa()
{
cout << "\nSalsa validation suite running...\n";
return RunTestDataFile("TestVectors/salsa.txt");
}

View File

@ -391,7 +391,7 @@ bool ValidateWhirlpool()
cout << "word64 not available, skipping Whirlpool validation." << endl; cout << "word64 not available, skipping Whirlpool validation." << endl;
return true; return true;
#endif #endif
} }
bool ValidateMD5MAC() bool ValidateMD5MAC()
{ {

View File

@ -52,6 +52,7 @@ bool ValidateTwofish();
bool ValidateSerpent(); bool ValidateSerpent();
bool ValidateSHACAL2(); bool ValidateSHACAL2();
bool ValidateCamellia(); bool ValidateCamellia();
bool ValidateSalsa();
bool ValidateBBS(); bool ValidateBBS();
bool ValidateDH(); bool ValidateDH();