Crypto++ 8.5 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
24 using CryptoPP::rotlConstant;
25 using 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.
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_CHAM128_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_CHAM128_ADVANCED_PROCESS_BLOCKS
114
115 void CHAM64::Base::UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs &params)
116 {
117 CRYPTOPP_UNUSED(params);
118 m_kw = keyLength/sizeof(word16);
119 m_rk.New(2*m_kw);
120
121 for (size_t i = 0; i < m_kw; userKey += sizeof(word32))
122 {
123 // Do not cast the buffer. It will SIGBUS on some ARM and SPARC.
124 const word32 rk = GetWord<word32>(false, BIG_ENDIAN_ORDER, userKey);
125
126 const word16 rk1 = rk >> 16;
127 m_rk[i] = rk1 ^ rotlConstant<1>(rk1) ^ rotlConstant<8>(rk1);
128 m_rk[(i + m_kw) ^ 1] = rk1 ^ rotlConstant<1>(rk1) ^ rotlConstant<11>(rk1);
129 i++;
130
131 const word16 rk2 = rk & 0xffff;
132 m_rk[i] = rk2 ^ rotlConstant<1>(rk2) ^ rotlConstant<8>(rk2);
133 m_rk[(i + m_kw) ^ 1] = rk2 ^ rotlConstant<1>(rk2) ^ rotlConstant<11>(rk2);
134 i++;
135 }
136 }
137
138 void CHAM64::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const
139 {
140 // Do not cast the buffer. It will SIGBUS on some ARM and SPARC.
141 GetBlock<word16, BigEndian> iblock(inBlock);
142 iblock(m_x[0])(m_x[1])(m_x[2])(m_x[3]);
143
144 const int R = 80;
145 for (int i = 0; i < R; i+=16)
146 {
147 CHAM_EncRound< 0, 16>(m_x.begin(), m_rk.begin(), i+0);
148 CHAM_EncRound< 1, 16>(m_x.begin(), m_rk.begin(), i+1);
149 CHAM_EncRound< 2, 16>(m_x.begin(), m_rk.begin(), i+2);
150 CHAM_EncRound< 3, 16>(m_x.begin(), m_rk.begin(), i+3);
151 CHAM_EncRound< 4, 16>(m_x.begin(), m_rk.begin(), i+4);
152 CHAM_EncRound< 5, 16>(m_x.begin(), m_rk.begin(), i+5);
153 CHAM_EncRound< 6, 16>(m_x.begin(), m_rk.begin(), i+6);
154 CHAM_EncRound< 7, 16>(m_x.begin(), m_rk.begin(), i+7);
155 CHAM_EncRound< 8, 16>(m_x.begin(), m_rk.begin(), i+8);
156 CHAM_EncRound< 9, 16>(m_x.begin(), m_rk.begin(), i+9);
157 CHAM_EncRound<10, 16>(m_x.begin(), m_rk.begin(), i+10);
158 CHAM_EncRound<11, 16>(m_x.begin(), m_rk.begin(), i+11);
159 CHAM_EncRound<12, 16>(m_x.begin(), m_rk.begin(), i+12);
160 CHAM_EncRound<13, 16>(m_x.begin(), m_rk.begin(), i+13);
161 CHAM_EncRound<14, 16>(m_x.begin(), m_rk.begin(), i+14);
162 CHAM_EncRound<15, 16>(m_x.begin(), m_rk.begin(), i+15);
163 }
164
165 PutBlock<word16, BigEndian> oblock(xorBlock, outBlock);
166 oblock(m_x[0])(m_x[1])(m_x[2])(m_x[3]);
167 }
168
169 void CHAM64::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const
170 {
171 // Do not cast the buffer. It will SIGBUS on some ARM and SPARC.
172 GetBlock<word16, BigEndian> iblock(inBlock);
173 iblock(m_x[0])(m_x[1])(m_x[2])(m_x[3]);
174
175 const int R = 80;
176 for (int i = R-1; i >=0 ; i-=16)
177 {
178 CHAM_DecRound<15, 16>(m_x.begin(), m_rk.begin(), i-0);
179 CHAM_DecRound<14, 16>(m_x.begin(), m_rk.begin(), i-1);
180 CHAM_DecRound<13, 16>(m_x.begin(), m_rk.begin(), i-2);
181 CHAM_DecRound<12, 16>(m_x.begin(), m_rk.begin(), i-3);
182 CHAM_DecRound<11, 16>(m_x.begin(), m_rk.begin(), i-4);
183 CHAM_DecRound<10, 16>(m_x.begin(), m_rk.begin(), i-5);
184 CHAM_DecRound< 9, 16>(m_x.begin(), m_rk.begin(), i-6);
185 CHAM_DecRound< 8, 16>(m_x.begin(), m_rk.begin(), i-7);
186 CHAM_DecRound< 7, 16>(m_x.begin(), m_rk.begin(), i-8);
187 CHAM_DecRound< 6, 16>(m_x.begin(), m_rk.begin(), i-9);
188 CHAM_DecRound< 5, 16>(m_x.begin(), m_rk.begin(), i-10);
189 CHAM_DecRound< 4, 16>(m_x.begin(), m_rk.begin(), i-11);
190 CHAM_DecRound< 3, 16>(m_x.begin(), m_rk.begin(), i-12);
191 CHAM_DecRound< 2, 16>(m_x.begin(), m_rk.begin(), i-13);
192 CHAM_DecRound< 1, 16>(m_x.begin(), m_rk.begin(), i-14);
193 CHAM_DecRound< 0, 16>(m_x.begin(), m_rk.begin(), i-15);
194 }
195
196 PutBlock<word16, BigEndian> oblock(xorBlock, outBlock);
197 oblock(m_x[0])(m_x[1])(m_x[2])(m_x[3]);
198 }
199
200 std::string CHAM128::Base::AlgorithmProvider() const
201 {
202 #if defined(CRYPTOPP_SSSE3_AVAILABLE)
203 if (HasSSSE3())
204 return "SSSE3";
205 #endif
206 return "C++";
207 }
208
209 void CHAM128::Base::UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs &params)
210 {
211 CRYPTOPP_UNUSED(params);
212 m_kw = keyLength/sizeof(word32);
213 m_rk.New(2*m_kw);
214
215 for (size_t i = 0; i < m_kw; userKey += sizeof(word32))
216 {
217 // Do not cast the buffer. It will SIGBUS on some ARM and SPARC.
218 const word32 rk = GetWord<word32>(false, BIG_ENDIAN_ORDER, userKey);
219 m_rk[i] = rk ^ rotlConstant<1>(rk) ^ rotlConstant<8>(rk);
220 m_rk[(i + m_kw) ^ 1] = rk ^ rotlConstant<1>(rk) ^ rotlConstant<11>(rk);
221 i++;
222 }
223 }
224
225 void CHAM128::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const
226 {
227 // Do not cast the buffer. It will SIGBUS on some ARM and SPARC.
228 GetBlock<word32, BigEndian> iblock(inBlock);
229 iblock(m_x[0])(m_x[1])(m_x[2])(m_x[3]);
230
231 switch (m_kw)
232 {
233 case 4: // 128-bit key
234 {
235 const int R = 80;
236 for (int i = 0; i < R; i+=8)
237 {
238 CHAM_EncRound<0, 8>(m_x.begin(), m_rk.begin(), i+0);
239 CHAM_EncRound<1, 8>(m_x.begin(), m_rk.begin(), i+1);
240 CHAM_EncRound<2, 8>(m_x.begin(), m_rk.begin(), i+2);
241 CHAM_EncRound<3, 8>(m_x.begin(), m_rk.begin(), i+3);
242 CHAM_EncRound<4, 8>(m_x.begin(), m_rk.begin(), i+4);
243 CHAM_EncRound<5, 8>(m_x.begin(), m_rk.begin(), i+5);
244 CHAM_EncRound<6, 8>(m_x.begin(), m_rk.begin(), i+6);
245 CHAM_EncRound<7, 8>(m_x.begin(), m_rk.begin(), i+7);
246 }
247 break;
248 }
249 case 8: // 256-bit key
250 {
251 const int R = 96;
252 for (int i = 0; i < R; i+=16)
253 {
254 CHAM_EncRound< 0, 16>(m_x.begin(), m_rk.begin(), i+0);
255 CHAM_EncRound< 1, 16>(m_x.begin(), m_rk.begin(), i+1);
256 CHAM_EncRound< 2, 16>(m_x.begin(), m_rk.begin(), i+2);
257 CHAM_EncRound< 3, 16>(m_x.begin(), m_rk.begin(), i+3);
258 CHAM_EncRound< 4, 16>(m_x.begin(), m_rk.begin(), i+4);
259 CHAM_EncRound< 5, 16>(m_x.begin(), m_rk.begin(), i+5);
260 CHAM_EncRound< 6, 16>(m_x.begin(), m_rk.begin(), i+6);
261 CHAM_EncRound< 7, 16>(m_x.begin(), m_rk.begin(), i+7);
262 CHAM_EncRound< 8, 16>(m_x.begin(), m_rk.begin(), i+8);
263 CHAM_EncRound< 9, 16>(m_x.begin(), m_rk.begin(), i+9);
264 CHAM_EncRound<10, 16>(m_x.begin(), m_rk.begin(), i+10);
265 CHAM_EncRound<11, 16>(m_x.begin(), m_rk.begin(), i+11);
266 CHAM_EncRound<12, 16>(m_x.begin(), m_rk.begin(), i+12);
267 CHAM_EncRound<13, 16>(m_x.begin(), m_rk.begin(), i+13);
268 CHAM_EncRound<14, 16>(m_x.begin(), m_rk.begin(), i+14);
269 CHAM_EncRound<15, 16>(m_x.begin(), m_rk.begin(), i+15);
270 }
271 break;
272 }
273 default:
274 CRYPTOPP_ASSERT(0);
275 }
276
277 PutBlock<word32, BigEndian> oblock(xorBlock, outBlock);
278 oblock(m_x[0])(m_x[1])(m_x[2])(m_x[3]);
279 }
280
281 void CHAM128::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const
282 {
283 // Do not cast the buffer. It will SIGBUS on some ARM and SPARC.
284 GetBlock<word32, BigEndian> iblock(inBlock);
285 iblock(m_x[0])(m_x[1])(m_x[2])(m_x[3]);
286
287 switch (m_kw)
288 {
289 case 4: // 128-bit key
290 {
291 const int R = 80;
292 for (int i = R-1; i >= 0; i-=8)
293 {
294 CHAM_DecRound<7, 8>(m_x.begin(), m_rk.begin(), i-0);
295 CHAM_DecRound<6, 8>(m_x.begin(), m_rk.begin(), i-1);
296 CHAM_DecRound<5, 8>(m_x.begin(), m_rk.begin(), i-2);
297 CHAM_DecRound<4, 8>(m_x.begin(), m_rk.begin(), i-3);
298 CHAM_DecRound<3, 8>(m_x.begin(), m_rk.begin(), i-4);
299 CHAM_DecRound<2, 8>(m_x.begin(), m_rk.begin(), i-5);
300 CHAM_DecRound<1, 8>(m_x.begin(), m_rk.begin(), i-6);
301 CHAM_DecRound<0, 8>(m_x.begin(), m_rk.begin(), i-7);
302 }
303 break;
304 }
305 case 8: // 256-bit key
306 {
307 const int R = 96;
308 for (int i = R-1; i >= 0; i-=16)
309 {
310 CHAM_DecRound<15, 16>(m_x.begin(), m_rk.begin(), i-0);
311 CHAM_DecRound<14, 16>(m_x.begin(), m_rk.begin(), i-1);
312 CHAM_DecRound<13, 16>(m_x.begin(), m_rk.begin(), i-2);
313 CHAM_DecRound<12, 16>(m_x.begin(), m_rk.begin(), i-3);
314 CHAM_DecRound<11, 16>(m_x.begin(), m_rk.begin(), i-4);
315 CHAM_DecRound<10, 16>(m_x.begin(), m_rk.begin(), i-5);
316 CHAM_DecRound< 9, 16>(m_x.begin(), m_rk.begin(), i-6);
317 CHAM_DecRound< 8, 16>(m_x.begin(), m_rk.begin(), i-7);
318 CHAM_DecRound< 7, 16>(m_x.begin(), m_rk.begin(), i-8);
319 CHAM_DecRound< 6, 16>(m_x.begin(), m_rk.begin(), i-9);
320 CHAM_DecRound< 5, 16>(m_x.begin(), m_rk.begin(), i-10);
321 CHAM_DecRound< 4, 16>(m_x.begin(), m_rk.begin(), i-11);
322 CHAM_DecRound< 3, 16>(m_x.begin(), m_rk.begin(), i-12);
323 CHAM_DecRound< 2, 16>(m_x.begin(), m_rk.begin(), i-13);
324 CHAM_DecRound< 1, 16>(m_x.begin(), m_rk.begin(), i-14);
325 CHAM_DecRound< 0, 16>(m_x.begin(), m_rk.begin(), i-15);
326 }
327 break;
328 }
329 default:
330 CRYPTOPP_ASSERT(0);
331 }
332
333 PutBlock<word32, BigEndian> oblock(xorBlock, outBlock);
334 oblock(m_x[0])(m_x[1])(m_x[2])(m_x[3]);
335 }
336
337 #if CRYPTOPP_CHAM128_ADVANCED_PROCESS_BLOCKS
338 size_t CHAM128::Enc::AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks,
339 byte *outBlocks, size_t length, word32 flags) const
340 {
341 # if (CRYPTOPP_SSSE3_AVAILABLE)
342 if (HasSSSE3()) {
343 const size_t rounds = (m_kw == 4 ? 80 : 96);
344 return CHAM128_Enc_AdvancedProcessBlocks_SSSE3(m_rk, rounds,
345 inBlocks, xorBlocks, outBlocks, length, flags);
346 }
347 # endif // CRYPTOPP_SSSE3_AVAILABLE
348 return BlockTransformation::AdvancedProcessBlocks(inBlocks, xorBlocks, outBlocks, length, flags);
349 }
350
351 size_t CHAM128::Dec::AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks,
352 byte *outBlocks, size_t length, word32 flags) const
353 {
354 # if (CRYPTOPP_SSSE3_AVAILABLE)
355 if (HasSSSE3()) {
356 const size_t rounds = (m_kw == 4 ? 80 : 96);
357 return CHAM128_Dec_AdvancedProcessBlocks_SSSE3(m_rk, rounds,
358 inBlocks, xorBlocks, outBlocks, length, flags);
359 }
360 # endif // CRYPTOPP_SSSE3_AVAILABLE
361 return BlockTransformation::AdvancedProcessBlocks(inBlocks, xorBlocks, outBlocks, length, flags);
362 }
363 #endif // CRYPTOPP_CHAM128_ADVANCED_PROCESS_BLOCKS
364
365 NAMESPACE_END
cham.h
Classes for the CHAM block cipher.
BIG_ENDIAN_ORDER
@ BIG_ENDIAN_ORDER
byte order is big-endian
Definition: cryptlib.h:147
CRYPTOPP_ASSERT
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition: trap.h:68
rotlConstant
T rotlConstant(T x)
Performs a left rotate.
Definition: misc.h:1527
pch.h
Precompiled header file.
word32
unsigned int word32
32-bit unsigned datatype
Definition: config_int.h:62
BlockTransformation::AdvancedProcessBlocks
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.
GetBlock
Access a block of memory.
Definition: misc.h:2508
misc.h
Utility functions for the Crypto++ library.
rotrConstant
T rotrConstant(T x)
Performs a right rotate.
Definition: misc.h:1553
PutBlock
Access a block of memory.
Definition: misc.h:2549
cpu.h
Functions for CPU features and intrinsics.
SecBlock::New
void New(size_type newSize)
Change size without preserving contents.
Definition: secblock.h:1022
CryptoPP
Crypto++ library namespace.
config.h
Library configuration file.
NameValuePairs
Interface for retrieving values given their names.
Definition: cryptlib.h:321
word16
unsigned short word16
16-bit unsigned datatype
Definition: config_int.h:59