Crypto++  8.2
Free C++ class library of cryptographic schemes
cham.cpp
1 // cham.cpp - written and placed in the public domain by Kim Sung Hee and Jeffrey Walton
2 // Based on "CHAM: A Family of Lightweight Block Ciphers for
3 // Resource-Constrained Devices" by Bonwook Koo, Dongyoung Roh,
4 // Hyeonjin Kim, Younghoon Jung, Dong-Geon Lee, and Daesung Kwon
5 
6 #include "pch.h"
7 #include "config.h"
8 
9 #include "cham.h"
10 #include "misc.h"
11 #include "cpu.h"
12 
13 // CHAM table of parameters
14 // +-------------------------------------------------
15 // +cipher n k r w k/w
16 // +-------------------------------------------------
17 // +CHAM-64/128 64 128 80 16 8
18 // +CHAM-128/128 128 128 80 32 4
19 // +CHAM-128/256 128 256 96 32 8
20 // +-------------------------------------------------
21 
22 ANONYMOUS_NAMESPACE_BEGIN
23 
26 
27 /// \brief CHAM encryption round
28 /// \tparam RR the round number residue
29 /// \tparam KW the number of key words
30 /// \tparam T words type
31 /// \param x the state array
32 /// \param k the subkey table
33 /// \param i the round number
34 /// \details CHAM_EncRound applies the encryption round to the plain text.
35 /// RR is the "round residue" and it is used modulo 4. ProcessAndXorBlock
36 /// may provide a fully unrolled encryption transformation, or provide
37 /// a transformation that loops using multiples of 4 encryption rounds.
38 /// \details CHAM_EncRound calculates indexes into the x[] array based
39 /// on the round number residue. There is no need for the assignments
40 /// that shift values in preparations for the next round.
41 /// \details CHAM_EncRound depends on the round number. The actual round
42 /// being executed is passed through the parameter <tt>i</tt>. If
43 /// ProcessAndXorBlock fully unrolled the loop then the parameter
44 /// <tt>i</tt> would be unnecessary.
45 template <unsigned int RR, unsigned int KW, class T>
46 inline void CHAM_EncRound(T x[4], const T k[KW], unsigned int i)
47 {
48  CRYPTOPP_CONSTANT(IDX0 = (RR+0) % 4)
49  CRYPTOPP_CONSTANT(IDX1 = (RR+1) % 4)
50  CRYPTOPP_CONSTANT(IDX3 = (RR+3+1) % 4)
51  CRYPTOPP_CONSTANT(R1 = (RR % 2 == 0) ? 1 : 8)
52  CRYPTOPP_CONSTANT(R2 = (RR % 2 == 0) ? 8 : 1)
53 
54  // Follows conventions in the ref impl
55  const T kk = k[i % KW];
56  const T aa = x[IDX0] ^ static_cast<T>(i);
57  const T bb = rotlConstant<R1>(x[IDX1]) ^ kk;
58  x[IDX3] = rotlConstant<R2>(static_cast<T>(aa + bb));
59 }
60 
61 /// \brief CHAM decryption round
62 /// \tparam RR the round number residue
63 /// \tparam KW the number of key words
64 /// \tparam T words type
65 /// \param x the state array
66 /// \param k the subkey table
67 /// \param i the round number
68 /// \details CHAM_DecRound applies the decryption round to the cipher text.
69 /// RR is the "round residue" and it is used modulo 4. ProcessAndXorBlock
70 /// may provide a fully unrolled decryption transformation, or provide
71 /// a transformation that loops using multiples of 4 decryption rounds.
72 /// \details CHAM_DecRound calculates indexes into the x[] array based
73 /// on the round number residue. There is no need for the assignments
74 /// that shift values in preparations for the next round.
75 /// \details CHAM_DecRound depends on the round number. The actual round
76 /// being executed is passed through the parameter <tt>i</tt>. If
77 /// ProcessAndXorBlock fully unrolled the loop then the parameter
78 /// <tt>i</tt> would be unnecessary.
79 template <unsigned int RR, unsigned int KW, class T>
80 inline void CHAM_DecRound(T x[4], const T k[KW], unsigned int i)
81 {
82  CRYPTOPP_CONSTANT(IDX0 = (RR+0) % 4)
83  CRYPTOPP_CONSTANT(IDX1 = (RR+1) % 4)
84  CRYPTOPP_CONSTANT(IDX3 = (RR+3+1) % 4)
85  CRYPTOPP_CONSTANT(R1 = (RR % 2 == 0) ? 8 : 1)
86  CRYPTOPP_CONSTANT(R2 = (RR % 2 == 0) ? 1 : 8)
87 
88  // Follows conventions in the ref impl
89  const T kk = k[i % KW];
90  const T aa = rotrConstant<R1>(x[IDX3]);
91  const T bb = rotlConstant<R2>(x[IDX1]) ^ kk;
92  x[IDX0] = static_cast<T>(aa - bb) ^ static_cast<T>(i);
93 }
94 
95 ANONYMOUS_NAMESPACE_END
96 
97 NAMESPACE_BEGIN(CryptoPP)
98 
99 #if CRYPTOPP_CHAM_ADVANCED_PROCESS_BLOCKS
100 # if (CRYPTOPP_SSSE3_AVAILABLE)
101 extern size_t CHAM64_Enc_AdvancedProcessBlocks_SSSE3(const word16* subKeys, size_t rounds,
102  const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags);
103 
104 extern size_t CHAM64_Dec_AdvancedProcessBlocks_SSSE3(const word16* subKeys, size_t rounds,
105  const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags);
106 
107 extern size_t CHAM128_Enc_AdvancedProcessBlocks_SSSE3(const word32* subKeys, size_t rounds,
108  const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags);
109 
110 extern size_t CHAM128_Dec_AdvancedProcessBlocks_SSSE3(const word32* subKeys, size_t rounds,
111  const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags);
112 # endif // CRYPTOPP_SSSE3_AVAILABLE
113 #endif // CRYPTOPP_CHAM_ADVANCED_PROCESS_BLOCKS
114 
115 std::string CHAM64::Base::AlgorithmProvider() const
116 {
117 #if (CRYPTOPP_CHAM_ADVANCED_PROCESS_BLOCKS)
118 # if defined(CRYPTOPP_SSSE3_AVAILABLE)
119  if (HasSSSE3())
120  return "SSSE3";
121 # endif
122 #endif
123  return "C++";
124 }
125 
126 void CHAM64::Base::UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs &params)
127 {
128  CRYPTOPP_UNUSED(params);
129  m_kw = keyLength/sizeof(word16);
130  m_rk.New(2*m_kw);
131 
132  for (size_t i = 0; i < m_kw; ++i, userKey += sizeof(word16))
133  {
134  // Do not cast the buffer. It will SIGBUS on some ARM and SPARC.
135  const word16 rk = GetWord<word16>(false, BIG_ENDIAN_ORDER, userKey);
136  m_rk[i] = rk ^ rotlConstant<1>(rk) ^ rotlConstant<8>(rk);
137  m_rk[(i + m_kw) ^ 1] = rk ^ rotlConstant<1>(rk) ^ rotlConstant<11>(rk);
138  }
139 }
140 
141 void CHAM64::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const
142 {
143  // Do not cast the buffer. It will SIGBUS on some ARM and SPARC.
144  GetBlock<word16, BigEndian> iblock(inBlock);
145  iblock(m_x[0])(m_x[1])(m_x[2])(m_x[3]);
146 
147  const int R = 80;
148  for (int i = 0; i < R; i+=16)
149  {
150  CHAM_EncRound< 0, 16>(m_x.begin(), m_rk.begin(), i+0);
151  CHAM_EncRound< 1, 16>(m_x.begin(), m_rk.begin(), i+1);
152  CHAM_EncRound< 2, 16>(m_x.begin(), m_rk.begin(), i+2);
153  CHAM_EncRound< 3, 16>(m_x.begin(), m_rk.begin(), i+3);
154  CHAM_EncRound< 4, 16>(m_x.begin(), m_rk.begin(), i+4);
155  CHAM_EncRound< 5, 16>(m_x.begin(), m_rk.begin(), i+5);
156  CHAM_EncRound< 6, 16>(m_x.begin(), m_rk.begin(), i+6);
157  CHAM_EncRound< 7, 16>(m_x.begin(), m_rk.begin(), i+7);
158  CHAM_EncRound< 8, 16>(m_x.begin(), m_rk.begin(), i+8);
159  CHAM_EncRound< 9, 16>(m_x.begin(), m_rk.begin(), i+9);
160  CHAM_EncRound<10, 16>(m_x.begin(), m_rk.begin(), i+10);
161  CHAM_EncRound<11, 16>(m_x.begin(), m_rk.begin(), i+11);
162  CHAM_EncRound<12, 16>(m_x.begin(), m_rk.begin(), i+12);
163  CHAM_EncRound<13, 16>(m_x.begin(), m_rk.begin(), i+13);
164  CHAM_EncRound<14, 16>(m_x.begin(), m_rk.begin(), i+14);
165  CHAM_EncRound<15, 16>(m_x.begin(), m_rk.begin(), i+15);
166  }
167 
168  PutBlock<word16, BigEndian> oblock(xorBlock, outBlock);
169  oblock(m_x[0])(m_x[1])(m_x[2])(m_x[3]);
170 }
171 
172 void CHAM64::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const
173 {
174  // Do not cast the buffer. It will SIGBUS on some ARM and SPARC.
175  GetBlock<word16, BigEndian> iblock(inBlock);
176  iblock(m_x[0])(m_x[1])(m_x[2])(m_x[3]);
177 
178  const int R = 80;
179  for (int i = R-1; i >=0 ; i-=16)
180  {
181  CHAM_DecRound<15, 16>(m_x.begin(), m_rk.begin(), i-0);
182  CHAM_DecRound<14, 16>(m_x.begin(), m_rk.begin(), i-1);
183  CHAM_DecRound<13, 16>(m_x.begin(), m_rk.begin(), i-2);
184  CHAM_DecRound<12, 16>(m_x.begin(), m_rk.begin(), i-3);
185  CHAM_DecRound<11, 16>(m_x.begin(), m_rk.begin(), i-4);
186  CHAM_DecRound<10, 16>(m_x.begin(), m_rk.begin(), i-5);
187  CHAM_DecRound< 9, 16>(m_x.begin(), m_rk.begin(), i-6);
188  CHAM_DecRound< 8, 16>(m_x.begin(), m_rk.begin(), i-7);
189  CHAM_DecRound< 7, 16>(m_x.begin(), m_rk.begin(), i-8);
190  CHAM_DecRound< 6, 16>(m_x.begin(), m_rk.begin(), i-9);
191  CHAM_DecRound< 5, 16>(m_x.begin(), m_rk.begin(), i-10);
192  CHAM_DecRound< 4, 16>(m_x.begin(), m_rk.begin(), i-11);
193  CHAM_DecRound< 3, 16>(m_x.begin(), m_rk.begin(), i-12);
194  CHAM_DecRound< 2, 16>(m_x.begin(), m_rk.begin(), i-13);
195  CHAM_DecRound< 1, 16>(m_x.begin(), m_rk.begin(), i-14);
196  CHAM_DecRound< 0, 16>(m_x.begin(), m_rk.begin(), i-15);
197  }
198 
199  PutBlock<word16, BigEndian> oblock(xorBlock, outBlock);
200  oblock(m_x[0])(m_x[1])(m_x[2])(m_x[3]);
201 }
202 
203 std::string CHAM128::Base::AlgorithmProvider() const
204 {
205 #if defined(CRYPTOPP_SSSE3_AVAILABLE)
206  if (HasSSSE3())
207  return "SSSE3";
208 #endif
209  return "C++";
210 }
211 
212 void CHAM128::Base::UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs &params)
213 {
214  CRYPTOPP_UNUSED(params);
215  m_kw = keyLength/sizeof(word32);
216  m_rk.New(2*m_kw);
217 
218  for (size_t i = 0; i < m_kw; ++i, userKey += sizeof(word32))
219  {
220  // Do not cast the buffer. It will SIGBUS on some ARM and SPARC.
221  const word32 rk = GetWord<word32>(false, BIG_ENDIAN_ORDER, userKey);
222  m_rk[i] = rk ^ rotlConstant<1>(rk) ^ rotlConstant<8>(rk);
223  m_rk[(i + m_kw) ^ 1] = rk ^ rotlConstant<1>(rk) ^ rotlConstant<11>(rk);
224  }
225 }
226 
227 void CHAM128::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const
228 {
229  // Do not cast the buffer. It will SIGBUS on some ARM and SPARC.
230  GetBlock<word32, BigEndian> iblock(inBlock);
231  iblock(m_x[0])(m_x[1])(m_x[2])(m_x[3]);
232 
233  switch (m_kw)
234  {
235  case 4: // 128-bit key
236  {
237  const int R = 80;
238  for (int i = 0; i < R; i+=8)
239  {
240  CHAM_EncRound<0, 8>(m_x.begin(), m_rk.begin(), i+0);
241  CHAM_EncRound<1, 8>(m_x.begin(), m_rk.begin(), i+1);
242  CHAM_EncRound<2, 8>(m_x.begin(), m_rk.begin(), i+2);
243  CHAM_EncRound<3, 8>(m_x.begin(), m_rk.begin(), i+3);
244  CHAM_EncRound<4, 8>(m_x.begin(), m_rk.begin(), i+4);
245  CHAM_EncRound<5, 8>(m_x.begin(), m_rk.begin(), i+5);
246  CHAM_EncRound<6, 8>(m_x.begin(), m_rk.begin(), i+6);
247  CHAM_EncRound<7, 8>(m_x.begin(), m_rk.begin(), i+7);
248  }
249  break;
250  }
251  case 8: // 256-bit key
252  {
253  const int R = 96;
254  for (int i = 0; i < R; i+=16)
255  {
256  CHAM_EncRound< 0, 16>(m_x.begin(), m_rk.begin(), i+0);
257  CHAM_EncRound< 1, 16>(m_x.begin(), m_rk.begin(), i+1);
258  CHAM_EncRound< 2, 16>(m_x.begin(), m_rk.begin(), i+2);
259  CHAM_EncRound< 3, 16>(m_x.begin(), m_rk.begin(), i+3);
260  CHAM_EncRound< 4, 16>(m_x.begin(), m_rk.begin(), i+4);
261  CHAM_EncRound< 5, 16>(m_x.begin(), m_rk.begin(), i+5);
262  CHAM_EncRound< 6, 16>(m_x.begin(), m_rk.begin(), i+6);
263  CHAM_EncRound< 7, 16>(m_x.begin(), m_rk.begin(), i+7);
264  CHAM_EncRound< 8, 16>(m_x.begin(), m_rk.begin(), i+8);
265  CHAM_EncRound< 9, 16>(m_x.begin(), m_rk.begin(), i+9);
266  CHAM_EncRound<10, 16>(m_x.begin(), m_rk.begin(), i+10);
267  CHAM_EncRound<11, 16>(m_x.begin(), m_rk.begin(), i+11);
268  CHAM_EncRound<12, 16>(m_x.begin(), m_rk.begin(), i+12);
269  CHAM_EncRound<13, 16>(m_x.begin(), m_rk.begin(), i+13);
270  CHAM_EncRound<14, 16>(m_x.begin(), m_rk.begin(), i+14);
271  CHAM_EncRound<15, 16>(m_x.begin(), m_rk.begin(), i+15);
272  }
273  break;
274  }
275  default:
276  CRYPTOPP_ASSERT(0);;
277  }
278 
279  PutBlock<word32, BigEndian> oblock(xorBlock, outBlock);
280  oblock(m_x[0])(m_x[1])(m_x[2])(m_x[3]);
281 }
282 
283 void CHAM128::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const
284 {
285  // Do not cast the buffer. It will SIGBUS on some ARM and SPARC.
286  GetBlock<word32, BigEndian> iblock(inBlock);
287  iblock(m_x[0])(m_x[1])(m_x[2])(m_x[3]);
288 
289  switch (m_kw)
290  {
291  case 4: // 128-bit key
292  {
293  const int R = 80;
294  for (int i = R-1; i >= 0; i-=8)
295  {
296  CHAM_DecRound<7, 8>(m_x.begin(), m_rk.begin(), i-0);
297  CHAM_DecRound<6, 8>(m_x.begin(), m_rk.begin(), i-1);
298  CHAM_DecRound<5, 8>(m_x.begin(), m_rk.begin(), i-2);
299  CHAM_DecRound<4, 8>(m_x.begin(), m_rk.begin(), i-3);
300  CHAM_DecRound<3, 8>(m_x.begin(), m_rk.begin(), i-4);
301  CHAM_DecRound<2, 8>(m_x.begin(), m_rk.begin(), i-5);
302  CHAM_DecRound<1, 8>(m_x.begin(), m_rk.begin(), i-6);
303  CHAM_DecRound<0, 8>(m_x.begin(), m_rk.begin(), i-7);
304  }
305  break;
306  }
307  case 8: // 256-bit key
308  {
309  const int R = 96;
310  for (int i = R-1; i >= 0; i-=16)
311  {
312  CHAM_DecRound<15, 16>(m_x.begin(), m_rk.begin(), i-0);
313  CHAM_DecRound<14, 16>(m_x.begin(), m_rk.begin(), i-1);
314  CHAM_DecRound<13, 16>(m_x.begin(), m_rk.begin(), i-2);
315  CHAM_DecRound<12, 16>(m_x.begin(), m_rk.begin(), i-3);
316  CHAM_DecRound<11, 16>(m_x.begin(), m_rk.begin(), i-4);
317  CHAM_DecRound<10, 16>(m_x.begin(), m_rk.begin(), i-5);
318  CHAM_DecRound< 9, 16>(m_x.begin(), m_rk.begin(), i-6);
319  CHAM_DecRound< 8, 16>(m_x.begin(), m_rk.begin(), i-7);
320  CHAM_DecRound< 7, 16>(m_x.begin(), m_rk.begin(), i-8);
321  CHAM_DecRound< 6, 16>(m_x.begin(), m_rk.begin(), i-9);
322  CHAM_DecRound< 5, 16>(m_x.begin(), m_rk.begin(), i-10);
323  CHAM_DecRound< 4, 16>(m_x.begin(), m_rk.begin(), i-11);
324  CHAM_DecRound< 3, 16>(m_x.begin(), m_rk.begin(), i-12);
325  CHAM_DecRound< 2, 16>(m_x.begin(), m_rk.begin(), i-13);
326  CHAM_DecRound< 1, 16>(m_x.begin(), m_rk.begin(), i-14);
327  CHAM_DecRound< 0, 16>(m_x.begin(), m_rk.begin(), i-15);
328  }
329  break;
330  }
331  default:
332  CRYPTOPP_ASSERT(0);;
333  }
334 
335  PutBlock<word32, BigEndian> oblock(xorBlock, outBlock);
336  oblock(m_x[0])(m_x[1])(m_x[2])(m_x[3]);
337 }
338 
339 #if CRYPTOPP_CHAM_ADVANCED_PROCESS_BLOCKS
340 size_t CHAM64::Enc::AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks,
341  byte *outBlocks, size_t length, word32 flags) const
342 {
343 # if (CRYPTOPP_SSSE3_AVAILABLE)
344  if (HasSSSE3()) {
345  return CHAM64_Enc_AdvancedProcessBlocks_SSSE3(m_rk, 80,
346  inBlocks, xorBlocks, outBlocks, length, flags);
347  }
348 # endif // CRYPTOPP_SSSE3_AVAILABLE
349  return BlockTransformation::AdvancedProcessBlocks(inBlocks, xorBlocks, outBlocks, length, flags);
350 }
351 
352 size_t CHAM64::Dec::AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks,
353  byte *outBlocks, size_t length, word32 flags) const
354 {
355 # if (CRYPTOPP_SSSE3_AVAILABLE)
356  if (HasSSSE3()) {
357  return CHAM64_Dec_AdvancedProcessBlocks_SSSE3(m_rk, 80,
358  inBlocks, xorBlocks, outBlocks, length, flags);
359  }
360 # endif // CRYPTOPP_SSSE3_AVAILABLE
361  return BlockTransformation::AdvancedProcessBlocks(inBlocks, xorBlocks, outBlocks, length, flags);
362 }
363 
364 size_t CHAM128::Enc::AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks,
365  byte *outBlocks, size_t length, word32 flags) const
366 {
367 # if (CRYPTOPP_SSSE3_AVAILABLE)
368  if (HasSSSE3()) {
369  const size_t rounds = (m_kw == 4 ? 80 : 96);
370  return CHAM128_Enc_AdvancedProcessBlocks_SSSE3(m_rk, rounds,
371  inBlocks, xorBlocks, outBlocks, length, flags);
372  }
373 # endif // CRYPTOPP_SSSE3_AVAILABLE
374  return BlockTransformation::AdvancedProcessBlocks(inBlocks, xorBlocks, outBlocks, length, flags);
375 }
376 
377 size_t CHAM128::Dec::AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks,
378  byte *outBlocks, size_t length, word32 flags) const
379 {
380 # if (CRYPTOPP_SSSE3_AVAILABLE)
381  if (HasSSSE3()) {
382  const size_t rounds = (m_kw == 4 ? 80 : 96);
383  return CHAM128_Dec_AdvancedProcessBlocks_SSSE3(m_rk, rounds,
384  inBlocks, xorBlocks, outBlocks, length, flags);
385  }
386 # endif // CRYPTOPP_SSSE3_AVAILABLE
387  return BlockTransformation::AdvancedProcessBlocks(inBlocks, xorBlocks, outBlocks, length, flags);
388 }
389 #endif // CRYPTOPP_CHAM_ADVANCED_PROCESS_BLOCKS
390 
391 NAMESPACE_END
Utility functions for the Crypto++ library.
bool HasSSSE3()
Determines SSSE3 availability.
Definition: cpu.h:131
Library configuration file.
Classes for the CHAM block cipher.
T rotlConstant(T x)
Performs a left rotate.
Definition: misc.h:1499
virtual size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const
Encrypt and xor multiple blocks using additional flags.
Definition: cryptlib.cpp:141
Precompiled header file.
byte order is big-endian
Definition: cryptlib.h:147
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition: trap.h:69
Functions for CPU features and intrinsics.
T rotrConstant(T x)
Performs a right rotate.
Definition: misc.h:1525
Access a block of memory.
Definition: misc.h:2454
Access a block of memory.
Definition: misc.h:2495
Crypto++ library namespace.
Interface for retrieving values given their names.
Definition: cryptlib.h:293