Commit 7145b21f authored by Robert Dubner's avatar Robert Dubner
Browse files

Sanitized DES by pretty much rewriting it from scratch

parent a715ee23
Pipeline #3658 passed with stage
in 38 minutes and 56 seconds
FREERADIUS_FILES = /usr/local/etc/raddb/
GCC = gcc
COPTS = -ggdb -O0 -Wall -fmax-errors=5
COPTS = -ggdb -O0 -Wall -fmax-errors=5 -Werror
ALLH = $(wildcard *.h)
LIBS = -L/usr/lib -lssl -lcrypto
......@@ -87,6 +87,7 @@ rad: all
./radiusclient -c $(CLIENT_CONF) -h 127.0.0.1 -p 1812 -m ttls -s testing123 testing password
radd: all
gdb --args ./radiusclient -c $(CLIENT_CONF) -h 127.0.0.1 -p 18129 -m peap -s testing123 abel1 abel1
# gdb --args ./radiusclient -c $(CLIENT_CONF) -h 127.0.0.1 -p 18129 -m peap -s testing123 abel1 abel1
# gdb --args ./radiusclient -c $(CLIENT_CONF) -h 127.0.0.1 -p 1812 -m peap -s testing123 testing password
......@@ -103,3 +104,13 @@ clean:
rm -f memcomms
rm -f radiusclient
$(MAKE) -C certs destroycerts
.PHONY: refdes
refdes:
g++ -ggdb -O0 -o refdes refdes.cpp
./refdes
.PHONY: refdesd
refdesd:
g++ -ggdb -O0 -o refdes refdes.cpp
gdb ./refdes
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2021 The OpenLDAP Foundation.
* Portions Copyright 2021 Robert Dubner, Symas Corp.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -14,73 +14,153 @@
*
*/
#include <ctype.h>
#define uchar unsigned char
static const uchar perm1[56] = {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
};
static const uchar perm2[48] = {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
};
static const uchar perm3[64] = {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
};
static const uchar perm4[48] = { 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
};
static const uchar perm5[32] = { 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
};
static const uchar perm6[64] = { 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
};
static const uchar sc[16] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
static const uchar sbox[8][4][16] =
// This code is based on FIPS Publication 46-3
#include <string.h>
#include "des.h"
#define DES_DATA_SIZE (64)
#define DES_DATA_HALF_SIZE (32)
#define DES_KEY_SIZE (56)
#define DES_HALF_KEY_SIZE (28)
#define DES_SBUFFER_SIZE (48)
#define DES_ROUNDS (16)
static void
str_to_key(uint8_t key56[DES_KEY_SIZE], uint8_t key64[DES_DATA_SIZE])
{
// Turn a 7-byte 56-bit key into a DES 64-bit key
// with the low-order bits off.
key64[0] = key56[0]>>1;
key64[1] = ((key56[0]&0x01)<<6) | (key56[1]>>2);
key64[2] = ((key56[1]&0x03)<<5) | (key56[2]>>3);
key64[3] = ((key56[2]&0x07)<<4) | (key56[3]>>4);
key64[4] = ((key56[3]&0x0F)<<3) | (key56[4]>>5);
key64[5] = ((key56[4]&0x1F)<<2) | (key56[5]>>6);
key64[6] = ((key56[5]&0x3F)<<1) | (key56[6]>>7);
key64[7] = key56[6]&0x7F;
for(int i=0; i<8; i++)
{
key64[i] = (key64[i]<<1);
}
}
static void
permute(uint8_t *out, const uint8_t *in, const uint8_t *perm, int n)
{
// Takes two equal-size bit arrays and does the permutation operation
// repeatedly utilized in the DES standard. perm[] is what I think of
// as a "come from" table, the i-th location in out[] "comes from" the
// perm[i] location in in[].
int i;
for (i=0; i<n; i++)
{
out[i] = in[perm[i]-1];
}
}
static void
lshift(uint8_t *dest, int count, int nbits)
{
// This is the "left-shift" operation, which is really a 28-byte left
// rotate. Count is either 1 or 2. The first loop fills the temporary
// temp[] array with values either 1 or 2 bytes to the right; we then
// copy the result into place:
uint8_t temp[64];
int i;
for (i=0; i<nbits; i++)
{
temp[i] = dest[(i+count)%nbits];
}
memcpy(dest, temp, nbits);
}
static void
concat(uint8_t *out, uint8_t *A, uint8_t *B, int lengthA, int lengthB)
{
// out[] is the result of concatenating lengthA bytes of A with
// lengthB bytes of B
memcpy(out, A, lengthA);
out += lengthA;
memcpy(out, B, lengthB);
}
static const uint8_t parity_drop[56] =
{
// Also known as permuted_choice_1
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
};
static const uint8_t permuted_choice_2[48] =
{
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
};
static const uint8_t initial_permutation[64] =
{
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
};
static const uint8_t e_bit_selection[48] =
{
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
};
static const uint8_t permutation_p[32] =
{
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
};
static const uint8_t inverse_initial[64] =
{
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
};
static const uint8_t sc[16] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
static const uint8_t sbox[8][4][16] =
{
{ {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},
......@@ -132,205 +212,198 @@ static const uchar sbox[8][4][16] =
};
static void
permute(char *out, char const *in, uchar const *p, int n)
xor(uint8_t *out, uint8_t *A, uint8_t *B, int n)
{
int i;
for (i=0; i<n; i++)
// This is the "mixing" step, a two's complement addition with
// no carry, known to the world as an exclusive or.
for (int i=0; i<n; i++)
{
out[i] = in[p[i]-1];
out[i] = A[i] ^ B[i];
}
}
static void
lshift(char *d, int count, int n)
des_ecb_cycle(uint8_t *out, uint8_t *in, uint8_t *key64)
{
char out[64];
int i;
for (i=0; i<n; i++)
{
out[i] = d[(i+count)%n];
}
for (i=0; i<n; i++)
uint8_t permuted_key[DES_KEY_SIZE];
uint8_t key_c[DES_HALF_KEY_SIZE];
uint8_t key_d[DES_HALF_KEY_SIZE];
uint8_t cd[DES_KEY_SIZE];
uint8_t ki[DES_ROUNDS][DES_SBUFFER_SIZE];
uint8_t permuted_data[DES_DATA_SIZE];
uint8_t left[DES_DATA_HALF_SIZE], right[DES_DATA_HALF_SIZE];
uint8_t right_left[DES_DATA_SIZE];
// This is a walk through a single cycle of DES. You can follow along
// in FIPS 46-3 to see what it is doing:
// We'll work on the conversion of the 64-bit key (where every eighth bit
// is unused by DES) to a permuted 56-bit key. In FIPS 46 this is known
// as "permuted choice 1" PC-1
permute(permuted_key, key64, parity_drop, DES_KEY_SIZE);
// Split the permuted key into C-zero and D-zero
memcpy(key_c, permuted_key, DES_HALF_KEY_SIZE);
memcpy(key_d, permuted_key+DES_HALF_KEY_SIZE, DES_HALF_KEY_SIZE);
// Run through the sixteen levels of "key schedule calculation". See
// FIPS 46 Figure 3.
for(int i=0; i<DES_ROUNDS; i++)
{
d[i] = out[i];
}
}
// Left-rotate each half:
lshift(key_c, sc[i], DES_HALF_KEY_SIZE);
lshift(key_d, sc[i], DES_HALF_KEY_SIZE);
static void
concat(char *out, char *in1, char *in2, int l1, int l2)
{
while (l1--)
{
*out++ = *in1++;
}
while (l2--)
{
*out++ = *in2++;
}
}
// Put them back together as a single 56-bitarray value:
concat(cd, key_c, key_d, DES_HALF_KEY_SIZE, DES_HALF_KEY_SIZE);
static void
xor(char *out, char *in1, char *in2, int n)
{
int i;
for (i=0; i<n; i++)
{
out[i] = in1[i] ^ in2[i];
// And pull out K-sub-i using permuted choice 2
permute(ki[i], cd, permuted_choice_2, DES_SBUFFER_SIZE);
}
}
// And with that, we have the sixteen 48-bit key values in ki[][]
static void
dohash(char *out, char *in, char *key)
{
int i, j, k;
char pk1[56];
char c[28];
char d[28];
char cd[56];
char ki[16][48];
char pd1[64];
char l[32], r[32];
char rl[64];
permute(pk1, key, perm1, 56);
for (i=0; i<28; i++)
{
c[i] = pk1[i];
}
for (i=0; i<28; i++)
{
d[i] = pk1[i+28];
}
// We will now start operating on the 64-bit data to be encrypted:
for (i=0; i<16; i++)
{
lshift(c, sc[i], 28);
lshift(d, sc[i], 28);
permute(permuted_data, in, initial_permutation, DES_DATA_SIZE);
concat(cd, c, d, 28, 28);
permute(ki[i], cd, perm2, 48);
}
// Break the permuted data into initial left and right halves:
memcpy(left, permuted_data, DES_DATA_HALF_SIZE);
memcpy(right, permuted_data + DES_DATA_HALF_SIZE, DES_DATA_HALF_SIZE);
permute(pd1, in, perm3, 64);
// We are now ready to run throught the sixteen levels of FIPS 46 "Figure 1
// Eniphering computation."
for (j=0; j<32; j++)
for(int i=0; i<DES_ROUNDS; i++)
{
l[j] = pd1[j];
r[j] = pd1[j+32];
}
// The guts of the DES routine is the f(R, K) function, which operates
// on the right half of the data and the key.
for (i=0; i<16; i++)
{
char er[48];
char erk[48];
char b[8][6];
char cb[32];
char pcb[32];
char r2[32];
// See FIPS 46 "Figure 2 Calculation of f(R, K)"
permute(er, r, perm4, 48);
uint8_t expanded_right[DES_SBUFFER_SIZE];
uint8_t right_plus_key[DES_SBUFFER_SIZE];
uint8_t s_box_addresses[8][6];
uint8_t s32[DES_DATA_HALF_SIZE];
uint8_t permuted_s[DES_DATA_HALF_SIZE];
uint8_t right2[DES_DATA_HALF_SIZE];
xor(erk, er, ki[i], 48);
// Expand the right side to 48 bits
permute(expanded_right, right, e_bit_selection, DES_SBUFFER_SIZE);
for (j=0; j<8; j++)
// Add those 48 bits to the 46 bits of K-sub-i
xor(right_plus_key, expanded_right, ki[i], DES_SBUFFER_SIZE);
// We need to pull eight six-bit addresses out of right_plus_key. Each
// More properly this would be implemented as a union, or even a
// single copy.
for(int j=0; j<8; j++)
{
for (k=0; k<6; k++)
for (int k=0; k<6; k++)
{
b[j][k] = erk[j*6 + k];
s_box_addresses[j][k] = right_plus_key[j*6 + k];
}
}
for (j=0; j<8; j++)
{
int m, n;
m = (b[j][0]<<1) | b[j][5];
// As per the documentation, each six-bit address is interpreted thus:
// bit[0] and bit[5] reference the row of an s-box, bits [1-4]
// reference the column.
n = (b[j][1]<<3) | (b[j][2]<<2) | (b[j][3]<<1) | b[j][4];
for(int j=0; j<8; j++)
{
int row;
int column;
row = (s_box_addresses[j][0]<<1) | s_box_addresses[j][5];
for (k=0; k<4; k++)
{
b[j][k] = (sbox[j][m][n] & (1<<(3-k)))?1:0;
}
}
column = ( s_box_addresses[j][1]<<3)
| (s_box_addresses[j][2]<<2)
| (s_box_addresses[j][3]<<1)
| s_box_addresses[j][4];
for (j=0; j<8; j++)
{
for (k=0; k<4; k++)
for(int k=0; k<4; k++)
{
cb[j*4+k] = b[j][k];
// Pick up the four bits from the sbox at that row and column,
// and build them into a combined 32-bit value:
s32[j*4+k] = (sbox[j][row][column] & (1<<(3-k)))?1:0;
}
}
permute(pcb, cb, perm5, 32);
xor(r2, l, pcb, 32);
// Apply permutation P, the final step in Figure 2.
permute(permuted_s, s32, permutation_p, DES_DATA_HALF_SIZE);
for (j=0; j<32; j++)
{
l[j] = r[j];
}
// permuted_s is, finally, f(Right, Key). That gets exclusive-ored
// with the left side of the data:
xor(right2, left, permuted_s, DES_DATA_HALF_SIZE);
for (j=0; j<32; j++)
{
r[j] = r2[j];
}
memcpy(left, right, DES_DATA_HALF_SIZE);
memcpy(right, right2, DES_DATA_HALF_SIZE);
}
concat(rl, r, l, 32, 32);
// We've finished with the sixeen rounds of data. We need combine the
// the 32-bit left and right pieces back into a single 64-bit value. And
// because the sixteenth round actually doesn't end with a swap, we use
// this opportunity to unswap the final swap of the loop:
concat(right_left, right, left, DES_DATA_HALF_SIZE, DES_DATA_HALF_SIZE);
permute(out, rl, perm6, 64);
// And we are up to the final operation of Figure 1:
permute(out, right_left, inverse_initial, DES_DATA_SIZE);
// And with that, we are done!
}
static void
str_to_key(unsigned char *str,unsigned char *key)
make_bit_array(uint8_t bit_array[64], const uint8_t byte_array[8])
{
int i;
uint8_t *out = bit_array;
for(int i=0; i<8; i++)
{
uint8_t byte = byte_array[i];
for(int j=0; j<8; j++)
{
*out++ = (byte & 0x80) ? 1 : 0;
byte <<= 1;
}
}
}
key[0] = str[0]>>1;
key[1] = ((str[0]&0x01)<<6) | (str[1]>>2);
key[2] = ((str[1]&0x03)<<5) | (str[2]>>3);
key[3] = ((str[2]&0x07)<<4) | (str[3]>>4);
key[4] = ((str[3]&0x0F)<<3) | (str[4]>>5);
key[5] = ((str[4]&0x1F)<<2) | (str[5]>>6);
key[6] = ((str[5]&0x3F)<<1) | (str[6]>>7);
key[7] = str[6]&0x7F;
for (i=0; i<8; i++)
static void
undo_bit_array(uint8_t byte_array[8], const uint8_t bit_array[64])
{
const uint8_t *in = bit_array;
for(int i=0; i<8; i++)
{
key[i] = (key[i]<<1);
int n = 7;
uint8_t byte = 0;
for(int j=0; j<8; j++)
{
byte |= *in++ << n-- ;
}
byte_array[i] = byte;
}
}
void
DesInECBMode( unsigned char *out,
unsigned char const *in,
unsigned char *key)
DesInECBMode( uint8_t out[8],