1 | // chacha.cpp - written and placed in the public domain by Jeffrey Walton. |
---|
2 | // Copyright assigned to the Crypto++ project. |
---|
3 | // Based on Wei Dai's Salsa20 and Bernstein's reference ChaCha |
---|
4 | // family implementation at http://cr.yp.to/chacha.html. |
---|
5 | |
---|
6 | #include "pch.h" |
---|
7 | #include "config.h" |
---|
8 | #include "chacha.h" |
---|
9 | #include "argnames.h" |
---|
10 | #include "misc.h" |
---|
11 | #include "cpu.h" |
---|
12 | |
---|
13 | NAMESPACE_BEGIN(CryptoPP) |
---|
14 | |
---|
15 | #define CHACHA_QUARTER_ROUND(a,b,c,d) \ |
---|
16 | a += b; d ^= a; d = rotlFixed<word32>(d,16); \ |
---|
17 | c += d; b ^= c; b = rotlFixed<word32>(b,12); \ |
---|
18 | a += b; d ^= a; d = rotlFixed<word32>(d, 8); \ |
---|
19 | c += d; b ^= c; b = rotlFixed<word32>(b, 7); |
---|
20 | |
---|
21 | #if CRYPTOPP_DEBUG && !defined(CRYPTOPP_DOXYGEN_PROCESSING) |
---|
22 | void ChaCha_TestInstantiations() |
---|
23 | { |
---|
24 | ChaCha8::Encryption x1; |
---|
25 | ChaCha12::Encryption x2; |
---|
26 | ChaCha20::Encryption x3; |
---|
27 | } |
---|
28 | #endif |
---|
29 | |
---|
30 | template <unsigned int R> |
---|
31 | void ChaCha_Policy<R>::CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length) |
---|
32 | { |
---|
33 | CRYPTOPP_UNUSED(params); |
---|
34 | CRYPTOPP_ASSERT(length == 16 || length == 32); |
---|
35 | |
---|
36 | // "expand 16-byte k" or "expand 32-byte k" |
---|
37 | m_state[0] = 0x61707865; |
---|
38 | m_state[1] = (length == 16) ? 0x3120646e : 0x3320646e; |
---|
39 | m_state[2] = (length == 16) ? 0x79622d36 : 0x79622d32; |
---|
40 | m_state[3] = 0x6b206574; |
---|
41 | |
---|
42 | GetBlock<word32, LittleEndian> get1(key); |
---|
43 | get1(m_state[4])(m_state[5])(m_state[6])(m_state[7]); |
---|
44 | |
---|
45 | GetBlock<word32, LittleEndian> get2(key + ((length == 32) ? 16 : 0)); |
---|
46 | get2(m_state[8])(m_state[9])(m_state[10])(m_state[11]); |
---|
47 | } |
---|
48 | |
---|
49 | template <unsigned int R> |
---|
50 | void ChaCha_Policy<R>::CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length) |
---|
51 | { |
---|
52 | CRYPTOPP_UNUSED(keystreamBuffer), CRYPTOPP_UNUSED(length); |
---|
53 | CRYPTOPP_ASSERT(length==8); |
---|
54 | |
---|
55 | GetBlock<word32, LittleEndian> get(IV); |
---|
56 | m_state[12] = m_state[13] = 0; |
---|
57 | get(m_state[14])(m_state[15]); |
---|
58 | } |
---|
59 | |
---|
60 | template<unsigned int R> |
---|
61 | void ChaCha_Policy<R>::SeekToIteration(lword iterationCount) |
---|
62 | { |
---|
63 | CRYPTOPP_UNUSED(iterationCount); |
---|
64 | throw NotImplemented(std::string(ChaCha_Info<R>::StaticAlgorithmName()) + ": SeekToIteration is not yet implemented"); |
---|
65 | |
---|
66 | // TODO: these were Salsa20, and Wei re-arranged the state array for SSE2 operations. |
---|
67 | // If we can generate some out-of-band test vectors, then test and implement. Also |
---|
68 | // see the test vectors in salsa.txt and the use of Seek test argument. |
---|
69 | // m_state[8] = (word32)iterationCount; |
---|
70 | // m_state[5] = (word32)SafeRightShift<32>(iterationCount); |
---|
71 | } |
---|
72 | |
---|
73 | template<unsigned int R> |
---|
74 | unsigned int ChaCha_Policy<R>::GetAlignment() const |
---|
75 | { |
---|
76 | #if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE && 0 |
---|
77 | if (HasSSE2()) |
---|
78 | return 16; |
---|
79 | else |
---|
80 | #endif |
---|
81 | return GetAlignmentOf<word32>(); |
---|
82 | } |
---|
83 | |
---|
84 | template<unsigned int R> |
---|
85 | unsigned int ChaCha_Policy<R>::GetOptimalBlockSize() const |
---|
86 | { |
---|
87 | #if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE && 0 |
---|
88 | if (HasSSE2()) |
---|
89 | return 4*BYTES_PER_ITERATION; |
---|
90 | else |
---|
91 | #endif |
---|
92 | return BYTES_PER_ITERATION; |
---|
93 | } |
---|
94 | |
---|
95 | template<unsigned int R> |
---|
96 | void ChaCha_Policy<R>::OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount) |
---|
97 | { |
---|
98 | word32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; |
---|
99 | |
---|
100 | while (iterationCount--) |
---|
101 | { |
---|
102 | x0 = m_state[0]; x1 = m_state[1]; x2 = m_state[2]; x3 = m_state[3]; |
---|
103 | x4 = m_state[4]; x5 = m_state[5]; x6 = m_state[6]; x7 = m_state[7]; |
---|
104 | x8 = m_state[8]; x9 = m_state[9]; x10 = m_state[10]; x11 = m_state[11]; |
---|
105 | x12 = m_state[12]; x13 = m_state[13]; x14 = m_state[14]; x15 = m_state[15]; |
---|
106 | |
---|
107 | for (int i = static_cast<int>(ROUNDS); i > 0; i -= 2) |
---|
108 | { |
---|
109 | CHACHA_QUARTER_ROUND(x0, x4, x8, x12); |
---|
110 | CHACHA_QUARTER_ROUND(x1, x5, x9, x13); |
---|
111 | CHACHA_QUARTER_ROUND(x2, x6, x10, x14); |
---|
112 | CHACHA_QUARTER_ROUND(x3, x7, x11, x15); |
---|
113 | |
---|
114 | CHACHA_QUARTER_ROUND(x0, x5, x10, x15); |
---|
115 | CHACHA_QUARTER_ROUND(x1, x6, x11, x12); |
---|
116 | CHACHA_QUARTER_ROUND(x2, x7, x8, x13); |
---|
117 | CHACHA_QUARTER_ROUND(x3, x4, x9, x14); |
---|
118 | } |
---|
119 | |
---|
120 | #undef CHACHA_OUTPUT |
---|
121 | #define CHACHA_OUTPUT(x){\ |
---|
122 | CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 0, x0 + m_state[0]);\ |
---|
123 | CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 1, x1 + m_state[1]);\ |
---|
124 | CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 2, x2 + m_state[2]);\ |
---|
125 | CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 3, x3 + m_state[3]);\ |
---|
126 | CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 4, x4 + m_state[4]);\ |
---|
127 | CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 5, x5 + m_state[5]);\ |
---|
128 | CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 6, x6 + m_state[6]);\ |
---|
129 | CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 7, x7 + m_state[7]);\ |
---|
130 | CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 8, x8 + m_state[8]);\ |
---|
131 | CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 9, x9 + m_state[9]);\ |
---|
132 | CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 10, x10 + m_state[10]);\ |
---|
133 | CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 11, x11 + m_state[11]);\ |
---|
134 | CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 12, x12 + m_state[12]);\ |
---|
135 | CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 13, x13 + m_state[13]);\ |
---|
136 | CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 14, x14 + m_state[14]);\ |
---|
137 | CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 15, x15 + m_state[15]);} |
---|
138 | |
---|
139 | #ifndef CRYPTOPP_DOXYGEN_PROCESSING |
---|
140 | CRYPTOPP_KEYSTREAM_OUTPUT_SWITCH(CHACHA_OUTPUT, BYTES_PER_ITERATION); |
---|
141 | #endif |
---|
142 | |
---|
143 | ++m_state[12]; |
---|
144 | m_state[13] += static_cast<word32>(m_state[12] == 0); |
---|
145 | } |
---|
146 | } |
---|
147 | |
---|
148 | template class ChaCha_Policy<8>; |
---|
149 | template class ChaCha_Policy<12>; |
---|
150 | template class ChaCha_Policy<20>; |
---|
151 | |
---|
152 | NAMESPACE_END |
---|
153 | |
---|