Skip to content

Commit

Permalink
Added new module for DES encryption/decryption
Browse files Browse the repository at this point in the history
  • Loading branch information
aquaratixc committed Mar 16, 2023
1 parent 50a3e66 commit 2b66fbd
Showing 1 changed file with 333 additions and 0 deletions.
333 changes: 333 additions & 0 deletions source/styx2000/protosrv/des.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,333 @@
// Written in the D programming language.

/**
This class provides an implementation of the DES cryptoalgorithm.
Implementation is based on the following code (by Daniel Huertas Gonzalez): https://github.com/dhuertas/DES/blob/master/des.c
Copyright: LightHouse Software, 2023
License: $(HTTP https://github.com/aquaratixc/ESL-License, Experimental Software License 1.0).
Authors: Oleg Bakharev,
Daniel Huertas Gonzalez
See also:
https://en.wikipedia.org/wiki/Data_Encryption_Standard, FIPS PUB 46-3
*/
module styx2000.protosrv.des;

/// DES functional mode: encryption or decryption
enum CRYPTOPERATION
{
/// encrypt with DES
ENCRYPT,
/// decrypt with DES
DECRYPT
}


/// DES algorith implementation
class DES
{
private {
enum LB32_MASK = 0x00000001;
enum LB64_MASK = 0x0000000000000001;
enum L64_MASK = 0x00000000ffffffff;
enum H64_MASK = 0xffffffff00000000;
}

private {
/* Initial Permutation Table */
static char[] IP = [
58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46,
38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, 57, 49, 41, 33, 25, 17,
9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 61, 53, 45, 37, 29, 21, 13, 5, 63,
55, 47, 39, 31, 23, 15, 7
];

/* Inverse Initial Permutation Table */
static char[] PI = [
40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, 38, 6, 46,
14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29, 36, 4, 44, 12, 52, 20,
60, 28, 35, 3, 43, 11, 51, 19, 59, 27, 34, 2, 42, 10, 50, 18, 58, 26, 33,
1, 41, 9, 49, 17, 57, 25
];

/* Expansion table */
static char[] E = [
32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13, 12, 13, 14, 15,
16, 17, 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25, 24, 25, 26, 27,
28, 29, 28, 29, 30, 31, 32, 1
];

/* Post S-Box permutation */
static char[] P = [
16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 2, 8, 24,
14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25
];

/* The S-Box tables */
static char[64][8] S = [
[
/* S1 */
14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, 0, 15, 7, 4,
14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, 4, 1, 14, 8, 13, 6, 2, 11,
15, 12, 9, 7, 3, 10, 5, 0, 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0,
6, 13
],
[
/* S2 */
15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, 3, 13, 4, 7, 15,
2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, 0, 14, 7, 11, 10, 4, 13, 1, 5, 8,
12, 6, 9, 3, 2, 15, 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9
],
[
/* S3 */
10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, 13, 7, 0, 9, 3,
4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, 13, 6, 4, 9, 8, 15, 3, 0, 11,
1, 2, 12, 5, 10, 14, 7, 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2,
12
],
[
/* S4 */
7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, 13, 8, 11, 5, 6,
15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, 10, 6, 9, 0, 12, 11, 7, 13, 15, 1,
3, 14, 5, 2, 8, 4, 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14
],
[
/* S5 */
2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, 14, 11, 2, 12,
4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, 4, 2, 1, 11, 10, 13, 7, 8, 15,
9, 12, 5, 6, 3, 0, 14, 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5,
3
],
[
/* S6 */
12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, 10, 15, 4, 2, 7,
12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, 9, 14, 15, 5, 2, 8, 12, 3, 7, 0,
4, 10, 1, 13, 11, 6, 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13
],
[
/* S7 */
4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, 13, 0, 11, 7, 4,
9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, 1, 4, 11, 13, 12, 3, 7, 14, 10,
15, 6, 8, 0, 5, 9, 2, 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12
],
[
/* S8 */
13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, 1, 15, 13, 8, 10,
3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, 7, 11, 4, 1, 9, 12, 14, 2, 0, 6,
10, 13, 15, 3, 5, 8, 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11
]
];

/* Permuted Choice 1 Table */
static char[] PC1 = [
57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43,
35, 27, 19, 11, 3, 60, 52, 44, 36, 63, 55, 47, 39, 31, 23, 15, 7, 62, 54,
46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4
];

/* Permuted Choice 2 Table */
static char[] PC2 = [
14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, 23, 19, 12, 4, 26, 8, 16, 7,
27, 20, 13, 2, 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, 44, 49, 39,
56, 34, 53, 46, 42, 50, 36, 29, 32
];

/* Iteration Shift Array */
static char[] iteration_shift = [
/* 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 */
1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
];
}


/**
Method for encryption or decryption of one elementary block (block size - 64 bit, key size - 64 bit).
Params:
input = Elementary block for encrypt/decrypt with DES.
key = Key for encrypt/decrypt
mode = Type of operation mode of DES class - encryption or decryption
*/
static ulong des(ulong input, ulong key, CRYPTOPERATION mode)
{
/* 8 bits */
char row, column;

/* 28 bits */
uint C = 0;
uint D = 0;

/* 32 bits */
uint L = 0;
uint R = 0;
uint s_output = 0;
uint f_function_res = 0;
uint temp = 0;

/* 48 bits */
ulong[16] sub_key = 0;
ulong s_input = 0;

/* 56 bits */
ulong permuted_choice_1 = 0;
ulong permuted_choice_2 = 0;

/* 64 bits */
ulong init_perm_res = 0;
ulong inv_init_perm_res = 0;
ulong pre_output = 0;

/* initial permutation */
for (int i = 0; i < 64; i++)
{
init_perm_res <<= 1;
init_perm_res |= (input >> (64 - IP[i])) & LB64_MASK;
}

L = cast(uint)(init_perm_res >> 32) & L64_MASK;
R = cast(uint) init_perm_res & L64_MASK;

/* initial key schedule calculation */
for (int i = 0; i < 56; i++)
{
permuted_choice_1 <<= 1;
permuted_choice_1 |= (key >> (64 - PC1[i])) & LB64_MASK;
}

C = cast(uint)((permuted_choice_1 >> 28) & 0x000000000fffffff);
D = cast(uint)(permuted_choice_1 & 0x000000000fffffff);

/* Calculation of the 16 keys */
for (int i = 0; i < 16; i++)
{
/* key schedule */
// shifting Ci and Di
for (int j = 0; j < iteration_shift[i]; j++)
{
C = 0x0fffffff & (C << 1) | 0x00000001 & (C >> 27);
D = 0x0fffffff & (D << 1) | 0x00000001 & (D >> 27);
}

permuted_choice_2 = 0;
permuted_choice_2 = ((cast(ulong) C) << 28) | cast(ulong) D;

sub_key[i] = 0;

for (int j = 0; j < 48; j++)
{
sub_key[i] <<= 1;
sub_key[i] |= (permuted_choice_2 >> (56 - PC2[j])) & LB64_MASK;
}

}

for (int i = 0; i < 16; i++)
{
/* f(R,k) function */
s_input = 0;

for (int j = 0; j < 48; j++)
{
s_input <<= 1;
s_input |= cast(ulong)((R >> (32 - E[j])) & LB32_MASK);
}

/*
* Encryption/Decryption
* XORing expanded Ri with Ki
*/
final switch (mode) with (CRYPTOPERATION)
{
case ENCRYPT:
s_input = s_input ^ sub_key[i];
break;
case DECRYPT:
s_input = s_input ^ sub_key[15 - i];
break;
}

/* S-Box Tables */
for (int j = 0; j < 8; j++)
{
// 00 00 RCCC CR00 00 00 00 00 00 s_input
// 00 00 1000 0100 00 00 00 00 00 row mask
// 00 00 0111 1000 00 00 00 00 00 column mask

row = cast(char) ((s_input & (0x0000840000000000 >> 6 * j)) >> 42 - 6 * j);
row = (row >> 4) | row & 0x01;

column = cast(char) ((s_input & (0x0000780000000000 >> 6 * j)) >> 43 - 6 * j);

s_output <<= 4;
s_output |= cast(uint) (S[j][16 * row + column] & 0x0f);
}

f_function_res = 0;

for (int j = 0; j < 32; j++)
{
f_function_res <<= 1;
f_function_res |= (s_output >> (32 - P[j])) & LB32_MASK;
}

temp = R;
R = L ^ f_function_res;
L = temp;
}

pre_output = ((cast(ulong) R) << 32) | cast(ulong) L;

/* inverse initial permutation */
for (int i = 0; i < 64; i++)
{
inv_init_perm_res <<= 1;
inv_init_perm_res |= (pre_output >> (64 - PI[i])) & LB64_MASK;
}

return inv_init_perm_res;
}
}

unittest {
enum ulong[16] TESTING_VECTOR = [
0x8da744e0c94e5e17,
0x0cdb25e3ba3c6d79,
0x4784c4ba5006081f,
0x1cf1fc126f2ef842,
0xe4be250042098d13,
0x7bfc5dc6adb5797c,
0x1ab3b4d82082fb28,
0xc1576a14de707097,
0x739b68cd2e26782a,
0x2a59f0c464506edb,
0xa5c39d4251f0a81e,
0x7239ac9a6107ddb1,
0x070cac8590241233,
0x78f87b6e3dfecf61,
0x95ec2578c2c433f0,
0x1b1a2ddb4c642438,
];

ulong input = 0x9474B8E8C73BCA7D;
ulong key = 0x0000000000000000;
ulong result = input;

ulong[16] vector;

for (int i = 0; i < 16; i++)
{
if (i % 2 == 0)
{
result = DES.des(result, result, CRYPTOPERATION.ENCRYPT);
}
else
{
result = DES.des(result, result, CRYPTOPERATION.DECRYPT);
}

vector[i] = result;
}

assert(vector == TESTING_VECTOR);
assert(result == 0x1b1a2ddb4c642438);
}

0 comments on commit 2b66fbd

Please sign in to comment.