-
Notifications
You must be signed in to change notification settings - Fork 0
/
aes_tools.cpp
333 lines (271 loc) · 7.7 KB
/
aes_tools.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
/**
* aes_tools.cpp: Ricardo Quezada
* Functions for interact with the AES implementation:
* Generation of pseudo-random keys and modes of operations.
**/
#include<bits/stdc++.h>
#include"aes.h"
#include"aes_tools.h"
using namespace std;
/**
* gen_key: generate a random key of the given size.
* The default size is 256 bits.
* The key is returned as a vector of chars (Array type).
**/
Array gen_key(int key_size)
{
int size = (key_size == KEY_SIZE_256) ? 32 :
(key_size == KEY_SIZE_192) ? 24 :
16;
Array key;
//Use a non-deterministic generator, if available.
random_device r;
default_random_engine engine(r());
uniform_int_distribution<int> uniform_dist(0, 255);
for(int i=0; i<size; i++)
key.push_back(uniform_dist(engine));
return key;
}
/**
* print_hex: print the given data in the given stream.
* The data is printed in hexadecimal format.
* Each byte of the key is separated by a space character.
* The default stream is 'cout'.
**/
void print_hex(Array &key, ostream &out)
{
for(int i=0; i < key.size(); i++)
//std::hex format only integers.
out << hex << (255 & key[i]) << " ";
out << endl;
}
/**
* print_data: print the given data in the given stream.
* The data is printed in ASCII format.
* The default stream is 'cout'.
**/
void print_data(Array &key, ostream &out)
{
for(int i=0; i < key.size(); i++)
out << key[i];
out << endl;
}
/**
* read_key: read a key on the given stream.
* return a Array type (vector<char>).
* Since this is made thinking on files, here are no default value.
**/
Array read_key(istream &in)
{
Array key;
int tmp;
while(in >> hex >> tmp)
key.push_back(tmp);
return key;
}
/**
* process: main public function for process a file.
* It uses the given mode of operation. The input and output
* are given like a streams.
**/
void process(Array key, istream &input, ostream &output ,
int operation, int mode){
long long int size, num_blocks;
int block_size = key.size();
//Generate the AES expansion keys
Data keys = key_schedule(key);
if(operation == ENCRYPTION_MODE){
//A cipher text is already fixed
streampos start = input.tellg();
input.seekg(0, ios::end);
streampos final = input.tellg();
size = final - start;
num_blocks = ceil(size / (double) block_size);
input.seekg(0, ios::beg);
int gap = (block_size - (size % block_size)) % block_size;
//Create and save the inizialitation vector
Array iv = gen_key((block_size == 32) ? KEY_SIZE_256 :
(block_size == 24) ? KEY_SIZE_192 :
KEY_SIZE_128);
write_block(iv, output);
//Save the REAL length
output << size;
if(mode = CBC_MODE)
cbc(keys, iv, num_blocks, gap, input, output);
else
ctr(keys, iv, num_blocks, gap, input, output, operation);
}else{
//Read the initialization vector
Array iv = read_block(block_size, input);
//Read the real length
input >> size;
if(mode = CBC_MODE)
cbc_inverse(keys, iv, size, input, output);
else{
num_blocks = ceil((double)size / block_size);
int gap = size % block_size;
ctr(keys, iv, num_blocks, gap, input, output, operation);
}
}
}
/**
* write_block: simple function for write an Array in the stream.
* The stream must be opened in binary mode (ios::binary).
**/
void write_block(Array &block, ostream &out)
{
int size = block.size();
unsigned char aux[size];
for(int i=0; i<size; i++) aux[i] = block[i];
out.write((char*)aux, size);
}
/**
* read_block: simple function for read an Array from the stream.
* The stream must be opened in binary mode (ios::binary).
**/
Array read_block(int block_size, istream &in)
{
unsigned char aux[block_size];
in.read((char*)aux, block_size);
Array res;
for(int i=0; i<block_size; i++) res.push_back(aux[i]);
return res;
}
/**
* add: simple xoring of the elemento of the two arrays arguments.
* The result is saved in the first argument and a reference of this is
* returned.
**/
Array& add(Array &a, Array &b)
{
for(int i=0; i<a.size(); i++)
a[i] ^= b[i];
return a;
}
/**
* copy: Copy two Arrays objects.
**/
Array copy(Array &org)
{
Array res;
for(int i=0; i<org.size(); i++)
res.push_back(org[i]);
return res;
}
/**
* increment: Increment by n the last element of the Array.
* This is used in the counter mode of operation.
**/
Array increment(Array a, int n)
{
Array aux = copy(a);
aux[a.size() - 1] += n;
return aux;
}
/**
* cbc: Code Block Chaining mode of operation.
* Process the two file streams.
**/
void cbc(Data &keys, Array &iv, long long int num_blocks, int gap,
istream &input, ostream &output)
{
int block_size = iv.size();
if(num_blocks != 1){
Array aux = read_block(block_size, input); //Everithing is done
operate(add(aux, iv), keys, ENCRYPTION_MODE); //over the same Array
write_block(aux, output);
for(int i=1; i<num_blocks - 1; i++){
Array aux2 = read_block(block_size, input);
operate(add(aux, aux2),
keys, ENCRYPTION_MODE);
write_block(aux, output);
}
Array last = read_block(block_size - gap, input);
for(int i=0; i<gap; i++) last.push_back('z');
operate(add(aux, last), keys, ENCRYPTION_MODE);
write_block(aux, output);
}else{
//Only one block
Array last = read_block(block_size - gap, input);
for(int i=0; i<gap; i++) last.push_back('z');
operate(add(last, iv), keys, ENCRYPTION_MODE);
write_block(last, output);
}
}
/**
* cbc_inverse: reverse Code Block Chaining mode of operation.
* Used for decrypting.
**/
void cbc_inverse(Data &keys, Array &iv, long long int size,
istream &input, ostream &output)
{
int block_size = iv.size();
int num_blocks = size / block_size;
int gap = size % block_size;
Array aux, aux2, aux3;
if(num_blocks != 0){
aux = read_block(block_size, input);
aux2 = copy(aux);
operate(aux, keys, DECRYPTION_MODE);
write_block(add(aux, iv), output);
for(int i=1; i<num_blocks; i++){
aux = read_block(block_size, input);
(i & 1) ? aux3 = copy(aux) : aux2 = copy(aux);
operate(aux, keys, DECRYPTION_MODE);
(i & 1) ? write_block(add(aux, aux2), output) :
write_block(add(aux, aux3), output) ;
}
}
if(gap != 0){
aux = read_block(block_size, input);
operate(aux, keys, DECRYPTION_MODE);
for(int i = 0; i < block_size - gap; i++)
aux.pop_back();
if(num_blocks != 0){
(num_blocks & 1) ?
write_block(add(aux, aux2), output) :
write_block(add(aux, aux3), output) ;
}else write_block(add(aux, iv), output) ;
}
}
/**
* ctr: Counter mode.
* Receive the operation (ENCRYPT or DECRYPT). This iis because
* both operations are performed in the same way in this mode.
**/
void ctr(Data &keys, Array &iv, long long int num_blocks, int gap,
istream &input, ostream &output, int mode)
{
int block_size = iv.size();
Array iv_original = copy(iv), aux;
if(num_blocks != 1){
aux = read_block(block_size, input);
operate(iv, keys, mode);
add(iv, aux);
write_block(iv, output);
for(int i=1; i<num_blocks - 1; i++){
aux = read_block(block_size, input);
iv = increment(iv_original, i);
operate(iv, keys, mode);
add(iv, aux);
write_block(iv, output);
}
}
//At least one block
if(mode == ENCRYPTION_MODE){
Array last = read_block(block_size - gap, input);
for(int i=0; i<gap; i++) last.push_back('z');
iv = increment(iv_original, (num_blocks == 1) ? 1 : num_blocks - 1);
operate(iv, keys, mode);
add(iv, last);
write_block(iv, output);
}else{
aux = read_block(block_size, input);
iv = increment(iv_original, (num_blocks == 1) ? 1 : num_blocks - 1);
operate(iv, keys, mode);
add(iv, aux);
for(int i = 0; i < block_size - gap; i++)
iv.pop_back();
write_block(iv, output);
}
}