Crypto++  8.8
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 
76 ANONYMOUS_NAMESPACE_BEGIN
77 
78 using CryptoPP::word32;
80 
81 inline word32 f1(word32 x)
82 {
83  return rotrConstant<7>(x) ^ rotrConstant<18>(x) ^ ((x) >> 3);
84 }
85 
86 inline word32 f2(word32 x)
87 {
88  return rotrConstant<17>(x) ^ rotrConstant<19>(x) ^ ((x) >> 10);
89 }
90 
91 ANONYMOUS_NAMESPACE_END
92 
93 NAMESPACE_BEGIN(CryptoPP)
94 
95 /*16 steps of HC-128, generate 512 bits keystream*/
96 void 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*/
145 void 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 
192 void 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 
201 void 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 
242 void 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 
279 NAMESPACE_END
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.
T rotrConstant(T x)
Performs a right rotate.
Definition: misc.h:1783
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
#define EnumToInt(v)
Integer value.
Definition: misc.h:504
void PutWord(bool assumeAligned, ByteOrder order, byte *block, T value, const byte *xorBlock=NULL)
Access a block of memory.
Definition: misc.h:2948
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