1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // AESCrypt.cc
4 // -----------
5 // AES encryption implementation
6 //
7 // Design and Implementation by Bjoern Lemke
8 //
9 // (C)opyright 2010-2016 Bjoern Lemke
10 //
11 //
12 // IMPLEMENTATION MODULE
13 //
14 // Class: AESCrpyt
15 //
16 // Description: AES encryption
17 // The code has been derived from
18 //
19 // Niyaz PK
20 // E-mail: niyazpk@gmail.com
21 // Downloaded from Website: www.hoozi.com
22 //
23 // Status: CLEAN
24 //
25 ///////////////////////////////////////////////////////////////////////////////
26
27 // Include stdio.h for standard input/output.
28 // Used for giving output to the screen.
29 // #include<stdio.h>
30
31 #include "Exception.h"
32 #include "AESCrypt.h"
33
34 // The number of columns comprising a state in AES. This is a constant in AES. Value=4
35 #define Nb 4
36
37 // xtime is a macro that finds the product of {02} and the argument to xtime modulo {1b}
38 // #define xtime(x) ((x<<1) ^ (((x>>7) & 1) * 0x1b))
39
AESCrypt()40 AESCrypt::AESCrypt()
41 {
42 }
43
AESCrypt(const Chain & keyString,int keyLen)44 AESCrypt::AESCrypt(const Chain& keyString, int keyLen)
45 {
46 // The number of rounds in AES Cipher. It is simply initiated to zero. The actual value is recieved in the program.
47 _Nr=0;
48 // The number of 32 bit words in the key. It is simply initiated to zero. The actual value is recieved in the program.
49 _Nk=0;
50
51 _Nr=keyLen;
52
53 // Calculate Nk and Nr from the received value.
54 _Nk = _Nr / 32;
55 _Nr = _Nk + 6;
56
57 if ( keyString.length() < _Nk*4 )
58 throw Exception(EXLOC, "Key string too short");
59
60 // keyLen must be either 128,192 or 256
61 if ( keyLen != 128 && keyLen !=192 && keyLen != 256 )
62 throw Exception(EXLOC, "Invalid keylen ( 128,192 or 256 are valid )");
63
64 // Copy the Key and PlainText
65 for(int i=0; i<_Nk*4; i++)
66 {
67 _Key[i]=keyString[i];
68 // _in[i]=temp2[i];
69 }
70
71 // The KeyExpansion routine must be called before encryption.
72 KeyExpansion();
73
74 }
75
~AESCrypt()76 AESCrypt::~AESCrypt()
77 {
78 }
79
getSBoxValue(int num)80 unsigned char AESCrypt::getSBoxValue(int num)
81 {
82 unsigned char sbox[256] = {
83 //0 1 2 3 4 5 6 7 8 9 A B C D E F
84 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, //0
85 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, //1
86 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, //2
87 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, //3
88 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, //4
89 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, //5
90 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, //6
91 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, //7
92 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, //8
93 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, //9
94 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, //A
95 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, //B
96 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, //C
97 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, //D
98 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, //E
99 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; //F
100 return sbox[num];
101 }
102
103 // The round constant word array, Rcon[i], contains the values given by
104 // x to th e power (i-1) being powers of x (x is denoted as {02}) in the field GF(28)
105 // Note that i starts at 1, not 0).
getRconValue(int num)106 unsigned char AESCrypt::getRconValue(int num)
107 {
108 unsigned char rcon[255] = {
109
110 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
111 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39,
112 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
113 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
114 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef,
115 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
116 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b,
117 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,
118 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,
119 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
120 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35,
121 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,
122 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,
123 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63,
124 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
125 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb };
126 return rcon[num];
127 }
128
129 // This function produces Nb(Nr+1) round keys. The round keys are used in each round to encrypt the states.
KeyExpansion()130 void AESCrypt::KeyExpansion()
131 {
132 int i,j;
133 unsigned char temp[4],k;
134
135 // The first round key is the key itself.
136 for(i=0;i<_Nk;i++)
137 {
138 _RoundKey[i*4]=_Key[i*4];
139 _RoundKey[i*4+1]=_Key[i*4+1];
140 _RoundKey[i*4+2]=_Key[i*4+2];
141 _RoundKey[i*4+3]=_Key[i*4+3];
142 }
143
144 // All other round keys are found from the previous round keys.
145 while (i < (Nb * (_Nr+1)))
146 {
147 for(j=0;j<4;j++)
148 {
149 temp[j]=_RoundKey[(i-1) * 4 + j];
150 }
151 if (i % _Nk == 0)
152 {
153 // This function rotates the 4 bytes in a word to the left once.
154 // [a0,a1,a2,a3] becomes [a1,a2,a3,a0]
155
156 // Function RotWord()
157 {
158 k = temp[0];
159 temp[0] = temp[1];
160 temp[1] = temp[2];
161 temp[2] = temp[3];
162 temp[3] = k;
163 }
164
165 // SubWord() is a function that takes a four-byte input word and
166 // applies the S-box to each of the four bytes to produce an output word.
167
168 // Function Subword()
169 {
170 temp[0]=getSBoxValue(temp[0]);
171 temp[1]=getSBoxValue(temp[1]);
172 temp[2]=getSBoxValue(temp[2]);
173 temp[3]=getSBoxValue(temp[3]);
174 }
175
176 temp[0] = temp[0] ^ getRconValue(i/_Nk);
177 }
178 else if (_Nk > 6 && i % _Nk == 4)
179 {
180 // Function Subword()
181 {
182 temp[0]=getSBoxValue(temp[0]);
183 temp[1]=getSBoxValue(temp[1]);
184 temp[2]=getSBoxValue(temp[2]);
185 temp[3]=getSBoxValue(temp[3]);
186 }
187 }
188 _RoundKey[i*4+0] = _RoundKey[(i-_Nk)*4+0] ^ temp[0];
189 _RoundKey[i*4+1] = _RoundKey[(i-_Nk)*4+1] ^ temp[1];
190 _RoundKey[i*4+2] = _RoundKey[(i-_Nk)*4+2] ^ temp[2];
191 _RoundKey[i*4+3] = _RoundKey[(i-_Nk)*4+3] ^ temp[3];
192 i++;
193 }
194 }
195
196 // This function adds the round key to state.
197 // The round key is added to the state by an XOR function.
AddRoundKey(int round)198 void AESCrypt::AddRoundKey(int round)
199 {
200 int i,j;
201 for(i=0;i<4;i++)
202 {
203 for(j=0;j<4;j++)
204 {
205 _state[j][i] ^= _RoundKey[round * Nb * 4 + i * Nb + j];
206 }
207 }
208 }
209
210 // The SubBytes Function Substitutes the values in the
211 // state matrix with values in an S-box.
SubBytes()212 void AESCrypt::SubBytes()
213 {
214 int i,j;
215 for(i=0;i<4;i++)
216 {
217 for(j=0;j<4;j++)
218 {
219 _state[i][j] = getSBoxValue(_state[i][j]);
220 }
221 }
222 }
223
224 // The ShiftRows() function shifts the rows in the state to the left.
225 // Each row is shifted with different offset.
226 // Offset = Row number. So the first row is not shifted.
ShiftRows()227 void AESCrypt::ShiftRows()
228 {
229 unsigned char temp;
230
231 // Rotate first row 1 columns to left
232 temp=_state[1][0];
233 _state[1][0]=_state[1][1];
234 _state[1][1]=_state[1][2];
235 _state[1][2]=_state[1][3];
236 _state[1][3]=temp;
237
238 // Rotate second row 2 columns to left
239 temp=_state[2][0];
240 _state[2][0]=_state[2][2];
241 _state[2][2]=temp;
242
243 temp=_state[2][1];
244 _state[2][1]=_state[2][3];
245 _state[2][3]=temp;
246
247 // Rotate third row 3 columns to left
248 temp=_state[3][0];
249 _state[3][0]=_state[3][3];
250 _state[3][3]=_state[3][2];
251 _state[3][2]=_state[3][1];
252 _state[3][1]=temp;
253 }
254
255 // MixColumns function mixes the columns of the state matrix
256 // The method used may look complicated, but it is easy if you know the underlying theory.
257 // Refer the documents specified above.
MixColumns()258 void AESCrypt::MixColumns()
259 {
260 int i;
261 unsigned char Tmp,Tm,t;
262 for(i=0;i<4;i++)
263 {
264 t=_state[0][i];
265 Tmp = _state[0][i] ^ _state[1][i] ^ _state[2][i] ^ _state[3][i] ;
266 Tm = _state[0][i] ^ _state[1][i] ; Tm = xtime(Tm); _state[0][i] ^= Tm ^ Tmp ;
267 Tm = _state[1][i] ^ _state[2][i] ; Tm = xtime(Tm); _state[1][i] ^= Tm ^ Tmp ;
268 Tm = _state[2][i] ^ _state[3][i] ; Tm = xtime(Tm); _state[2][i] ^= Tm ^ Tmp ;
269 Tm = _state[3][i] ^ t ; Tm = xtime(Tm); _state[3][i] ^= Tm ^ Tmp ;
270 }
271 }
272
xtime(unsigned char x)273 unsigned char AESCrypt::xtime(unsigned char x)
274 {
275 unsigned char v = ((x<<1) ^ (((x>>7) & 1) * 0x1b));
276 return v;
277 }
278
279 // Cipher is the main function that encrypts the PlainText.
Cipher()280 void AESCrypt::Cipher()
281 {
282 int i,j,round=0;
283
284 //Copy the input PlainText to state array.
285 for(i=0;i<4;i++)
286 {
287 for(j=0;j<4;j++)
288 {
289 _state[j][i] = _in[i*4 + j];
290 }
291 }
292
293 // Add the First round key to the state before starting the rounds.
294 AddRoundKey(0);
295
296 // There will be Nr rounds.
297 // The first Nr-1 rounds are identical.
298 // These Nr-1 rounds are executed in the loop below.
299 for(round=1;round<_Nr;round++)
300 {
301 SubBytes();
302 ShiftRows();
303 MixColumns();
304 AddRoundKey(round);
305 }
306
307 // The last round is given below.
308 // The MixColumns function is not here in the last round.
309 SubBytes();
310 ShiftRows();
311 AddRoundKey(_Nr);
312
313 // The encryption process is over.
314 // Copy the state array to output array.
315 for(i=0;i<4;i++)
316 {
317 for(j=0;j<4;j++)
318 {
319 _out[i*4+j]=_state[j][i];
320 }
321 }
322 }
323
324 #define MAXOUTBUF 1024
325
encrypt(const Chain & val)326 Chain AESCrypt::encrypt(const Chain& val)
327 {
328
329 // Receive the length of key here.
330 // while(Nr!=128 && Nr!=192 && Nr!=256)
331 // {
332 // printf("Enter the length of Key(128, 192 or 256 only): ");
333 // scanf("%d",&Nr);
334 // }
335
336 // The array temp stores the key.
337 // The array temp2 stores the plaintext.
338 // unsigned char temp[16] = {0x00 ,0x01 ,0x02 ,0x03 ,0x04 ,0x05 ,0x06 ,0x07 ,0x08 ,0x09 ,0x0a ,0x0b ,0x0c ,0x0d ,0x0e ,0x0f};
339 // unsigned char temp2[16]= {0x00 ,0x11 ,0x22 ,0x33 ,0x44 ,0x55 ,0x66 ,0x77 ,0x88 ,0x99 ,0xaa ,0xbb ,0xcc ,0xdd ,0xee ,0xff};
340
341 char outBuf[MAXOUTBUF];
342
343 int i;
344 int offset=0;
345
346 for ( i=0; i<val.length(); i+=16 )
347 {
348
349 int j;
350
351 // Copy the Key and PlainText
352 for(j=0; j<16; j++)
353 {
354 if ( i+j < val.length() )
355 _in[j]=val[i + j];
356 else
357 _in[j]=0;
358 }
359
360 // The next function call encrypts the PlainText with the Key using AES algorithm.
361 Cipher();
362
363 // Output the encrypted text.
364
365 for(j=0; j<16; j++)
366 {
367 // outBuf[i*16+j] = _out[j];
368 // cout << "Pos=" << i+j << " Val=" << (int)_out[j] << endl;
369 sprintf(outBuf+offset, "%02x", _out[j]);
370 offset=offset+2;
371
372 // outBuf[i*16+j+1] = 0;
373 }
374 }
375
376 Chain outString(outBuf);
377 return outString;
378 }
379