-
Notifications
You must be signed in to change notification settings - Fork 112
/
EncTools.cpp
175 lines (145 loc) · 6.04 KB
/
EncTools.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
//
// Created by Dusan Klinec on 30.12.17.
//
#include <stdexcept>
#include "EncTools.h"
#include "GenericAES.h"
#include "WBAESGenerator.h"
#include "RingBuffer.h"
void EncTools::processData(bool decrypt, WBAES * wbaes, WBAESGenerator * generator,
InputObject<BYTE> * inf, InputObject<BYTE> * out,
ExtEncoding * coding, bool padding, bool cbc, BYTE * iv,
time_t *cacc, clock_t * pacc)
{
// read the file
const int buffSize = 4096;
const long int iters = buffSize / N_BYTES;
const unique_ptr<RingBuffer<BYTE>> buffer = unique_ptr<RingBuffer<BYTE>>(new RingBuffer<BYTE>(buffSize + N_BYTES));
unsigned long long blockCount = 0;
char blockbuff[N_BYTES];
char blockBuffOut[N_BYTES];
char prevBlock[N_BYTES] = {0};
bool paddingOk = true;
unsigned int paddingByte=0;
// IV cbc decryption init
if (cbc){
iv ? memcpy(prevBlock, iv, N_BYTES) : memset(prevBlock, 0, N_BYTES);
}
// time measurement of just the cipher operation
time_t cstart=0, cend=0;
if (cacc){
*cacc = 0;
}
clock_t pstart=0, pend=0;
if (pacc){
*pacc = 0;
}
// measure the time here
bool eof = false;
do {
// read data from the file to the buffer
streamsize bRead = buffer->write(inf, buffSize);
streamsize bufferSize = buffer->getBytesAvailable();
eof = inf->eof();
if (!eof && !inf->isGood()) {
break;
}
// here we have data in the buffer - lets encrypt them
W128b state{};
auto blocks = (float)bufferSize / N_BYTES;
auto blocks_rounded = (long int) (eof ? ceil(blocks) : floor(blocks));
auto iter2comp = min(iters, blocks_rounded);
// Padding not enabled but input data is not block aligned - exception.
if (eof && (!padding || decrypt) && (long int)blocks != blocks_rounded){
throw std::invalid_argument("Error: Padding not enabled, input data not block aligned");
}
if (eof && coding && coding->flags != WBAESGEN_EXTGEN_ID && (long int)blocks != blocks_rounded){
throw std::invalid_argument("Error: External IO encodings used, input has to be block aligned (processed by external IO encoding)");
}
// PKCS5 padding bytes computation so the input is block aligned
if (eof && padding && !decrypt && coding->flags == WBAESGEN_EXTGEN_ID){
auto missingBytes = (blocks_rounded * N_BYTES - bufferSize);
paddingByte = static_cast<unsigned int>(missingBytes == 0 ? N_BYTES : missingBytes);
assert(paddingByte > 0 && paddingByte <= N_BYTES && "Padding size is invalid");
iter2comp += missingBytes == 0 ? 1 : 0;
}
for(int k = 0; k < iter2comp; k++, blockCount++){
// Read 1 AES block from the ring buffer.
ssize_t bytesRead = buffer->read((BYTE*)blockbuff, N_BYTES);
// Pad to 16 bytes before IO encodings - may happen for the last block
if (bytesRead >= 0 && bytesRead != N_BYTES){
memset(blockbuff + bytesRead, 0, static_cast<size_t>(N_BYTES - bytesRead));
}
// strip IO encodings before processing further.
if (coding && generator && coding->flags != WBAESGEN_EXTGEN_ID) {
generator->applyExternalEnc((BYTE*)blockbuff, coding, true);
}
// Encryption padding
if (eof && padding && !decrypt && k + 1 >= iter2comp) {
memset(blockbuff + 16 - paddingByte, (char) paddingByte, (size_t) paddingByte);
}
// CBC xor for encryption
if (cbc && !decrypt){
EncTools::xorIv((BYTE*)blockbuff, (BYTE*)prevBlock);
}
// Timing - core cipher
if (cacc) {
time(&cstart);
}
if(pacc) {
pstart = clock();
}
// Cipher main operation
arr_to_W128b(blockbuff, 0, state);
if (decrypt){
wbaes->decrypt(state);
} else {
wbaes->encrypt(state);
}
W128b_to_arr(blockBuffOut, 0, state);
// Timing - core cipher
if (pacc) {
pend = clock();
*pacc += (pend - pstart);
}
if (cacc) {
time(&cend);
*cacc += (cend - cstart);
}
// result of the cipher operation
ssize_t writeBytes = N_BYTES;
// Decrypt CBC
if (cbc && decrypt){
EncTools::xorIv((BYTE*)blockBuffOut, (BYTE*)prevBlock);
EncTools::copyBlock((BYTE*)prevBlock, (BYTE*)blockbuff);
}
if (cbc && !decrypt){
EncTools::copyBlock((BYTE*)prevBlock, (BYTE*)blockBuffOut);
}
// If is the last decryption block with the padding - remove the padding.
// If IO encodings are used padding cannot be stripped
if (decrypt && padding && eof && k + 1 >= iter2comp && coding->flags == WBAESGEN_EXTGEN_ID){
char paddingVal = blockBuffOut[N_BYTES - 1];
if (paddingVal <= 0 || paddingVal > N_BYTES){
paddingOk = false;
}
for(int px = N_BYTES - paddingVal; paddingOk && px < N_BYTES; ++px){
paddingOk &= blockBuffOut[px] == paddingVal;
}
if (paddingOk){
writeBytes -= paddingVal;
}
}
// add IO encodings before output.
if (coding && generator && coding->flags != WBAESGEN_EXTGEN_ID) {
generator->applyExternalEnc((BYTE*)blockBuffOut, coding, false);
}
if (out && writeBytes > 0) {
out->write((BYTE*)blockBuffOut, (size_t)writeBytes);
}
}
} while(!eof);
if (!paddingOk){
throw std::invalid_argument("Padding is not OK");
}
}