Add IETF XChaCha (GH #727, PR #794)

This commit is contained in:
Jeffrey Walton 2019-02-06 01:03:28 -05:00 committed by GitHub
parent 48531785b7
commit 26c83877ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 286 additions and 21 deletions

View File

@ -549,6 +549,7 @@ TestVectors/ttmac.txt
TestVectors/vmac.txt
TestVectors/wake.txt
TestVectors/whrlpool.txt
TestVectors/xchacha.txt
TestPrograms/test_32bit.cxx
TestPrograms/test_64bit.cxx
TestPrograms/test_arm_acle.cxx

View File

@ -9,6 +9,7 @@ Test: TestVectors/ccm.txt
Test: TestVectors/chacha_tls.txt
Test: TestVectors/chacha20poly1305.txt
Test: TestVectors/chacha.txt
Test: TestVectors/xchacha.txt
Test: TestVectors/cham.txt
Test: TestVectors/cmac.txt
Test: TestVectors/dlies.txt

75
TestVectors/xchacha.txt Normal file
View File

@ -0,0 +1,75 @@
AlgorithmType: SymmetricCipher
Name: XChaCha20
Source: https://tools.ietf.org/html/draft-arciszewski-xchacha
#
Comment: A.2. Example and Test Vector for XChaCha20
Key: 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f \
90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f
IV: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f \
50 51 52 53 54 55 56 58
Plaintext: r304 00
Ciphertext: 29 62 4b 4b 1b 14 0a ce 53 74 0e 40 5b 21 68 54 \
0f d7 d6 30 c1 f5 36 fe cd 72 2f c3 cd db a7 f4 \
cc a9 8c f9 e4 7e 5e 64 d1 15 45 0f 9b 12 5b 54 \
44 9f f7 61 41 ca 62 0a 1f 9c fc ab 2a 1a 8a 25 \
5e 76 6a 52 66 b8 78 84 61 20 ea 64 ad 99 aa 47 \
94 71 e6 3b ef cb d3 7c d1 c2 2a 22 1f e4 62 21 \
5c f3 2c 74 89 5b f5 05 86 3c cd dd 48 f6 29 16 \
dc 65 21 f1 ec 50 a5 ae 08 90 3a a2 59 d9 bf 60 \
7c d8 02 6f ba 54 86 04 f1 b6 07 2d 91 bc 91 24 \
3a 5b 84 5f 7f d1 71 b0 2e dc 5a 0a 84 cf 28 dd \
24 11 46 bc 37 6e 3f 48 df 5e 7f ee 1d 11 04 8c \
19 0a 3d 3d eb 0f eb 64 b4 2d 9c 6f de ee 29 0f \
a0 e6 ae 2c 26 c0 24 9e a8 c1 81 f7 e2 ff d1 00 \
cb e5 fd 3c 4f 82 71 d6 2b 15 33 0c b8 fd cf 00 \
b3 df 50 7c a8 c9 24 f7 01 7b 7e 71 2d 15 a2 eb \
5c 50 48 44 51 e5 4e 1b 4b 99 5b d8 fd d9 45 97 \
bb 94 d7 af 0b 2c 04 df 10 ba 08 90 89 9e d9 29 \
3a 0f 55 b8 ba fa 99 92 64 03 5f 1d 4f be 7f e0 \
aa fa 10 9a 62 37 20 27 e5 0e 10 cd fe cc a1 27
Test: Encrypt
#
Comment: A.2. Example and Test Vector for XChaCha20
Key: 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f \
90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f
IV: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f \
50 51 52 53 54 55 56 58
Plaintext: 54 68 65 20 64 68 6f 6c 65 20 28 70 72 6f 6e 6f \
75 6e 63 65 64 20 22 64 6f 6c 65 22 29 20 69 73 \
20 61 6c 73 6f 20 6b 6e 6f 77 6e 20 61 73 20 74 \
68 65 20 41 73 69 61 74 69 63 20 77 69 6c 64 20 \
64 6f 67 2c 20 72 65 64 20 64 6f 67 2c 20 61 6e \
64 20 77 68 69 73 74 6c 69 6e 67 20 64 6f 67 2e \
20 49 74 20 69 73 20 61 62 6f 75 74 20 74 68 65 \
20 73 69 7a 65 20 6f 66 20 61 20 47 65 72 6d 61 \
6e 20 73 68 65 70 68 65 72 64 20 62 75 74 20 6c \
6f 6f 6b 73 20 6d 6f 72 65 20 6c 69 6b 65 20 61 \
20 6c 6f 6e 67 2d 6c 65 67 67 65 64 20 66 6f 78 \
2e 20 54 68 69 73 20 68 69 67 68 6c 79 20 65 6c \
75 73 69 76 65 20 61 6e 64 20 73 6b 69 6c 6c 65 \
64 20 6a 75 6d 70 65 72 20 69 73 20 63 6c 61 73 \
73 69 66 69 65 64 20 77 69 74 68 20 77 6f 6c 76 \
65 73 2c 20 63 6f 79 6f 74 65 73 2c 20 6a 61 63 \
6b 61 6c 73 2c 20 61 6e 64 20 66 6f 78 65 73 20 \
69 6e 20 74 68 65 20 74 61 78 6f 6e 6f 6d 69 63 \
20 66 61 6d 69 6c 79 20 43 61 6e 69 64 61 65 2e
Ciphertext: 7d 0a 2e 6b 7f 7c 65 a2 36 54 26 30 29 4e 06 3b \
7a b9 b5 55 a5 d5 14 9a a2 1e 4a e1 e4 fb ce 87 \
ec c8 e0 8a 8b 5e 35 0a be 62 2b 2f fa 61 7b 20 \
2c fa d7 20 32 a3 03 7e 76 ff dc dc 43 76 ee 05 \
3a 19 0d 7e 46 ca 1d e0 41 44 85 03 81 b9 cb 29 \
f0 51 91 53 86 b8 a7 10 b8 ac 4d 02 7b 8b 05 0f \
7c ba 58 54 e0 28 d5 64 e4 53 b8 a9 68 82 41 73 \
fc 16 48 8b 89 70 ca c8 28 f1 1a e5 3c ab d2 01 \
12 f8 71 07 df 24 ee 61 83 d2 27 4f e4 c8 b1 48 \
55 34 ef 2c 5f bc 1e c2 4b fc 36 63 ef aa 08 bc \
04 7d 29 d2 50 43 53 2d b8 39 1a 8a 3d 77 6b f4 \
37 2a 69 55 82 7c cb 0c dd 4a f4 03 a7 ce 4c 63 \
d5 95 c7 5a 43 e0 45 f0 cc e1 f2 9c 8b 93 bd 65 \
af c5 97 49 22 f2 14 a4 0b 7c 40 2c db 91 ae 73 \
c0 b6 36 15 cd ad 04 80 68 0f 16 51 5a 7a ce 9d \
39 23 64 64 32 8a 37 74 3f fc 28 f4 dd b3 24 f4 \
d0 f5 bb dc 27 0c 65 b1 74 9a 6e ff f1 fb aa 09 \
53 61 75 cc d2 9f b9 e6 05 7b 30 73 20 d3 16 83 \
8a 9c 71 f7 0b 5b 59 07 a6 6f 7e a4 9a ad c4 09
Test: Encrypt

View File

@ -142,7 +142,7 @@ void Benchmark2(double t, double hertz)
BenchMarkByName<SymmetricCipher>("ChaCha", 0, "ChaCha20");
BenchMarkByName<SymmetricCipher>("ChaCha", 0, "ChaCha12", MakeParameters(Name::Rounds(), 12));
BenchMarkByName<SymmetricCipher>("ChaCha", 0, "ChaCha8", MakeParameters(Name::Rounds(), 8));
BenchMarkByName<SymmetricCipher>("ChaChaTLS", 0, "ChaChaTLS");
BenchMarkByName<SymmetricCipher>("ChaChaTLS");
BenchMarkByName<SymmetricCipher>("Sosemanuk");
BenchMarkByName<SymmetricCipher>("Rabbit");
BenchMarkByName<SymmetricCipher>("RabbitWithIV");

View File

@ -39,6 +39,7 @@ void ChaCha_TestInstantiations()
{
ChaCha::Encryption x;
ChaChaTLS::Encryption y;
XChaCha20::Encryption z;
}
#endif
@ -218,9 +219,35 @@ void ChaCha_OperateKeystream(KeystreamOperation operation,
// We may re-enter a SIMD keystream operation from here.
} while (iterationCount--);
}
#undef CHACHA_QUARTER_ROUND
#undef CHACHA_OUTPUT
// XChaCha key derivation
void HChaCha_OperateKeystream(const word32 state[16], word32 output[8])
{
word32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
x0 = state[0]; x1 = state[1]; x2 = state[2]; x3 = state[3];
x4 = state[4]; x5 = state[5]; x6 = state[6]; x7 = state[7];
x8 = state[8]; x9 = state[9]; x10 = state[10]; x11 = state[11];
x12 = state[12]; x13 = state[13]; x14 = state[14]; x15 = state[15];
for (int i = 20; i > 0; i -= 2)
{
CHACHA_QUARTER_ROUND(x0, x4, x8, x12);
CHACHA_QUARTER_ROUND(x1, x5, x9, x13);
CHACHA_QUARTER_ROUND(x2, x6, x10, x14);
CHACHA_QUARTER_ROUND(x3, x7, x11, x15);
CHACHA_QUARTER_ROUND(x0, x5, x10, x15);
CHACHA_QUARTER_ROUND(x1, x6, x11, x12);
CHACHA_QUARTER_ROUND(x2, x7, x8, x13);
CHACHA_QUARTER_ROUND(x3, x4, x9, x14);
}
output[0] = x0; output[1] = x1;
output[2] = x2; output[3] = x3;
output[4] = x12; output[5] = x13;
output[6] = x14; output[7] = x15;
}
std::string ChaCha_AlgorithmProvider()
@ -398,19 +425,14 @@ void ChaChaTLS_Policy::CipherSetKey(const NameValuePairs &params, const byte *ke
// the function, so we have to use the heavier-weight SetKey to change it.
word64 block;
if (params.GetValue("InitialBlock", block))
m_state[16] = static_cast<word32>(block);
m_state[CTR] = static_cast<word32>(block);
else
m_state[16] = 0;
// State words are defined in RFC 8439, Section 2.3.
m_state[0] = 0x61707865;
m_state[1] = 0x3320646e;
m_state[2] = 0x79622d32;
m_state[3] = 0x6b206574;
m_state[CTR] = 0;
// State words are defined in RFC 8439, Section 2.3. Key is 32-bytes.
GetBlock<word32, LittleEndian> get(key);
get(m_state[4])(m_state[5])(m_state[6])(m_state[7])(m_state[8])(m_state[9])(m_state[10])(m_state[11]);
get(m_state[KEY+0])(m_state[KEY+1])(m_state[KEY+2])(m_state[KEY+3])
(m_state[KEY+4])(m_state[KEY+5])(m_state[KEY+6])(m_state[KEY+7]);
}
void ChaChaTLS_Policy::CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length)
@ -418,9 +440,16 @@ void ChaChaTLS_Policy::CipherResynchronize(byte *keystreamBuffer, const byte *IV
CRYPTOPP_UNUSED(keystreamBuffer), CRYPTOPP_UNUSED(length);
CRYPTOPP_ASSERT(length==12);
// State words are defined in RFC 8439, Section 2.3.
m_state[0] = 0x61707865; m_state[1] = 0x3320646e;
m_state[2] = 0x79622d32; m_state[3] = 0x6b206574;
// Copy saved key into state
std::memcpy(m_state+4, m_state+KEY, 8*sizeof(word32));
// State words are defined in RFC 8439, Section 2.3
GetBlock<word32, LittleEndian> get(IV);
m_state[12] = m_state[16];
m_state[12] = m_state[CTR];
get(m_state[13])(m_state[14])(m_state[15]);
}
@ -461,4 +490,92 @@ void ChaChaTLS_Policy::OperateKeystream(KeystreamOperation operation,
CRYPTOPP_ASSERT(discard==0);
}
////////////////////////////// IETF XChaCha20 //////////////////////////////
std::string XChaCha20_Policy::AlgorithmName() const
{
return std::string("XChaCha20");
}
std::string XChaCha20_Policy::AlgorithmProvider() const
{
return ChaCha_AlgorithmProvider();
}
void XChaCha20_Policy::CipherSetKey(const NameValuePairs &params, const byte *key, size_t length)
{
CRYPTOPP_ASSERT(key); CRYPTOPP_ASSERT(length == 32);
// XChaCha20 is always 20 rounds. Fetch Rounds() to avoid a spurious failure.
int rounds = params.GetIntValueWithDefault(Name::Rounds(), ROUNDS);
if (rounds != 20)
throw InvalidRounds(XChaCha20::StaticAlgorithmName(), rounds);
word64 block;
if (params.GetValue("InitialBlock", block))
m_state[CTR] = static_cast<word32>(block);
else
m_state[CTR] = 1;
// Stash key away for use in CipherResynchronize
GetBlock<word32, LittleEndian> get(key);
get(m_state[KEY+0])(m_state[KEY+1])(m_state[KEY+2])(m_state[KEY+3])
(m_state[KEY+4])(m_state[KEY+5])(m_state[KEY+6])(m_state[KEY+7]);
}
void XChaCha20_Policy::CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length)
{
CRYPTOPP_UNUSED(keystreamBuffer), CRYPTOPP_UNUSED(length);
CRYPTOPP_ASSERT(length==24);
// HChaCha derivation
m_state[0] = 0x61707865; m_state[1] = 0x3320646e;
m_state[2] = 0x79622d32; m_state[3] = 0x6b206574;
// Copy saved key into state
std::memcpy(m_state+4, m_state+KEY, 8*sizeof(word32));
GetBlock<word32, LittleEndian> get(iv);
get(m_state[12])(m_state[13])(m_state[14])(m_state[15]);
// Operate the keystream without adding state back in.
// This function also gathers the key words into a
// contiguous 8-word block.
HChaCha_OperateKeystream(m_state, m_state+4);
// XChaCha state
m_state[0] = 0x61707865; m_state[1] = 0x3320646e;
m_state[2] = 0x79622d32; m_state[3] = 0x6b206574;
// Setup new IV
m_state[12] = m_state[CTR];
m_state[13] = 0;
m_state[14] = GetWord<word32>(false, LITTLE_ENDIAN_ORDER, iv+16);
m_state[15] = GetWord<word32>(false, LITTLE_ENDIAN_ORDER, iv+20);
}
void XChaCha20_Policy::SeekToIteration(lword iterationCount)
{
// Should we throw here??? XChaCha does not have a block
// counter, so I'm not sure how to seek on it.
CRYPTOPP_ASSERT(0);
}
unsigned int XChaCha20_Policy::GetAlignment() const
{
return ChaCha_GetAlignment();
}
unsigned int XChaCha20_Policy::GetOptimalBlockSize() const
{
return ChaCha_GetOptimalBlockSize();
}
void XChaCha20_Policy::OperateKeystream(KeystreamOperation operation,
byte *output, const byte *input, size_t iterationCount)
{
ChaCha_OperateKeystream(operation, m_state, m_state[12], m_state[13],
ROUNDS, output, input, iterationCount);
}
NAMESPACE_END

