Crypto++ 8.9
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 "strciphr.h"
13#include "misc.h"
14
15/*h1 function*/
16#define h1(x, y) { \
17 byte a,c; \
18 a = (byte) (x); \
19 c = (byte) ((x) >> 16); \
20 y = (m_T[512+a])+(m_T[512+256+c]); \
21}
22
23/*h2 function*/
24#define h2(x, y) { \
25 byte a,c; \
26 a = (byte) (x); \
27 c = (byte) ((x) >> 16); \
28 y = (m_T[a])+(m_T[256+c]); \
29}
30
31/*one step of HC-128, update P and generate 32 bits keystream*/
32#define step_P(u,v,a,b,c,d,n){ \
33 word32 tem0,tem1,tem2,tem3; \
34 h1(m_X[(d)],tem3); \
35 tem0 = rotrConstant<23>(m_T[(v)]); \
36 tem1 = rotrConstant<10>(m_X[(c)]); \
37 tem2 = rotrConstant<8>(m_X[(b)]); \
38 (m_T[(u)]) += tem2+(tem0 ^ tem1); \
39 (m_X[(a)]) = (m_T[(u)]); \
40 (n) = tem3 ^ (m_T[(u)]); \
41}
42
43/*one step of HC-128, update Q and generate 32 bits keystream*/
44#define step_Q(u,v,a,b,c,d,n){ \
45 word32 tem0,tem1,tem2,tem3; \
46 h2(m_Y[(d)],tem3); \
47 tem0 = rotrConstant<(32-23)>(m_T[(v)]); \
48 tem1 = rotrConstant<(32-10)>(m_Y[(c)]); \
49 tem2 = rotrConstant<(32-8)>(m_Y[(b)]); \
50 (m_T[(u)]) += tem2 + (tem0 ^ tem1); \
51 (m_Y[(a)]) = (m_T[(u)]); \
52 (n) = tem3 ^ (m_T[(u)]) ; \
53}
54
55/*update table P*/
56#define update_P(u,v,a,b,c,d){ \
57 word32 tem0,tem1,tem2,tem3; \
58 tem0 = rotrConstant<23>(m_T[(v)]); \
59 tem1 = rotrConstant<10>(m_X[(c)]); \
60 tem2 = rotrConstant<8>(m_X[(b)]); \
61 h1(m_X[(d)],tem3); \
62 (m_T[(u)]) = ((m_T[(u)]) + tem2+(tem0^tem1)) ^ tem3; \
63 (m_X[(a)]) = (m_T[(u)]); \
64}
65
66/*update table Q*/
67#define update_Q(u,v,a,b,c,d){ \
68 word32 tem0,tem1,tem2,tem3; \
69 tem0 = rotrConstant<(32-23)>(m_T[(v)]); \
70 tem1 = rotrConstant<(32-10)>(m_Y[(c)]); \
71 tem2 = rotrConstant<(32-8)>(m_Y[(b)]); \
72 h2(m_Y[(d)],tem3); \
73 (m_T[(u)]) = ((m_T[(u)]) + tem2+(tem0^tem1)) ^ tem3; \
74 (m_Y[(a)]) = (m_T[(u)]); \
75}
76
77#define BYTES_PER_ITERATION 64
78
79#define WordType word32
80
81#define HC128_OUTPUT(x){\
82 CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 0, keystream[ 0]);\
83 CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 1, keystream[ 1]);\
84 CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 2, keystream[ 2]);\
85 CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 3, keystream[ 3]);\
86 CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 4, keystream[ 4]);\
87 CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 5, keystream[ 5]);\
88 CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 6, keystream[ 6]);\
89 CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 7, keystream[ 7]);\
90 CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 8, keystream[ 8]);\
91 CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 9, keystream[ 9]);\
92 CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 10, keystream[10]);\
93 CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 11, keystream[11]);\
94 CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 12, keystream[12]);\
95 CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 13, keystream[13]);\
96 CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 14, keystream[14]);\
97 CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 15, keystream[15]);}
98
99ANONYMOUS_NAMESPACE_BEGIN
100
101using CryptoPP::word32;
102using CryptoPP::rotrConstant;
103
104inline word32 f1(word32 x)
105{
106 return rotrConstant<7>(x) ^ rotrConstant<18>(x) ^ ((x) >> 3);
107}
108
109inline word32 f2(word32 x)
110{
111 return rotrConstant<17>(x) ^ rotrConstant<19>(x) ^ ((x) >> 10);
112}
113
114ANONYMOUS_NAMESPACE_END
115
116NAMESPACE_BEGIN(CryptoPP)
117
118/*16 steps of HC-128, generate 512 bits keystream*/
119void HC128Policy::GenerateKeystream(word32 keystream[16])
120{
121 unsigned int cc = m_ctr & 0x1ff;
122 unsigned int dd = (cc + 16) & 0x1ff;
123
124 if (m_ctr < 512)
125 {
126 m_ctr = (m_ctr + 16) & 0x3ff;
127 step_P(cc + 0, cc + 1, 0, 6, 13, 4, keystream[0]);
128 step_P(cc + 1, cc + 2, 1, 7, 14, 5, keystream[1]);
129 step_P(cc + 2, cc + 3, 2, 8, 15, 6, keystream[2]);
130 step_P(cc + 3, cc + 4, 3, 9, 0, 7, keystream[3]);
131 step_P(cc + 4, cc + 5, 4, 10, 1, 8, keystream[4]);
132 step_P(cc + 5, cc + 6, 5, 11, 2, 9, keystream[5]);
133 step_P(cc + 6, cc + 7, 6, 12, 3, 10, keystream[6]);
134 step_P(cc + 7, cc + 8, 7, 13, 4, 11, keystream[7]);
135 step_P(cc + 8, cc + 9, 8, 14, 5, 12, keystream[8]);
136 step_P(cc + 9, cc + 10, 9, 15, 6, 13, keystream[9]);
137 step_P(cc + 10, cc + 11, 10, 0, 7, 14, keystream[10]);
138 step_P(cc + 11, cc + 12, 11, 1, 8, 15, keystream[11]);
139 step_P(cc + 12, cc + 13, 12, 2, 9, 0, keystream[12]);
140 step_P(cc + 13, cc + 14, 13, 3, 10, 1, keystream[13]);
141 step_P(cc + 14, cc + 15, 14, 4, 11, 2, keystream[14]);
142 step_P(cc + 15, dd + 0, 15, 5, 12, 3, keystream[15]);
143 }
144 else
145 {
146 m_ctr = (m_ctr + 16) & 0x3ff;
147 step_Q(512 + cc + 0, 512 + cc + 1, 0, 6, 13, 4, keystream[0]);
148 step_Q(512 + cc + 1, 512 + cc + 2, 1, 7, 14, 5, keystream[1]);
149 step_Q(512 + cc + 2, 512 + cc + 3, 2, 8, 15, 6, keystream[2]);
150 step_Q(512 + cc + 3, 512 + cc + 4, 3, 9, 0, 7, keystream[3]);
151 step_Q(512 + cc + 4, 512 + cc + 5, 4, 10, 1, 8, keystream[4]);
152 step_Q(512 + cc + 5, 512 + cc + 6, 5, 11, 2, 9, keystream[5]);
153 step_Q(512 + cc + 6, 512 + cc + 7, 6, 12, 3, 10, keystream[6]);
154 step_Q(512 + cc + 7, 512 + cc + 8, 7, 13, 4, 11, keystream[7]);
155 step_Q(512 + cc + 8, 512 + cc + 9, 8, 14, 5, 12, keystream[8]);
156 step_Q(512 + cc + 9, 512 + cc + 10, 9, 15, 6, 13, keystream[9]);
157 step_Q(512 + cc + 10, 512 + cc + 11, 10, 0, 7, 14, keystream[10]);
158 step_Q(512 + cc + 11, 512 + cc + 12, 11, 1, 8, 15, keystream[11]);
159 step_Q(512 + cc + 12, 512 + cc + 13, 12, 2, 9, 0, keystream[12]);
160 step_Q(512 + cc + 13, 512 + cc + 14, 13, 3, 10, 1, keystream[13]);
161 step_Q(512 + cc + 14, 512 + cc + 15, 14, 4, 11, 2, keystream[14]);
162 step_Q(512 + cc + 15, 512 + dd + 0, 15, 5, 12, 3, keystream[15]);
163 }
164}
165
166/*16 steps of HC-128, without generating keystream, */
167/*but use the outputs to update P and Q*/
168void HC128Policy::SetupUpdate() /*each time 16 steps*/
169{
170 unsigned int cc = m_ctr & 0x1ff;
171 unsigned int dd = (cc + 16) & 0x1ff;
172
173 if (m_ctr < 512)
174 {
175 m_ctr = (m_ctr + 16) & 0x3ff;
176 update_P(cc + 0, cc + 1, 0, 6, 13, 4);
177 update_P(cc + 1, cc + 2, 1, 7, 14, 5);
178 update_P(cc + 2, cc + 3, 2, 8, 15, 6);
179 update_P(cc + 3, cc + 4, 3, 9, 0, 7);
180 update_P(cc + 4, cc + 5, 4, 10, 1, 8);
181 update_P(cc + 5, cc + 6, 5, 11, 2, 9);
182 update_P(cc + 6, cc + 7, 6, 12, 3, 10);
183 update_P(cc + 7, cc + 8, 7, 13, 4, 11);
184 update_P(cc + 8, cc + 9, 8, 14, 5, 12);
185 update_P(cc + 9, cc + 10, 9, 15, 6, 13);
186 update_P(cc + 10, cc + 11, 10, 0, 7, 14);
187 update_P(cc + 11, cc + 12, 11, 1, 8, 15);
188 update_P(cc + 12, cc + 13, 12, 2, 9, 0);
189 update_P(cc + 13, cc + 14, 13, 3, 10, 1);
190 update_P(cc + 14, cc + 15, 14, 4, 11, 2);
191 update_P(cc + 15, dd + 0, 15, 5, 12, 3);
192 }
193 else
194 {
195 m_ctr = (m_ctr + 16) & 0x3ff;
196 update_Q(512 + cc + 0, 512 + cc + 1, 0, 6, 13, 4);
197 update_Q(512 + cc + 1, 512 + cc + 2, 1, 7, 14, 5);
198 update_Q(512 + cc + 2, 512 + cc + 3, 2, 8, 15, 6);
199 update_Q(512 + cc + 3, 512 + cc + 4, 3, 9, 0, 7);
200 update_Q(512 + cc + 4, 512 + cc + 5, 4, 10, 1, 8);
201 update_Q(512 + cc + 5, 512 + cc + 6, 5, 11, 2, 9);
202 update_Q(512 + cc + 6, 512 + cc + 7, 6, 12, 3, 10);
203 update_Q(512 + cc + 7, 512 + cc + 8, 7, 13, 4, 11);
204 update_Q(512 + cc + 8, 512 + cc + 9, 8, 14, 5, 12);
205 update_Q(512 + cc + 9, 512 + cc + 10, 9, 15, 6, 13);
206 update_Q(512 + cc + 10, 512 + cc + 11, 10, 0, 7, 14);
207 update_Q(512 + cc + 11, 512 + cc + 12, 11, 1, 8, 15);
208 update_Q(512 + cc + 12, 512 + cc + 13, 12, 2, 9, 0);
209 update_Q(512 + cc + 13, 512 + cc + 14, 13, 3, 10, 1);
210 update_Q(512 + cc + 14, 512 + cc + 15, 14, 4, 11, 2);
211 update_Q(512 + cc + 15, 512 + dd + 0, 15, 5, 12, 3);
212 }
213}
214
215void HC128Policy::CipherSetKey(const NameValuePairs &params, const byte *userKey, size_t keylen)
216{
217 CRYPTOPP_UNUSED(params);
218
219 GetUserKey(LITTLE_ENDIAN_ORDER, m_key.begin(), 4, userKey, keylen);
220 for (unsigned int i = 4; i < 8; i++)
221 m_key[i] = m_key[i - 4];
222}
223
224void HC128Policy::OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount)
225{
226 while (iterationCount--)
227 {
229 GenerateKeystream(keystream);
230
232 }
233}
234
235void HC128Policy::CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length)
236{
237 CRYPTOPP_UNUSED(keystreamBuffer);
238
239 GetUserKey(LITTLE_ENDIAN_ORDER, m_iv.begin(), 4, iv, length);
240 for (unsigned int i = 4; i < 8; i++)
241 m_iv[i] = m_iv[i - 4];
242
243 /* expand the key and IV into the table T */
244 /* (expand the key and IV into the table P and Q) */
245
246 for (unsigned int i = 0; i < 8; i++)
247 m_T[i] = m_key[i];
248 for (unsigned int i = 8; i < 16; i++)
249 m_T[i] = m_iv[i - 8];
250
251 for (unsigned int i = 16; i < (256 + 16); i++)
252 m_T[i] = f2(m_T[i - 2]) + m_T[i - 7] + f1(m_T[i - 15]) + m_T[i - 16] + i;
253
254 for (unsigned int i = 0; i < 16; i++)
255 m_T[i] = m_T[256 + i];
256
257 for (unsigned int i = 16; i < 1024; i++)
258 m_T[i] = f2(m_T[i - 2]) + m_T[i - 7] + f1(m_T[i - 15]) + m_T[i - 16] + 256 + i;
259
260 /* initialize counter1024, X and Y */
261 m_ctr = 0;
262 for (unsigned int i = 0; i < 16; i++)
263 m_X[i] = m_T[512 - 16 + i];
264 for (unsigned int i = 0; i < 16; i++)
265 m_Y[i] = m_T[512 + 512 - 16 + i];
266
267 /* run the cipher 1024 steps before generating the output */
268 for (unsigned int i = 0; i < 64; i++)
269 SetupUpdate();
270}
271
272NAMESPACE_END
Fixed size stack-based SecBlock.
Definition secblock.h:1246
Interface for retrieving values given their names.
Definition cryptlib.h:327
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:72
@ LITTLE_ENDIAN_ORDER
byte order is little-endian
Definition cryptlib.h:150
Classes for HC-128 stream cipher.
Utility functions for the Crypto++ library.
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:2500
Crypto++ library namespace.
Precompiled header file.
Classes and functions for secure memory allocations.
Classes for implementing stream ciphers.
#define CRYPTOPP_KEYSTREAM_OUTPUT_SWITCH(x, y)
Helper macro to implement OperateKeystream.
Definition strciphr.h:266
KeystreamOperation
Keystream operation flags.
Definition strciphr.h:88
static const int BYTES_PER_ITERATION
Number of bytes for an iteration.
Definition strciphr.h:211