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
|
#include "des.h"
#include "des_key.h"
#include "des_data.h"
#include "des_lookup.h"
#include <memory>
//#pragma GCC push_options
#ifndef _MSC_VER
#pragma GCC optimize ("unroll-loops")
#endif
DES::DES(ui64 key)
{
keygen(key);
}
DES::DES(ui64* sub_key)
{
set_sub_key(sub_key);
}
void DES::set_sub_key(ui64 *sub_key)
{
std::memcpy(this->sub_key, sub_key, 128);
}
ui64 DES::encrypt(ui64 block)
{
return des(block, false);
}
ui64 DES::decrypt(ui64 block)
{
return des(block, true);
}
ui64 DES::encrypt(ui64 block, ui64 key)
{
DES des(key);
return des.des(block, false);
}
ui64 DES::decrypt(ui64 block, ui64 key)
{
DES des(key);
return des.des(block, true);
}
void DES::keygen(ui64 key)
{
// initial key schedule calculation
ui64 permuted_choice_1 = 0; // 56 bits
for (ui8 i = 0; i < 56; i++)
{
permuted_choice_1 <<= 1;
permuted_choice_1 |= (key >> (64-PC1[i])) & LB64_MASK;
}
// 28 bits
ui32 C = (ui32) ((permuted_choice_1 >> 28) & 0x000000000fffffff);
ui32 D = (ui32) (permuted_choice_1 & 0x000000000fffffff);
// Calculation of the 16 keys
for (ui8 i = 0; i < 16; i++)
{
// key schedule, shifting Ci and Di
for (ui8 j = 0; j < ITERATION_SHIFT[i]; j++)
{
C = (0x0fffffff & (C << 1)) | (0x00000001 & (C >> 27));
D = (0x0fffffff & (D << 1)) | (0x00000001 & (D >> 27));
}
ui64 permuted_choice_2 = (((ui64) C) << 28) | (ui64) D;
sub_key[i] = 0; // 48 bits (2*24)
for (ui8 j = 0; j < 48; j++)
{
sub_key[i] <<= 1;
sub_key[i] |= (permuted_choice_2 >> (56-PC2[j])) & LB64_MASK;
}
}
}
ui64 DES::des(ui64 block, bool mode)
{
// applying initial permutation
block = ip(block);
// dividing T' into two 32-bit parts
ui32 L = (ui32) (block >> 32) & L64_MASK;
ui32 R = (ui32) (block & L64_MASK);
// 16 rounds
for (ui8 i = 0; i < 16; i++)
{
ui32 F = mode ? f(R, sub_key[15-i]) : f(R, sub_key[i]);
feistel(L, R, F);
}
// swapping the two parts
block = (((ui64) R) << 32) | (ui64) L;
// applying final permutation
return fp(block);
}
ui64 DES::ip(ui64 block)
{
// initial permutation
ui64 result = 0;
for (ui8 i = 0; i < 64; i++)
{
result <<= 1;
result |= (block >> (64-IP[i])) & LB64_MASK;
}
return result;
}
ui64 DES::fp(ui64 block)
{
// inverse initial permutation
ui64 result = 0;
for (ui8 i = 0; i < 64; i++)
{
result <<= 1;
result |= (block >> (64-FP[i])) & LB64_MASK;
}
return result;
}
void DES::feistel(ui32 &L, ui32 &R, ui32 F)
{
ui32 temp = R;
R = L ^ F;
L = temp;
}
ui32 DES::f(ui32 R, ui64 k) // f(R,k) function
{
// applying expansion permutation and returning 48-bit data
ui64 s_input = 0;
for (ui8 i = 0; i < 48; i++)
{
s_input <<= 1;
s_input |= (ui64) ((R >> (32-EXPANSION[i])) & LB32_MASK);
}
// XORing expanded Ri with Ki, the round key
s_input = s_input ^ k;
// applying S-Boxes function and returning 32-bit data
ui32 s_output = 0;
for (ui8 i = 0; i < 8; i++)
{
// Outer bits
char row = (char) ((s_input & (0x0000840000000000 >> 6*i)) >> (42-6*i));
row = (row >> 4) | (row & 0x01);
// Middle 4 bits of input
char column = (char) ((s_input & (0x0000780000000000 >> 6*i)) >> (43-6*i));
s_output <<= 4;
s_output |= (ui32) (SBOX[i][16*row + column] & 0x0f);
}
// applying the round permutation
ui32 f_result = 0;
for (ui8 i = 0; i < 32; i++)
{
f_result <<= 1;
f_result |= (s_output >> (32 - PBOX[i])) & LB32_MASK;
}
return f_result;
}
//#pragma GCC pop_options
|