View File

@ -5,10 +5,10 @@
// The library added Bernstein's ChaCha classses at Crypto++ 5.6.4. The IETF
// uses a slightly different implementation than Bernstein, and the IETF
// classes were added at Crypto++ 8.1. We wanted to maintain ABI compatibility
// at the 8.1 release so the original ChaCha classes were not disturbed.
// Instead new classes were added for IETF ChaCha. The back-end implementation
// shares code as expected, however.
// ChaCha and XChaCha classes were added at Crypto++ 8.1. We wanted to maintain
// ABI compatibility at the 8.1 release so the original ChaCha classes were not
// disturbed. Instead new classes were added for IETF ChaCha. The back-end
// implementation shares code as expected, however.
/// \file chacha.h
/// \brief Classes for ChaCha8, ChaCha12 and ChaCha20 stream ciphers
@ -20,8 +20,11 @@
/// implementation for cipher suites
/// <tt>TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256</tt>,
/// <tt>TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256</tt>,
/// and <tt>TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256</tt>.
/// \since ChaCha since Crypto++ 5.6.4, ChaChaTLS since Crypto++ 8.1
/// and <tt>TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256</tt>. Finally,
/// the library provides <a
/// href="https://tools.ietf.org/html/draft-arciszewski-xchacha">XChaCha:
/// eXtended-nonce ChaCha and AEAD_XChaCha20_Poly1305 (rev. 03)</a>.
/// \since ChaCha since Crypto++ 5.6.4, ChaChaTLS and XChaCha20 since Crypto++ 8.1
#ifndef CRYPTOPP_CHACHA_H
#define CRYPTOPP_CHACHA_H
@ -81,7 +84,9 @@ protected:
/// \since Crypto++ 5.6.4
struct ChaCha : public ChaCha_Info, public SymmetricCipherDocumentation
{
/// \brief ChaCha Encryption
typedef SymmetricCipherFinal<ConcretePolicyHolder<ChaCha_Policy, AdditiveCipherTemplate<> >, ChaCha_Info > Encryption;
/// \brief ChaCha Decryption
typedef Encryption Decryption;
};
@ -123,8 +128,10 @@ protected:
std::string AlgorithmName() const;
std::string AlgorithmProvider() const;
FixedSizeAlignedSecBlock<word32, 16+1> m_state;
FixedSizeAlignedSecBlock<word32, 16+8+1> m_state;
CRYPTOPP_CONSTANT(ROUNDS = ChaChaTLS_Info::ROUNDS)
CRYPTOPP_CONSTANT(KEY = 16) // Index into m_state
CRYPTOPP_CONSTANT(CTR = 24) // Index into m_state
};
/// \brief ChaCha-TLS stream cipher
@ -136,14 +143,76 @@ protected:
/// <tt>TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256</tt>, and
/// <tt>TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256</tt>.
/// \sa <a href="https://tools.ietf.org/html/rfc8439">RFC 8439, ChaCha20 and
/// Poly1305 for IETF Protocols</a>, <A HREF="https://mailarchive.ietf.org/arch/msg/cfrg/gsOnTJzcbgG6OqD8Sc0GO5aR_tU">How
/// Poly1305 for IETF Protocols</a>, <A
/// HREF="https://mailarchive.ietf.org/arch/msg/cfrg/gsOnTJzcbgG6OqD8Sc0GO5aR_tU">How
/// to handle block counter wrap in IETF's ChaCha algorithm?</A> and
/// <A HREF="https://github.com/weidai11/cryptopp/issues/790">Issue
/// 790, ChaChaTLS results when counter block wraps</A>.
/// \since Crypto++ 8.1
struct ChaChaTLS : public ChaChaTLS_Info, public SymmetricCipherDocumentation
{
/// \brief ChaCha-TLS Encryption
typedef SymmetricCipherFinal<ConcretePolicyHolder<ChaChaTLS_Policy, AdditiveCipherTemplate<> >, ChaChaTLS_Info > Encryption;
/// \brief ChaCha-TLS Decryption
typedef Encryption Decryption;
};
////////////////////////////// IETF XChaCha20 draft //////////////////////////////
/// \brief XChaCha stream cipher information
/// \since Crypto++ 8.1
struct XChaCha20_Info : public FixedKeyLength<32, SimpleKeyingInterface::UNIQUE_IV, 24>, FixedRounds<20>
{
/// \brief The algorithm name
/// \returns the algorithm name
/// \details StaticAlgorithmName returns the algorithm's name as a static
/// member function.
/// \details This is the IETF's XChaCha from draft-arciszewski-xchacha.
static const char* StaticAlgorithmName() {
return "XChaCha20";
}
};
/// \brief XChaCha stream cipher implementation
/// \since Crypto++ 8.1
class CRYPTOPP_NO_VTABLE XChaCha20_Policy : public AdditiveCipherConcretePolicy<word32, 16>
{
public:
virtual ~XChaCha20_Policy() {}
XChaCha20_Policy() {}
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, size_t length);
bool CipherIsRandomAccess() const {return false;}
void SeekToIteration(lword iterationCount);
unsigned int GetAlignment() const;
unsigned int GetOptimalBlockSize() const;
std::string AlgorithmName() const;
std::string AlgorithmProvider() const;
FixedSizeAlignedSecBlock<word32, 16+8+1> m_state;
CRYPTOPP_CONSTANT(ROUNDS = XChaCha20_Info::ROUNDS)
CRYPTOPP_CONSTANT(KEY = 16) // Index into m_state
CRYPTOPP_CONSTANT(CTR = 24) // Index into m_state
};
/// \brief XChaCha stream cipher
/// \details This is the IETF's XChaCha from draft-arciszewski-xchacha.
/// \sa <a href="https://tools.ietf.org/html/draft-arciszewski-xchacha">XChaCha:
/// eXtended-nonce ChaCha and AEAD_XChaCha20_Poly1305 (rev. 03)</a>, <A
/// HREF="https://mailarchive.ietf.org/arch/msg/cfrg/gsOnTJzcbgG6OqD8Sc0GO5aR_tU">How
/// to handle block counter wrap in IETF's ChaCha algorithm?</A> and
/// <A HREF="https://github.com/weidai11/cryptopp/issues/790">Issue
/// 790, ChaCha20 results when counter block wraps</A>.
/// \since Crypto++ 8.1
struct XChaCha20 : public XChaCha20_Info, public SymmetricCipherDocumentation
{
/// \brief XChaCha Encryption
typedef SymmetricCipherFinal<ConcretePolicyHolder<XChaCha20_Policy, AdditiveCipherTemplate<> >, XChaCha20_Info > Encryption;
/// \brief XChaCha Decryption
typedef Encryption Decryption;
};

View File

@ -23,6 +23,7 @@
#include "sha3.h"
#include "blake2.h"
#include "ripemd.h"
#include "chacha.h"
#include "poly1305.h"
#include "siphash.h"
#include "panama.h"
@ -95,6 +96,7 @@ void RegisterFactories3()
RegisterSymmetricCipherDefaultFactories<XSalsa20>();
RegisterSymmetricCipherDefaultFactories<ChaCha>();
RegisterSymmetricCipherDefaultFactories<ChaChaTLS>();
RegisterSymmetricCipherDefaultFactories<XChaCha20>();
RegisterSymmetricCipherDefaultFactories<Sosemanuk>();
RegisterSymmetricCipherDefaultFactories<Rabbit>();
RegisterSymmetricCipherDefaultFactories<RabbitWithIV>();