diff --git a/Readme.txt b/Readme.txt index dfec1c05..6d77158e 100644 --- a/Readme.txt +++ b/Readme.txt @@ -1,5 +1,5 @@ Crypto++: a C++ Class Library of Cryptographic Schemes -Version 5.3 (in development) +Version 5.4 (in development) This library includes: @@ -354,4 +354,7 @@ the mailing list. - Added defense against AES timing attacks, and more AES test vectors - Changed StaticAlgorithmName() of Rijndael to "AES", CTR to "CTR" +5.4 - added Salsa20 + - updated Whirlpool to version 3.0 + Written by Wei Dai diff --git a/TestVectors/Readme.txt b/TestVectors/Readme.txt index 664d9724..755a0461 100644 --- a/TestVectors/Readme.txt +++ b/TestVectors/Readme.txt @@ -54,6 +54,7 @@ Plaintext - encoded string Ciphertext - encoded string Digest - encoded string TruncatedSize - int, size of truncated digest in bytes +Seek - int, seek location for random access ciphers (more to come here) Possible Tests diff --git a/TestVectors/all.txt b/TestVectors/all.txt index a0cfaa99..4419e30a 100644 --- a/TestVectors/all.txt +++ b/TestVectors/all.txt @@ -19,3 +19,4 @@ Test: seal.txt Test: sha.txt Test: panama.txt Test: aes.txt +Test: salsa.txt diff --git a/TestVectors/salsa.txt b/TestVectors/salsa.txt new file mode 100755 index 00000000..d07967e7 --- /dev/null +++ b/TestVectors/salsa.txt @@ -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 diff --git a/bench.cpp b/bench.cpp index 6ba54314..b1017c17 100644 --- a/bench.cpp +++ b/bench.cpp @@ -49,6 +49,7 @@ #include "mdc.h" #include "lubyrack.h" #include "tea.h" +#include "salsa.h" #include #include @@ -184,19 +185,19 @@ void BenchMark(const char *name, BufferedTransformation &bt, double timeTotal) //VC60 workaround: compiler bug triggered without the extra dummy parameters template -void BenchMarkKeyed(const char *name, double timeTotal, T *x=NULL) +void BenchMarkKeyed(const char *name, double timeTotal, const NameValuePairs ¶ms = g_nullNameValuePairs, T *x=NULL) { 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); } //VC60 workaround: compiler bug triggered without the extra dummy parameters template -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 ¶ms = g_nullNameValuePairs, T *x=NULL) { 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); } @@ -287,6 +288,10 @@ void BenchmarkAll(double t) BenchMarkKeyedVariable("Camellia (128-bit key)", t, 16); BenchMarkKeyedVariable("Camellia (256-bit key)", t, 32); #endif + BenchMarkKeyed("Salsa20", t); + BenchMarkKeyed("Salsa20/12", t, MakeParameters(Name::Rounds(), 12)); + BenchMarkKeyed("Salsa20/8", t, MakeParameters(Name::Rounds(), 8)); + BenchMarkKeyed("MD5-MAC", t); BenchMarkKeyed >("XMACC/MD5", t); BenchMarkKeyed >("HMAC/MD5", t); diff --git a/cryptest.vcproj b/cryptest.vcproj index 0cf74eb5..2620b162 100755 --- a/cryptest.vcproj +++ b/cryptest.vcproj @@ -1,4 +1,4 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -975,6 +984,15 @@ PreprocessorDefinitions="" /> + + + @@ -985,7 +1003,7 @@ /> - - - - - - + + + @@ -1051,6 +1060,15 @@ PreprocessorDefinitions="" /> + + + @@ -1061,7 +1079,7 @@ /> - - - - - - + + + @@ -1135,6 +1144,15 @@ PreprocessorDefinitions="" /> + + + @@ -1145,7 +1163,7 @@ /> - - - - - - + + + @@ -1211,6 +1220,15 @@ PreprocessorDefinitions="" /> + + + @@ -1221,7 +1239,7 @@ /> - - - - - - + + + @@ -1291,6 +1300,15 @@ PreprocessorDefinitions="" /> + + + @@ -1301,7 +1319,7 @@ /> - - - - - - + + + @@ -1367,6 +1376,15 @@ PreprocessorDefinitions="" /> + + + @@ -1377,7 +1395,7 @@ /> - - - - - - + + + @@ -1443,6 +1452,15 @@ PreprocessorDefinitions="" /> + + + @@ -1453,7 +1471,7 @@ /> - - - - - - + + + @@ -1519,6 +1528,15 @@ PreprocessorDefinitions="" /> + + + @@ -1529,7 +1547,7 @@ /> - - - - - - + + + @@ -1595,6 +1604,15 @@ PreprocessorDefinitions="" /> + + + @@ -1605,7 +1623,7 @@ /> - - - - - - + + + @@ -1671,6 +1680,15 @@ PreprocessorDefinitions="" /> + + + @@ -1681,7 +1699,7 @@ /> - - - - - - + + + @@ -9567,6 +9571,10 @@ RelativePath="safer.h" > + + diff --git a/datatest.cpp b/datatest.cpp index 79609e88..32b10fbf 100644 --- a/datatest.cpp +++ b/datatest.cpp @@ -265,6 +265,9 @@ void TestSymmetricCipher(TestData &v) { std::auto_ptr encryptor(ObjectFactoryRegistry::Registry().CreateObject(name.c_str())); encryptor->SetKey((const byte *)key.data(), key.size(), pairs); + int seek = pairs.GetIntValueWithDefault("Seek", 0); + if (seek) + encryptor->Seek(seek); std::string encrypted; StringSource ss(plaintext, true, new StreamTransformationFilter(*encryptor, new StringSink(encrypted), StreamTransformationFilter::NO_PADDING)); if (encrypted != ciphertext) @@ -274,6 +277,9 @@ void TestSymmetricCipher(TestData &v) { std::auto_ptr decryptor(ObjectFactoryRegistry::Registry().CreateObject(name.c_str())); decryptor->SetKey((const byte *)key.data(), key.size(), pairs); + int seek = pairs.GetIntValueWithDefault("Seek", 0); + if (seek) + decryptor->Seek(seek); std::string decrypted; StringSource ss(ciphertext, true, new StreamTransformationFilter(*decryptor, new StringSink(decrypted), StreamTransformationFilter::NO_PADDING)); if (decrypted != plaintext) diff --git a/regtest.cpp b/regtest.cpp index 05ff75e5..a59e0d41 100644 --- a/regtest.cpp +++ b/regtest.cpp @@ -19,6 +19,7 @@ #include "panama.h" #include "pssr.h" #include "aes.h" +#include "salsa.h" USING_NAMESPACE(CryptoPP) @@ -69,6 +70,7 @@ void RegisterFactories() RegisterSymmetricCipherDefaultFactories >(); RegisterSymmetricCipherDefaultFactories >(); RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories(); s_registered = true; } diff --git a/salsa.cpp b/salsa.cpp new file mode 100755 index 00000000..a3c18ef9 --- /dev/null +++ b/salsa.cpp @@ -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 ¶ms, 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 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 diff --git a/salsa.h b/salsa.h new file mode 100755 index 00000000..dd66d157 --- /dev/null +++ b/salsa.h @@ -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, public Salsa20_Info +{ +public: + unsigned int IVSize() const {return 8;} + void GetNextIV(byte *IV) const; + +protected: + void CipherSetKey(const NameValuePairs ¶ms, 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 m_state; +}; + +//! Salsa20, variable rounds: 8, 12 or 20 (default 20) +struct Salsa20 : public Salsa20_Info, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal >, Salsa20_Info> Encryption; + typedef Encryption Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/test.cpp b/test.cpp index 97785c8a..6a8f2646 100644 --- a/test.cpp +++ b/test.cpp @@ -811,6 +811,7 @@ bool Validate(int alg, bool thorough, const char *seed) case 61: result = ValidateCamellia(); break; case 62: result = ValidateWhirlpool(); break; case 63: result = ValidateTTMAC(); break; + case 64: result = ValidateSalsa(); break; default: result = ValidateAll(thorough); break; } diff --git a/validat1.cpp b/validat1.cpp index f337ca18..361aa9a1 100644 --- a/validat1.cpp +++ b/validat1.cpp @@ -91,6 +91,7 @@ bool ValidateAll(bool thorough) pass=ValidateSerpent() && pass; pass=ValidateSHACAL2() && pass; pass=ValidateCamellia() && pass; + pass=ValidateSalsa() && pass; pass=ValidateBBS() && pass; pass=ValidateDH() && pass; @@ -1307,3 +1308,10 @@ bool ValidateCamellia() return true; #endif } + +bool ValidateSalsa() +{ + cout << "\nSalsa validation suite running...\n"; + + return RunTestDataFile("TestVectors/salsa.txt"); +} diff --git a/validat3.cpp b/validat3.cpp index cfe989a8..437d1519 100644 --- a/validat3.cpp +++ b/validat3.cpp @@ -391,7 +391,7 @@ bool ValidateWhirlpool() cout << "word64 not available, skipping Whirlpool validation." << endl; return true; #endif - } +} bool ValidateMD5MAC() { diff --git a/validate.h b/validate.h index f77c67bc..d425b267 100644 --- a/validate.h +++ b/validate.h @@ -52,6 +52,7 @@ bool ValidateTwofish(); bool ValidateSerpent(); bool ValidateSHACAL2(); bool ValidateCamellia(); +bool ValidateSalsa(); bool ValidateBBS(); bool ValidateDH();