Data Encryption Standard
Data Encryption Standard
Encryption has become a part and parcel of our lives and we have accepted the fact that data
is going to encrypted and decrypted at various stages. However, there is not a single
encryption algorithm followed everywhere. There are a number of algorithms existing, and I
feel there is a need to understand how they work. So this text explains a number of popular
encryption algorithms and makes you look at them as mathematical formulas.
Summaries:
Key schedule:
C[0]D[0] = PC1(key)
for 1 <= i <= 16
C[i] = LS[i](C[i-1])
D[i] = LS[i](D[i-1])
K[i] = PC2(C[i]D[i])
Encipherment:
L[0]R[0] = IP(plain block)
for 1 <= i <= 16
L[i] = R[i-1]
R[i] = L[i-1] xor f(R[i-1], K[i])
cipher block = FP(R[16]L[16])
Decipherment:
R[16]L[16] = IP(cipher block)
for 1 <= i <= 16
R[i-1] = L[i]
L[i-1] = R[i] xor f(L[i], K[i])
plain block = FP(L[0]R[0])
To encrypt or decrypt more than 64 bits there are four official modes (defined in FIPS PUB
81). One is to go through the above-described process for each block in succession. This is
called Electronic Codebook (ECB) mode. A stronger method is to exclusive-or each plaintext
block with the preceding ciphertext block prior to encryption. (The first block is exclusive-
or'ed with a secret 64-bit initialization vector (IV).) This is called Cipher Block Chaining
(CBC) mode. The other two modes are Output Feedback (OFB) and Cipher Feedback (CFB).
When it comes to padding the data block, there are several options. One is to simply append
zeros. Two suggested by FIPS PUB 81 are, if the data is binary data, fill up the block with
bits that are the opposite of the last bit of data, or, if the data is ASCII data, fill up the block
with random bytes and put the ASCII character for the number of pad bytes in the last byte of
the block. Another technique is to pad the block with random bytes and in the last 3 bits store
the original number of data bytes.
The DES algorithm can also be used to calculate checksums up to 64 bits long (see FIPS
PUB 113). If the number of data bits to be check summed is not a multiple of 64, the last data
block should be padded with zeros. If the data is ASCII data, the first bit of each byte should
be set to 0. The data is then encrypted in CBC mode with IV = 0. The leftmost n bits (where
16 <= n <= 64, and n is a multiple of 8) of the final ciphertext block are an n-bit checksum.
Wow, that was one heck of a paper on DES. That would be all you need to implement DES.
Well, if you still have not understood how the DES algorithm is implemented, then I suggest
you go through the following C program:
#include <stdio.h>
static int keyout[17][48];
void des_init(),lshift(),cypher(),des_encrypt(),des_descrypt();
void des_init(unsigned char *key){
unsigned char c[28],d[28];
static int pc1[56] = {57,49,41,33,25,17,9,
01,58,50,42,34,26,18,
10,02,59,51,43,35,27,
19,11,03,60,52,44,36,
63,55,47,39,31,23,15,
07,62,54,46,38,30,22,
14,06,61,53,45,37,29,
21,13,05,28,20,12,04};
static int pc2[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 int nls[17] = {
0,1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1};
static int cd[56],keyb[64];
static int cnt,n=0;
register int i,j;
for(i=0;i<8;i++) /*Read in key*/
for(j=0;j<8;j++) keyb[n++]=(key[i]>>j&0x01);
for(i=0;i<56;i++) /*Permuted choice 1*/
cd[i]=keyb[pc1[1]-1];
for(i=0;i<28;i++){
c[i]=cd[i];
d[i]=cd[i+28];
}
for(cnt=1;cnt<=16;cnt++){
for(i=0;i<nls[cnt];i++){
lshift(c); lshift(d);
}
for(i=0;i<28;i++){
cd[i]=c[i];
cd[i+28]=d[i];
}
for(i=0;i<48;i++) /*Permuted Choice 2*/
keyout[cnt][i]=cd[pc2[i]-1];
}
}
static void lshift(unsigned char shft[]){
register int temp,i;
temp=shft[0];
for(i=0;i<27;i++) shft[i]=shft[i+1];
shft[27]=temp;
}
static void cypher(int *r, int cnt, int *fout){
static int expand[48],b[8][6],sout[8],pin[48];
register int i,j;
static int n,row,col,scnt;
static int 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 int e[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 char s[8][64] = {
14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7, /*s1*/
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,
15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10, /*s2*/
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,
10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8, /*s3*/
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,
7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15,/*s4*/
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,
2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9,/*s5*/
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,
12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11, /*s6*/
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,
4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1,/*s7*/
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,
13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7, /*s8*/
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
};
for(i=0;i<48;i++) expand[i]=r[e[i]-1]; /*Expansion Function*/
for(i=n=0;i<8;i++) {
for(j=0;j<6;j++,n++) b[i][j]=expand[n]^keyout[cnt][n];
}
/*Selection functions*/
for(scnt=n=0;scnt<8;scnt++){
row=(b[scnt][0]<<1)+b[scnt][5];
col=(b[scnt][1]<<3)+(b[scnt][2]<<2)+(b[scnt][3]<<1)+b[scnt][4];
sout[scnt]=s[scnt][(row<<4)+col];
for(i=3;i>=0;i--){
pin[n]=sout[scnt]>>i;
sout[scnt]=sout[scnt]-(pin[n++]<<i);
}
}
for(i=0;i<32;i++) fout[i]=pin[p[i]-1]; /*Permutation Function*/
}
static int p[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,
5 = {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 int invp[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};
void des_encrypt(unsigned char *input){
static unsigned char out[64];
static int inputb[64],lr[64],l[32],r[32];
static int fn[32];
static int cnt,n;
register int i,j;
for(i=n=0;i<8;i++)
for(j=0;j<8;j++) inputb[n++]=(input[i]>>j&0x01);
for(i=0;i<64;i++){ /*Initial Permutation*/
lr[i]=inputb[p[i]-1];
if(i<32) l[i]=lr[i];
else r[i-32]=lr[i];
}
for(cnt=1;cnt<=16;cnt++){ /*Main encryption loop*/
cypher(r,cnt,fn);
for(i=0;i<32;i++){
j=r[i];
r[i]=l[i]^fn[i];
l[i]=j;
}
}
for(i=0;i<32;i++){
lr[i]=r[i];
lr[i+32]=l[i];
}
for(i=0;i<64;i++) out[i]=lr[invp[i]-1]; /*Inverse IP*/
for(i=1;i<=8;i++)
for(j=1;j<=8;j++) input[i-1]=(input[i-1]<<1)|out[i*8-j];
}
void des_decrypt(unsigned char *input){
static unsigned char out[64];
static int inputb[64],lr[64],l[32],r[32];
static int fn[32];
static int cnt,rtemp,n;
register int i,j;
for(i=n=0;i<8;i++)
for(j=0;j<8;j++) inputb[n++]=(input[i]>>j&0x01);
for(i=0;i<64;i++){ /*Initial Permutation*/
lr[i]=inputb[p[i]-1];
if(i<32) l[i]=lr[i];
else r[i-32]=lr[i];
}
for(cnt=16;cnt>0;cnt--){ /*Main decryption loop*/
cypher(r,cnt,fn);
for(i=0;i<32;i++){
rtemp=r[i];
if(l[i]==1 && fn[i]==1) r[i]=0;
else r[i]=(l[i] || fn[i]);
l[i]=rtemp;
}
}
for(i=0;i<32;i++){
lr[i]=r[i];
lr[i+32]=l[i];
}
for(i=0;i<64;i++) out[i]=lr[invp[i]-1]; /*Inverse IP*/
for(i=1;i<=8;i++)
for(j=1;j<=8;j++) input[i-1]=(input[i-1]<<1) | out[i*8-j];
}
int main(int argc, char *argv[]){
unsigned char *key;
unsigned char data[8];
int n;
FILE *in;
FILE *out;
if (argc!=4) {
printf("\r\nUsage: des [e][d] <source file> <destination file>\r\n");
return 1;
}
key=(unsigned char*)getpass("Enter Key:");
des_init(key);
if((in=fopen(argv[2],"rb"))==NULL){
fprintf(stderr,"\r\nCould not open input file: %s",argv[2]);
return 2;
}
if((out=fopen(argv[3],"wb"))==NULL){
fprintf(stderr,"\r\nCould not open output file: %s",argv[3]);
return 3;
}
if(argv[1][0]=='e'){
while ((n=fread(data,1,8,in)) >0){
des_encrypt(data);
printf("data enctyted");
if(fwrite(data,1,8,out) < 8){
fprintf(stderr,"\r\nError writing to output file\r\n");
return(3);
}
}
}
if(argv[1][0]=='d'){
while ((n=fread(data,1,8,in)) >0){
des_decrypt(data);
if(fwrite(data,1,8,out) < 8){
fprintf(stderr,"\r\nError writing to output file\r\n");
return(3);
}
}
}
fclose(in); fclose(out);
return 0;
}ntf(stderr,"\r\nError writing to output file\r\n");
return(3);
}
}
}
fclose(in); fclose(out);
return 0;
}
[Sources: Ankit Fadias Algorithms Explained]