Crypto++  6.1
Free C++ class library of cryptographic schemes
aria.cpp
1 // aria.cpp - written and placed in the public domain by Jeffrey Walton
2 
3 #include "pch.h"
4 #include "config.h"
5 
6 #include "aria.h"
7 #include "misc.h"
8 #include "cpu.h"
9 
10 #if CRYPTOPP_SSE2_INTRIN_AVAILABLE
11 # define CRYPTOPP_ENABLE_ARIA_SSE2_INTRINSICS 1
12 #endif
13 
14 #if CRYPTOPP_SSSE3_AVAILABLE
15 # define CRYPTOPP_ENABLE_ARIA_SSSE3_INTRINSICS 1
16 #endif
17 
18 // GCC cast warning
19 #define UINT32_CAST(x) ((uint32_t *)(void *)(x))
20 #define CONST_UINT32_CAST(x) ((const uint32_t *)(const void *)(x))
21 
22 NAMESPACE_BEGIN(CryptoPP)
23 NAMESPACE_BEGIN(ARIATab)
24 
25 extern const word32 S1[256];
26 extern const word32 S2[256];
27 extern const word32 X1[256];
28 extern const word32 X2[256];
29 extern const word32 KRK[3][4];
30 
31 NAMESPACE_END
32 NAMESPACE_END
33 
34 NAMESPACE_BEGIN(CryptoPP)
35 
36 using CryptoPP::ARIATab::S1;
37 using CryptoPP::ARIATab::S2;
38 using CryptoPP::ARIATab::X1;
39 using CryptoPP::ARIATab::X2;
40 using CryptoPP::ARIATab::KRK;
41 
44 
45 inline byte ARIA_BRF(const word32 x, const int y) {
46  return GETBYTE(x, y);
47 }
48 
49 // Key XOR Layer
50 #define ARIA_KXL { \
51  NativeEndianBlock::Put(rk, t)(t[0])(t[1])(t[2])(t[3]); \
52  }
53 
54 // S-Box Layer 1 + M
55 #define SBL1_M(T0,T1,T2,T3) { \
56  T0=S1[ARIA_BRF(T0,3)]^S2[ARIA_BRF(T0,2)]^X1[ARIA_BRF(T0,1)]^X2[ARIA_BRF(T0,0)]; \
57  T1=S1[ARIA_BRF(T1,3)]^S2[ARIA_BRF(T1,2)]^X1[ARIA_BRF(T1,1)]^X2[ARIA_BRF(T1,0)]; \
58  T2=S1[ARIA_BRF(T2,3)]^S2[ARIA_BRF(T2,2)]^X1[ARIA_BRF(T2,1)]^X2[ARIA_BRF(T2,0)]; \
59  T3=S1[ARIA_BRF(T3,3)]^S2[ARIA_BRF(T3,2)]^X1[ARIA_BRF(T3,1)]^X2[ARIA_BRF(T3,0)]; \
60  }
61 
62 // S-Box Layer 2 + M
63 #define SBL2_M(T0,T1,T2,T3) { \
64  T0=X1[ARIA_BRF(T0,3)]^X2[ARIA_BRF(T0,2)]^S1[ARIA_BRF(T0,1)]^S2[ARIA_BRF(T0,0)]; \
65  T1=X1[ARIA_BRF(T1,3)]^X2[ARIA_BRF(T1,2)]^S1[ARIA_BRF(T1,1)]^S2[ARIA_BRF(T1,0)]; \
66  T2=X1[ARIA_BRF(T2,3)]^X2[ARIA_BRF(T2,2)]^S1[ARIA_BRF(T2,1)]^S2[ARIA_BRF(T2,0)]; \
67  T3=X1[ARIA_BRF(T3,3)]^X2[ARIA_BRF(T3,2)]^S1[ARIA_BRF(T3,1)]^S2[ARIA_BRF(T3,0)]; \
68  }
69 
70 #define ARIA_P(T0,T1,T2,T3) { \
71  (T1) = (((T1)<< 8)&0xff00ff00) ^ (((T1)>> 8)&0x00ff00ff); \
72  (T2) = rotrConstant<16>(T2); \
73  (T3) = ByteReverse((T3)); \
74  }
75 
76 #define ARIA_M(X,Y) { \
77  Y=(X)<<8 ^ (X)>>8 ^ (X)<<16 ^ (X)>>16 ^ (X)<<24 ^ (X)>>24; \
78  }
79 
80 #define ARIA_MM(T0,T1,T2,T3) { \
81  (T1)^=(T2); (T2)^=(T3); (T0)^=(T1); \
82  (T3)^=(T1); (T2)^=(T0); (T1)^=(T2); \
83  }
84 
85 #define ARIA_FO {SBL1_M(t[0],t[1],t[2],t[3]) ARIA_MM(t[0],t[1],t[2],t[3]) ARIA_P(t[0],t[1],t[2],t[3]) ARIA_MM(t[0],t[1],t[2],t[3])}
86 #define ARIA_FE {SBL2_M(t[0],t[1],t[2],t[3]) ARIA_MM(t[0],t[1],t[2],t[3]) ARIA_P(t[2],t[3],t[0],t[1]) ARIA_MM(t[0],t[1],t[2],t[3])}
87 
88 #if (CRYPTOPP_ARM_NEON_AVAILABLE)
89 extern void ARIA_UncheckedSetKey_Schedule_NEON(byte* rk, word32* ws, unsigned int keylen);
90 extern void ARIA_ProcessAndXorBlock_Xor_NEON(const byte* xorBlock, byte* outblock);
91 #endif
92 
93 #if (CRYPTOPP_SSSE3_AVAILABLE)
94 extern void ARIA_ProcessAndXorBlock_Xor_SSSE3(const byte* xorBlock, byte* outBlock, const byte *rk, word32 *t);
95 #endif
96 
97 // n-bit right shift of Y XORed to X
98 template <unsigned int N>
99 inline void ARIA_GSRK(const word32 X[4], const word32 Y[4], byte RK[16])
100 {
101  // MSVC is not generating a "rotate immediate". Constify to help it along.
102  static const unsigned int Q = 4-(N/32);
103  static const unsigned int R = N % 32;
104  UINT32_CAST(RK)[0] = (X[0]) ^ ((Y[(Q )%4])>>R) ^ ((Y[(Q+3)%4])<<(32-R));
105  UINT32_CAST(RK)[1] = (X[1]) ^ ((Y[(Q+1)%4])>>R) ^ ((Y[(Q )%4])<<(32-R));
106  UINT32_CAST(RK)[2] = (X[2]) ^ ((Y[(Q+2)%4])>>R) ^ ((Y[(Q+1)%4])<<(32-R));
107  UINT32_CAST(RK)[3] = (X[3]) ^ ((Y[(Q+3)%4])>>R) ^ ((Y[(Q+2)%4])<<(32-R));
108 }
109 
110 void ARIA::Base::UncheckedSetKey(const byte *key, unsigned int keylen, const NameValuePairs &params)
111 {
112  CRYPTOPP_UNUSED(params);
113 
114  m_rk.New(16*17); // round keys
115  m_w.New(4*7); // w0, w1, w2, w3, t and u
116 
117  const byte *mk = key;
118  byte *rk = m_rk.data();
119  int Q, q, R, r;
120 
121  switch (keylen)
122  {
123  case 16:
124  R = r = m_rounds = 12;
125  Q = q = 0;
126  break;
127  case 32:
128  R = r = m_rounds = 16;
129  Q = q = 2;
130  break;
131  case 24:
132  R = r = m_rounds = 14;
133  Q = q = 1;
134  break;
135  default:
136  Q = q = R = r = m_rounds = 0;
137  CRYPTOPP_ASSERT(0);
138  }
139 
140  // w0 has room for 32 bytes. w1-w3 each has room for 16 bytes. t and u are 16 byte temp areas.
141  word32 *w0 = m_w.data(), *w1 = m_w.data()+8, *w2 = m_w.data()+12, *w3 = m_w.data()+16, *t = m_w.data()+20;
142 
143  BigEndianBlock::Get(mk)(w0[0])(w0[1])(w0[2])(w0[3]);
144  t[0]=w0[0]^KRK[q][0]; t[1]=w0[1]^KRK[q][1];
145  t[2]=w0[2]^KRK[q][2]; t[3]=w0[3]^KRK[q][3];
146 
147  ARIA_FO;
148 
149  if (keylen == 32)
150  {
151  BigEndianBlock::Get(mk+16)(w1[0])(w1[1])(w1[2])(w1[3]);
152  }
153  else if (keylen == 24)
154  {
155  BigEndianBlock::Get(mk+16)(w1[0])(w1[1]);
156  w1[2] = w1[3] = 0;
157  }
158  else
159  {
160  w1[0]=w1[1]=w1[2]=w1[3]=0;
161  }
162 
163  w1[0]^=t[0]; w1[1]^=t[1]; w1[2]^=t[2]; w1[3]^=t[3];
164  ::memcpy(t, w1, 16);
165 
166  q = (q==2) ? 0 : (q+1);
167  t[0]^=KRK[q][0]; t[1]^=KRK[q][1]; t[2]^=KRK[q][2]; t[3]^=KRK[q][3];
168 
169  ARIA_FE;
170 
171  t[0]^=w0[0]; t[1]^=w0[1]; t[2]^=w0[2]; t[3]^=w0[3];
172  ::memcpy(w2, t, 16);
173 
174  q = (q==2) ? 0 : (q+1);
175  t[0]^=KRK[q][0]; t[1]^=KRK[q][1]; t[2]^=KRK[q][2]; t[3]^=KRK[q][3];
176 
177  ARIA_FO;
178 
179  w3[0]=t[0]^w1[0]; w3[1]=t[1]^w1[1]; w3[2]=t[2]^w1[2]; w3[3]=t[3]^w1[3];
180 
181 #if CRYPTOPP_ARM_NEON_AVAILABLE
182  if (HasNEON())
183  {
184  ARIA_UncheckedSetKey_Schedule_NEON(rk, m_w, keylen);
185  }
186  else
187 #endif // CRYPTOPP_ARM_NEON_AVAILABLE
188  {
189  ARIA_GSRK<19>(w0, w1, rk + 0);
190  ARIA_GSRK<19>(w1, w2, rk + 16);
191  ARIA_GSRK<19>(w2, w3, rk + 32);
192  ARIA_GSRK<19>(w3, w0, rk + 48);
193  ARIA_GSRK<31>(w0, w1, rk + 64);
194  ARIA_GSRK<31>(w1, w2, rk + 80);
195  ARIA_GSRK<31>(w2, w3, rk + 96);
196  ARIA_GSRK<31>(w3, w0, rk + 112);
197  ARIA_GSRK<67>(w0, w1, rk + 128);
198  ARIA_GSRK<67>(w1, w2, rk + 144);
199  ARIA_GSRK<67>(w2, w3, rk + 160);
200  ARIA_GSRK<67>(w3, w0, rk + 176);
201  ARIA_GSRK<97>(w0, w1, rk + 192);
202 
203  if (keylen > 16)
204  {
205  ARIA_GSRK<97>(w1, w2, rk + 208);
206  ARIA_GSRK<97>(w2, w3, rk + 224);
207 
208  if (keylen > 24)
209  {
210  ARIA_GSRK< 97>(w3, w0, rk + 240);
211  ARIA_GSRK<109>(w0, w1, rk + 256);
212  }
213  }
214  }
215 
216  // Decryption operation
217  if (!IsForwardTransformation())
218  {
219  word32 *a, *z, *s;
220  rk = m_rk.data();
221  r = R; q = Q;
222 
223  a=UINT32_CAST(rk); s=m_w.data()+24; z=a+r*4;
224  ::memcpy(t, a, 16); ::memcpy(a, z, 16); ::memcpy(z, t, 16);
225 
226  a+=4; z-=4;
227  for (; a<z; a+=4, z-=4)
228  {
229  ARIA_M(a[0],t[0]); ARIA_M(a[1],t[1]); ARIA_M(a[2],t[2]); ARIA_M(a[3],t[3]);
230  ARIA_MM(t[0],t[1],t[2],t[3]); ARIA_P(t[0],t[1],t[2],t[3]); ARIA_MM(t[0],t[1],t[2],t[3]);
231  ::memcpy(s, t, 16);
232 
233  ARIA_M(z[0],t[0]); ARIA_M(z[1],t[1]); ARIA_M(z[2],t[2]); ARIA_M(z[3],t[3]);
234  ARIA_MM(t[0],t[1],t[2],t[3]); ARIA_P(t[0],t[1],t[2],t[3]); ARIA_MM(t[0],t[1],t[2],t[3]);
235  ::memcpy(a, t, 16); ::memcpy(z, s, 16);
236  }
237 
238  ARIA_M(a[0],t[0]); ARIA_M(a[1],t[1]); ARIA_M(a[2],t[2]); ARIA_M(a[3],t[3]);
239  ARIA_MM(t[0],t[1],t[2],t[3]); ARIA_P(t[0],t[1],t[2],t[3]); ARIA_MM(t[0],t[1],t[2],t[3]);
240  ::memcpy(z, t, 16);
241  }
242 
243  // Silence warnings
244  CRYPTOPP_UNUSED(Q); CRYPTOPP_UNUSED(R);
245  CRYPTOPP_UNUSED(q); CRYPTOPP_UNUSED(r);
246 }
247 
248 void ARIA::Base::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const
249 {
250  const byte *rk = reinterpret_cast<const byte*>(m_rk.data());
251  word32 *t = const_cast<word32*>(m_w.data()+20);
252 
253  // Timing attack countermeasure. See comments in Rijndael for more details.
254  // We used Yun's 32-bit implementation, so we use words rather than bytes.
255  const int cacheLineSize = GetCacheLineSize();
256  unsigned int i;
257  volatile word32 _u = 0;
258  word32 u = _u;
259 
260  for (i=0; i<COUNTOF(S1); i+=cacheLineSize/(sizeof(S1[0])))
261  u |= *(S1+i);
262  t[0] |= u;
263 
264  BigEndianBlock::Get(inBlock)(t[0])(t[1])(t[2])(t[3]);
265 
266  if (m_rounds > 12) {
267  ARIA_KXL; rk+= 16; ARIA_FO;
268  ARIA_KXL; rk+= 16; ARIA_FE;
269  }
270 
271  if (m_rounds > 14) {
272  ARIA_KXL; rk+= 16; ARIA_FO;
273  ARIA_KXL; rk+= 16; ARIA_FE;
274  }
275 
276  ARIA_KXL; rk+= 16; ARIA_FO; ARIA_KXL; rk+= 16; ARIA_FE;
277  ARIA_KXL; rk+= 16; ARIA_FO; ARIA_KXL; rk+= 16; ARIA_FE;
278  ARIA_KXL; rk+= 16; ARIA_FO; ARIA_KXL; rk+= 16; ARIA_FE;
279  ARIA_KXL; rk+= 16; ARIA_FO; ARIA_KXL; rk+= 16; ARIA_FE;
280  ARIA_KXL; rk+= 16; ARIA_FO; ARIA_KXL; rk+= 16; ARIA_FE;
281  ARIA_KXL; rk+= 16; ARIA_FO; ARIA_KXL; rk+= 16;
282 
283 #ifdef CRYPTOPP_LITTLE_ENDIAN
284 # if CRYPTOPP_ENABLE_ARIA_SSSE3_INTRINSICS
285  if (HasSSSE3())
286  {
287  ARIA_ProcessAndXorBlock_Xor_SSSE3(xorBlock, outBlock, rk, t);
288  return;
289  }
290  else
291 # endif // CRYPTOPP_ENABLE_ARIA_SSSE3_INTRINSICS
292  {
293  outBlock[ 0] = (byte)(X1[ARIA_BRF(t[0],3)] ) ^ rk[ 3];
294  outBlock[ 1] = (byte)(X2[ARIA_BRF(t[0],2)]>>8) ^ rk[ 2];
295  outBlock[ 2] = (byte)(S1[ARIA_BRF(t[0],1)] ) ^ rk[ 1];
296  outBlock[ 3] = (byte)(S2[ARIA_BRF(t[0],0)] ) ^ rk[ 0];
297  outBlock[ 4] = (byte)(X1[ARIA_BRF(t[1],3)] ) ^ rk[ 7];
298  outBlock[ 5] = (byte)(X2[ARIA_BRF(t[1],2)]>>8) ^ rk[ 6];
299  outBlock[ 6] = (byte)(S1[ARIA_BRF(t[1],1)] ) ^ rk[ 5];
300  outBlock[ 7] = (byte)(S2[ARIA_BRF(t[1],0)] ) ^ rk[ 4];
301  outBlock[ 8] = (byte)(X1[ARIA_BRF(t[2],3)] ) ^ rk[11];
302  outBlock[ 9] = (byte)(X2[ARIA_BRF(t[2],2)]>>8) ^ rk[10];
303  outBlock[10] = (byte)(S1[ARIA_BRF(t[2],1)] ) ^ rk[ 9];
304  outBlock[11] = (byte)(S2[ARIA_BRF(t[2],0)] ) ^ rk[ 8];
305  outBlock[12] = (byte)(X1[ARIA_BRF(t[3],3)] ) ^ rk[15];
306  outBlock[13] = (byte)(X2[ARIA_BRF(t[3],2)]>>8) ^ rk[14];
307  outBlock[14] = (byte)(S1[ARIA_BRF(t[3],1)] ) ^ rk[13];
308  outBlock[15] = (byte)(S2[ARIA_BRF(t[3],0)] ) ^ rk[12];
309  }
310 #else
311  outBlock[ 0] = (byte)(X1[ARIA_BRF(t[0],3)] );
312  outBlock[ 1] = (byte)(X2[ARIA_BRF(t[0],2)]>>8);
313  outBlock[ 2] = (byte)(S1[ARIA_BRF(t[0],1)] );
314  outBlock[ 3] = (byte)(S2[ARIA_BRF(t[0],0)] );
315  outBlock[ 4] = (byte)(X1[ARIA_BRF(t[1],3)] );
316  outBlock[ 5] = (byte)(X2[ARIA_BRF(t[1],2)]>>8);
317  outBlock[ 6] = (byte)(S1[ARIA_BRF(t[1],1)] );
318  outBlock[ 7] = (byte)(S2[ARIA_BRF(t[1],0)] );
319  outBlock[ 8] = (byte)(X1[ARIA_BRF(t[2],3)] );
320  outBlock[ 9] = (byte)(X2[ARIA_BRF(t[2],2)]>>8);
321  outBlock[10] = (byte)(S1[ARIA_BRF(t[2],1)] );
322  outBlock[11] = (byte)(S2[ARIA_BRF(t[2],0)] );
323  outBlock[12] = (byte)(X1[ARIA_BRF(t[3],3)] );
324  outBlock[13] = (byte)(X2[ARIA_BRF(t[3],2)]>>8);
325  outBlock[14] = (byte)(S1[ARIA_BRF(t[3],1)] );
326  outBlock[15] = (byte)(S2[ARIA_BRF(t[3],0)] );
327 
328  t = UINT32_CAST(outBlock);
329  BigEndianBlock::Put(rk, t)(t[0])(t[1])(t[2])(t[3]);
330 #endif // CRYPTOPP_LITTLE_ENDIAN
331 
332 #if CRYPTOPP_ARM_NEON_AVAILABLE
333  if (HasNEON())
334  {
335  if (xorBlock != NULLPTR)
336  ARIA_ProcessAndXorBlock_Xor_NEON(xorBlock, outBlock);
337  }
338  else
339 #endif // CRYPTOPP_ARM_NEON_AVAILABLE
340  {
341  if (xorBlock != NULLPTR)
342  for (unsigned int n=0; n<ARIA::BLOCKSIZE; ++n)
343  outBlock[n] ^= xorBlock[n];
344  }
345 }
346 
347 NAMESPACE_END
Utility functions for the Crypto++ library.
bool HasSSSE3()
Determines SSSE3 availability.
Definition: cpu.h:129
Library configuration file.
int GetCacheLineSize()
Provides the cache line size.
Definition: cpu.h:298
void New(size_type newSize)
Change size without preserving contents.
Definition: secblock.h:729
Access a block of memory.
Definition: misc.h:2402
A::pointer data()
Provides a pointer to the first element in the memory block.
Definition: secblock.h:553
Precompiled header file.
#define COUNTOF(arr)
Counts elements in an array.
Definition: misc.h:181
Classes for the ARIA block cipher.
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition: trap.h:60
Functions for CPU features and intrinsics.
Access a block of memory.
Definition: misc.h:2365
Crypto++ library namespace.
static const int BLOCKSIZE
The block size of the algorithm provided as a constant.
Definition: seckey.h:44
bool HasNEON()
Determine if an ARM processor has Advanced SIMD available.
Definition: cpu.h:329
Interface for retrieving values given their names.
Definition: cryptlib.h:290