Crypto++ 8.2
Free C&
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
22ANONYMOUS_NAMESPACE_BEGIN
23
24using CryptoPP::rotlConstant;
25using CryptoPP::rotrConstant;
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.
45template <unsigned int RR, unsigned int KW, class T>
46inline 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.
79template <unsigned int RR, unsigned int KW, class T>
80inline 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
95ANONYMOUS_NAMESPACE_END
96
97NAMESPACE_BEGIN(CryptoPP)
98
99#if CRYPTOPP_CHAM_ADVANCED_PROCESS_BLOCKS
100# if (CRYPTOPP_SSSE3_AVAILABLE)
101extern 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
104extern 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
107extern 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
110extern 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
115std::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
126void 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
141void 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
172void 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
203std::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
212void 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
227void 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
283void 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
340size_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
352size_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
364size_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
377size_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
391NAMESPACE_END
Classes for the CHAM block cipher.
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
Access a block of memory.
Definition: misc.h:2455
Interface for retrieving values given their names.
Definition: cryptlib.h:294
Access a block of memory.
Definition: misc.h:2496
Library configuration file.
Functions for CPU features and intrinsics.
bool HasSSSE3()
Determines SSSE3 availability.
Definition: cpu.h:131
@ BIG_ENDIAN_ORDER
byte order is big-endian
Definition: cryptlib.h:147
Utility functions for the Crypto++ library.
T rotlConstant(T x)
Performs a left rotate.
Definition: misc.h:1499
T rotrConstant(T x)
Performs a right rotate.
Definition: misc.h:1525
Crypto++ library namespace.
Precompiled header file.
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition: trap.h:69