Crypto++ 8.7
Free C++ class library of cryptographic schemes
hc128.cpp
1// hc128.cpp - written and placed in the public domain by Jeffrey Walton
2// based on public domain code by Hongjun Wu.
3//
4// The reference materials and source files are available at
5// The eSTREAM Project, http://www.ecrypt.eu.org/stream/e2-hc128.html.
6
7#include "pch.h"
8#include "config.h"
9
10#include "hc128.h"
11#include "secblock.h"
12#include "misc.h"
13
14/*h1 function*/
15#define h1(x, y) { \
16 byte a,c; \
17 a = (byte) (x); \
18 c = (byte) ((x) >> 16); \
19 y = (m_T[512+a])+(m_T[512+256+c]); \
20}
21
22/*h2 function*/
23#define h2(x, y) { \
24 byte a,c; \
25 a = (byte) (x); \
26 c = (byte) ((x) >> 16); \
27 y = (m_T[a])+(m_T[256+c]); \
28}
29
30/*one step of HC-128, update P and generate 32 bits keystream*/
31#define step_P(u,v,a,b,c,d,n){ \
32 word32 tem0,tem1,tem2,tem3; \
33 h1(m_X[(d)],tem3); \
34 tem0 = rotrConstant<23>(m_T[(v)]); \
35 tem1 = rotrConstant<10>(m_X[(c)]); \
36 tem2 = rotrConstant<8>(m_X[(b)]); \
37 (m_T[(u)]) += tem2+(tem0 ^ tem1); \
38 (m_X[(a)]) = (m_T[(u)]); \
39 (n) = tem3 ^ (m_T[(u)]); \
40}
41
42/*one step of HC-128, update Q and generate 32 bits keystream*/
43#define step_Q(u,v,a,b,c,d,n){ \
44 word32 tem0,tem1,tem2,tem3; \
45 h2(m_Y[(d)],tem3); \
46 tem0 = rotrConstant<(32-23)>(m_T[(v)]); \
47 tem1 = rotrConstant<(32-10)>(m_Y[(c)]); \
48 tem2 = rotrConstant<(32-8)>(m_Y[(b)]); \
49 (m_T[(u)]) += tem2 + (tem0 ^ tem1); \
50 (m_Y[(a)]) = (m_T[(u)]); \
51 (n) = tem3 ^ (m_T[(u)]) ; \
52}
53
54/*update table P*/
55#define update_P(u,v,a,b,c,d){ \
56 word32 tem0,tem1,tem2,tem3; \
57 tem0 = rotrConstant<23>(m_T[(v)]); \
58 tem1 = rotrConstant<10>(m_X[(c)]); \
59 tem2 = rotrConstant<8>(m_X[(b)]); \
60 h1(m_X[(d)],tem3); \
61 (m_T[(u)]) = ((m_T[(u)]) + tem2+(tem0^tem1)) ^ tem3; \
62 (m_X[(a)]) = (m_T[(u)]); \
63}
64
65/*update table Q*/
66#define update_Q(u,v,a,b,c,d){ \
67 word32 tem0,tem1,tem2,tem3; \
68 tem0 = rotrConstant<(32-23)>(m_T[(v)]); \
69 tem1 = rotrConstant<(32-10)>(m_Y[(c)]); \
70 tem2 = rotrConstant<(32-8)>(m_Y[(b)]); \
71 h2(m_Y[(d)],tem3); \
72 (m_T[(u)]) = ((m_T[(u)]) + tem2+(tem0^tem1)) ^ tem3; \
73 (m_Y[(a)]) = (m_T[(u)]); \
74}
75
76ANONYMOUS_NAMESPACE_BEGIN
77
80
81inline word32 f1(word32 x)
82{
83 return rotrConstant<7>(x) ^ rotrConstant<18>(x) ^ ((x) >> 3);
84}
85
86inline word32 f2(word32 x)
87{
88 return rotrConstant<17>(x) ^ rotrConstant<19>(x) ^ ((x) >> 10);
89}
90
91ANONYMOUS_NAMESPACE_END
92
93NAMESPACE_BEGIN(CryptoPP)
94
95/*16 steps of HC-128, generate 512 bits keystream*/
96void HC128Policy::GenerateKeystream(word32 keystream[16])
97{
98 unsigned int cc = m_ctr & 0x1ff;
99 unsigned int dd = (cc + 16) & 0x1ff;
100
101 if (m_ctr < 512)
102 {
103 m_ctr = (m_ctr + 16) & 0x3ff;
104 step_P(cc + 0, cc + 1, 0, 6, 13, 4, keystream[0]);
105 step_P(cc + 1, cc + 2, 1, 7, 14, 5, keystream[1]);
106 step_P(cc + 2, cc + 3, 2, 8, 15, 6, keystream[2]);
107 step_P(cc + 3, cc + 4, 3, 9, 0, 7, keystream[3]);
108 step_P(cc + 4, cc + 5, 4, 10, 1, 8, keystream[4]);
109 step_P(cc + 5, cc + 6, 5, 11, 2, 9, keystream[5]);
110 step_P(cc + 6, cc + 7, 6, 12, 3, 10, keystream[6]);
111 step_P(cc + 7, cc + 8, 7, 13, 4, 11, keystream[7]);
112 step_P(cc + 8, cc + 9, 8, 14, 5, 12, keystream[8]);
113 step_P(cc + 9, cc + 10, 9, 15, 6, 13, keystream[9]);
114 step_P(cc + 10, cc + 11, 10, 0, 7, 14, keystream[10]);
115 step_P(cc + 11, cc + 12, 11, 1, 8, 15, keystream[11]);
116 step_P(cc + 12, cc + 13, 12, 2, 9, 0, keystream[12]);
117 step_P(cc + 13, cc + 14, 13, 3, 10, 1, keystream[13]);
118 step_P(cc + 14, cc + 15, 14, 4, 11, 2, keystream[14]);
119 step_P(cc + 15, dd + 0, 15, 5, 12, 3, keystream[15]);
120 }
121 else
122 {
123 m_ctr = (m_ctr + 16) & 0x3ff;
124 step_Q(512 + cc + 0, 512 + cc + 1, 0, 6, 13, 4, keystream[0]);
125 step_Q(512 + cc + 1, 512 + cc + 2, 1, 7, 14, 5, keystream[1]);
126 step_Q(512 + cc + 2, 512 + cc + 3, 2, 8, 15, 6, keystream[2]);
127 step_Q(512 + cc + 3, 512 + cc + 4, 3, 9, 0, 7, keystream[3]);
128 step_Q(512 + cc + 4, 512 + cc + 5, 4, 10, 1, 8, keystream[4]);
129 step_Q(512 + cc + 5, 512 + cc + 6, 5, 11, 2, 9, keystream[5]);
130 step_Q(512 + cc + 6, 512 + cc + 7, 6, 12, 3, 10, keystream[6]);
131 step_Q(512 + cc + 7, 512 + cc + 8, 7, 13, 4, 11, keystream[7]);
132 step_Q(512 + cc + 8, 512 + cc + 9, 8, 14, 5, 12, keystream[8]);
133 step_Q(512 + cc + 9, 512 + cc + 10, 9, 15, 6, 13, keystream[9]);
134 step_Q(512 + cc + 10, 512 + cc + 11, 10, 0, 7, 14, keystream[10]);
135 step_Q(512 + cc + 11, 512 + cc + 12, 11, 1, 8, 15, keystream[11]);
136 step_Q(512 + cc + 12, 512 + cc + 13, 12, 2, 9, 0, keystream[12]);
137 step_Q(512 + cc + 13, 512 + cc + 14, 13, 3, 10, 1, keystream[13]);
138 step_Q(512 + cc + 14, 512 + cc + 15, 14, 4, 11, 2, keystream[14]);
139 step_Q(512 + cc + 15, 512 + dd + 0, 15, 5, 12, 3, keystream[15]);
140 }
141}
142
143/*16 steps of HC-128, without generating keystream, */
144/*but use the outputs to update P and Q*/
145void HC128Policy::SetupUpdate() /*each time 16 steps*/
146{
147 unsigned int cc = m_ctr & 0x1ff;
148 unsigned int dd = (cc + 16) & 0x1ff;
149
150 if (m_ctr < 512)
151 {
152 m_ctr = (m_ctr + 16) & 0x3ff;
153 update_P(cc + 0, cc + 1, 0, 6, 13, 4);
154 update_P(cc + 1, cc + 2, 1, 7, 14, 5);
155 update_P(cc + 2, cc + 3, 2, 8, 15, 6);
156 update_P(cc + 3, cc + 4, 3, 9, 0, 7);
157 update_P(cc + 4, cc + 5, 4, 10, 1, 8);
158 update_P(cc + 5, cc + 6, 5, 11, 2, 9);
159 update_P(cc + 6, cc + 7, 6, 12, 3, 10);
160 update_P(cc + 7, cc + 8, 7, 13, 4, 11);
161 update_P(cc + 8, cc + 9, 8, 14, 5, 12);
162 update_P(cc + 9, cc + 10, 9, 15, 6, 13);
163 update_P(cc + 10, cc + 11, 10, 0, 7, 14);
164 update_P(cc + 11, cc + 12, 11, 1, 8, 15);
165 update_P(cc + 12, cc + 13, 12, 2, 9, 0);
166 update_P(cc + 13, cc + 14, 13, 3, 10, 1);
167 update_P(cc + 14, cc + 15, 14, 4, 11, 2);
168 update_P(cc + 15, dd + 0, 15, 5, 12, 3);
169 }
170 else
171 {
172 m_ctr = (m_ctr + 16) & 0x3ff;
173 update_Q(512 + cc + 0, 512 + cc + 1, 0, 6, 13, 4);
174 update_Q(512 + cc + 1, 512 + cc + 2, 1, 7, 14, 5);
175 update_Q(512 + cc + 2, 512 + cc + 3, 2, 8, 15, 6);
176 update_Q(512 + cc + 3, 512 + cc + 4, 3, 9, 0, 7);
177 update_Q(512 + cc + 4, 512 + cc + 5, 4, 10, 1, 8);
178 update_Q(512 + cc + 5, 512 + cc + 6, 5, 11, 2, 9);
179 update_Q(512 + cc + 6, 512 + cc + 7, 6, 12, 3, 10);
180 update_Q(512 + cc + 7, 512 + cc + 8, 7, 13, 4, 11);
181 update_Q(512 + cc + 8, 512 + cc + 9, 8, 14, 5, 12);
182 update_Q(512 + cc + 9, 512 + cc + 10, 9, 15, 6, 13);
183 update_Q(512 + cc + 10, 512 + cc + 11, 10, 0, 7, 14);
184 update_Q(512 + cc + 11, 512 + cc + 12, 11, 1, 8, 15);
185 update_Q(512 + cc + 12, 512 + cc + 13, 12, 2, 9, 0);
186 update_Q(512 + cc + 13, 512 + cc + 14, 13, 3, 10, 1);
187 update_Q(512 + cc + 14, 512 + cc + 15, 14, 4, 11, 2);
188 update_Q(512 + cc + 15, 512 + dd + 0, 15, 5, 12, 3);
189 }
190}
191
192void HC128Policy::CipherSetKey(const NameValuePairs &params, const byte *userKey, size_t keylen)
193{
194 CRYPTOPP_UNUSED(params);
195
196 GetUserKey(LITTLE_ENDIAN_ORDER, m_key.begin(), 4, userKey, keylen);
197 for (unsigned int i = 4; i < 8; i++)
198 m_key[i] = m_key[i - 4];
199}
200
201void HC128Policy::OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount)
202{
203 while (iterationCount--)
204 {
205 word32 keystream[16];
206 GenerateKeystream(keystream);
207
208 PutWord(false, LITTLE_ENDIAN_ORDER, output + 0, keystream[0]);
209 PutWord(false, LITTLE_ENDIAN_ORDER, output + 4, keystream[1]);
210 PutWord(false, LITTLE_ENDIAN_ORDER, output + 8, keystream[2]);
211 PutWord(false, LITTLE_ENDIAN_ORDER, output + 12, keystream[3]);
212 PutWord(false, LITTLE_ENDIAN_ORDER, output + 16, keystream[4]);
213 PutWord(false, LITTLE_ENDIAN_ORDER, output + 20, keystream[5]);
214 PutWord(false, LITTLE_ENDIAN_ORDER, output + 24, keystream[6]);
215 PutWord(false, LITTLE_ENDIAN_ORDER, output + 28, keystream[7]);
216
217 PutWord(false, LITTLE_ENDIAN_ORDER, output + 32, keystream[8]);
218 PutWord(false, LITTLE_ENDIAN_ORDER, output + 36, keystream[9]);
219 PutWord(false, LITTLE_ENDIAN_ORDER, output + 40, keystream[10]);
220 PutWord(false, LITTLE_ENDIAN_ORDER, output + 44, keystream[11]);
221 PutWord(false, LITTLE_ENDIAN_ORDER, output + 48, keystream[12]);
222 PutWord(false, LITTLE_ENDIAN_ORDER, output + 52, keystream[13]);
223 PutWord(false, LITTLE_ENDIAN_ORDER, output + 56, keystream[14]);
224 PutWord(false, LITTLE_ENDIAN_ORDER, output + 60, keystream[15]);
225
226 // If AdditiveCipherTemplate does not have an accumulated keystream
227 // then it will ask OperateKeystream to generate one. Optionally it
228 // will ask for an XOR of the input with the keystream while
229 // writing the result to the output buffer. In all cases the
230 // keystream is written to the output buffer. The optional part is
231 // adding the input buffer and keystream.
232 if ((operation & EnumToInt(INPUT_NULL)) != EnumToInt(INPUT_NULL))
233 {
234 xorbuf(output, input, BYTES_PER_ITERATION);
235 input += BYTES_PER_ITERATION;
236 }
237
238 output += BYTES_PER_ITERATION;
239 }
240}
241
242void HC128Policy::CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length)
243{
244 CRYPTOPP_UNUSED(keystreamBuffer);
245
246 GetUserKey(LITTLE_ENDIAN_ORDER, m_iv.begin(), 4, iv, length);
247 for (unsigned int i = 4; i < 8; i++)
248 m_iv[i] = m_iv[i - 4];
249
250 /* expand the key and IV into the table T */
251 /* (expand the key and IV into the table P and Q) */
252
253 for (unsigned int i = 0; i < 8; i++)
254 m_T[i] = m_key[i];
255 for (unsigned int i = 8; i < 16; i++)
256 m_T[i] = m_iv[i - 8];
257
258 for (unsigned int i = 16; i < (256 + 16); i++)
259 m_T[i] = f2(m_T[i - 2]) + m_T[i - 7] + f1(m_T[i - 15]) + m_T[i - 16] + i;
260
261 for (unsigned int i = 0; i < 16; i++)
262 m_T[i] = m_T[256 + i];
263
264 for (unsigned int i = 16; i < 1024; i++)
265 m_T[i] = f2(m_T[i - 2]) + m_T[i - 7] + f1(m_T[i - 15]) + m_T[i - 16] + 256 + i;
266
267 /* initialize counter1024, X and Y */
268 m_ctr = 0;
269 for (unsigned int i = 0; i < 16; i++)
270 m_X[i] = m_T[512 - 16 + i];
271 for (unsigned int i = 0; i < 16; i++)
272 m_Y[i] = m_T[512 + 512 - 16 + i];
273
274 /* run the cipher 1024 steps before generating the output */
275 for (unsigned int i = 0; i < 64; i++)
276 SetupUpdate();
277}
278
279NAMESPACE_END
Interface for retrieving values given their names.
Definition: cryptlib.h:322
iterator begin()
Provides an iterator pointing to the first element in the memory block.
Definition: secblock.h:836
Library configuration file.
unsigned int word32
32-bit unsigned datatype
Definition: config_int.h:62
@ LITTLE_ENDIAN_ORDER
byte order is little-endian
Definition: cryptlib.h:145
Classes for HC-128 stream cipher.
Utility functions for the Crypto++ library.
T rotrConstant(T x)
Performs a right rotate.
Definition: misc.h:1574
void GetUserKey(ByteOrder order, T *out, size_t outlen, const byte *in, size_t inlen)
Copy bytes in a buffer to an array of elements in big-endian order.
Definition: misc.h:2291
#define EnumToInt(v)
Integer value.
Definition: misc.h:502
void PutWord(bool assumeAligned, ByteOrder order, byte *block, T value, const byte *xorBlock=NULL)
Access a block of memory.
Definition: misc.h:2739
CRYPTOPP_DLL void xorbuf(byte *buf, const byte *mask, size_t count)
Performs an XOR of a buffer with a mask.
Crypto++ library namespace.
Precompiled header file.
Classes and functions for secure memory allocations.
KeystreamOperation
Keystream operation flags.
Definition: strciphr.h:88
@ INPUT_NULL
Input buffer is NULL.
Definition: strciphr.h:82
static const int BYTES_PER_ITERATION
Number of bytes for an iteration.
Definition: strciphr.h:211