//This program is free software: you can redistribute it and/or modify it under the terms #of the GNU General Public License as published by the Free Software Foundation, either #version 3 of the License, or (at your option) any later version.
//This program is distributed in the hope that it will be useful, but WITHOUT ANY #WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A #PARTICULAR PURPOSE. See the GNU General Public License for more details.
//You should have received a copy of the GNU General Public License along with this #program. If not, see
/* des1.c */
/* DES Outerbridge single cipher : 64 bit key, 64 bit block */
/* Unless otherwise noted Copyright 1995 Willis E. Howard, III */
/* Willis E. Howard, III email: WEHoward@aol.com mail: POB 1473 Elkhart, IN 46515 */
/* under MSDOS, NMAKE /F DES1.MAK all clean */
#include
#include
#include "crypt.h"
#include "hex.h"
#include "des.h" /* one .h for all DES versions */
#include
#include
#include
/*
This routine uses the common interface to CRYPT.C.
Generally, the name of this module becomes the name
of the executable file.
*/
static int key_defined_des = 0; /* Set to 1 after a valid key has been defined */
static int encrypt_or_decrypt_des = ENCRYPTION_SELECT;
static short mode = EN0;
static char key_string_des[257];
static char actual_key_des[8];
void process_key_des (char *, char *);
/*
cipher_doc:
This array of strings must have two sections:
CIPHER that describes the cipher used and
KEY that describes how the key is defined and entered.
*/
static char *cipher_doc[] =
{
"CIPHER",
" The program uses the Data Encryption Standard (DES) cipher.",
" A 64 bit key is used to encrypt a 64 bit block.",
" This version uses the Outerbridge implementation.",
"",
" Because blocks of 8 bytes are processed, files that are not",
" a multiple of 8 bytes long may increase slightly in size.",
" Decrypted files may have additional spaces at the end.",
" Use the -d option for decryption.",
"",
"KEY",
" The key is an ASCII string. If you use more than one",
" word in the phrase and give the key with the -k option",
" on the command line, place the phrase within quotes.",
" At most 256 characters will be used in the phrase.",
" If the string evaluates to exactly 8 hex bytes such as",
" \"F0 AB 45 7E 00 6C E4 AA\" with spaces ignored, then that",
" exact 64 bit key is used. Otherwise, the ASCII characters",
" are hashed to form a 64 bit key. Weak and semi-weak keys",
" will produce a warning message.",
"",
" If a key file exists, only the first line is read, and",
" it is used as the key phrase.",
"",
" If there is no key phrase, you will be prompted for one.",
NULL
};
char **
crypt_help_des ()
{
return cipher_doc; /* return a pointer to the help strings */
}
/*
crypt_key:
Get the key from the passed string (that may be a file name in some
implementations) or from a key file name. Return 0 on success but
exit on error.
*/
int
crypt_key_des (int key_type, char *key_text)
{
int i;
char *s;
FILE *fp;
if (key_type == KEY_FILE) /* a file name has been given */
{
if ((fp = fopen (key_text, "r")) == NULL)
{
key_defined_des = 0;
return 0;
}
s = key_string_des;
i = 0;
for (;;)
{
*s = fgetc (fp);
if ((*s == '\n') || (*s == EOF))
{
*s = '\0';
if (i == 0)
{
key_defined_des = 0;
break;
}
else
{
process_key_des (key_string_des, actual_key_des);
key_defined_des = 1;
break;
}
}
else if (i == 255)
{
*++s = '\0';
process_key_des (key_string_des, actual_key_des);
key_defined_des = 1;
break;
}
s++;
i++;
}
fclose (fp);
return 0;
}
else if (key_type == KEY_IMMEDIATE) /* a key string has been given */
{
if (!strcmp (key_text, "?")) /* prompt for key */
{
printf ("Key: "); /* input key from stdin */
s = key_string_des;
i = 0;
for (;;)
{
*s = fgetc (stdin);
if ((*s == '\n') || (*s == EOF))
{
*s = '\0';
process_key_des (key_string_des, actual_key_des);
key_defined_des = 1;
break;
}
else if (i == 255)
{
*++s = '\0';
process_key_des (key_string_des, actual_key_des);
key_defined_des = 1;
break;
}
s++;
i++;
}
}
else
/* copy string up to 256 characters */
{
strncpy (key_string_des, key_text, 256);
key_string_des[256] = '\0';
process_key_des (key_string_des, actual_key_des);
key_defined_des = 1;
}
return 0;
}
fprintf (stderr, "Error getting key\n");
exit (1);
}
/*
crypt_key_erase:
If a local copy of the key has been made, erase it from memory.
This increases security that the key can not be obtained from
an examination of memory.
*/
void
crypt_key_erase_des ()
{
int i;
for (i = 0; i < 257; i++)
key_string_des[i] = '\0';
process_key_des (key_string_des, actual_key_des);
key_defined_des = 0;
return;
}
/*
crypt_select:
If encryption and decryption require different ciphers,
this routine defines the direction. Valid choices are
ENCRYPTION_SELECT and DECRYPTION_SELECT.
*/
int
crypt_select_des (int selection)
{
if (selection == ENCRYPTION_SELECT)
{
if (encrypt_or_decrypt_des == DECRYPTION_SELECT)
{
encrypt_or_decrypt_des = ENCRYPTION_SELECT;
mode = EN0;
if (key_defined_des) /* if we have a key, recalculate */
process_key_des (key_string_des, actual_key_des);
}
}
if (selection == DECRYPTION_SELECT)
{
if (encrypt_or_decrypt_des == ENCRYPTION_SELECT)
{
encrypt_or_decrypt_des = DECRYPTION_SELECT;
mode = DE1;
if (key_defined_des) /* if we have a key, recalculate */
process_key_des (key_string_des, actual_key_des);
}
}
return encrypt_or_decrypt_des;
}
/*
crypt_file:
encrypt or decrypt the source to the destination file.
Do not exit from this routine. Return 0 on success
and return 1 on error. Use an fprintf(stderr, ... ) to
report the nature of the error and close any open files.
This allows the main routine to do some cleanup before
exiting.
*/
int
crypt_file_des (char *source, char *dest)
{
int i;
int count = 8; /* block size */
char buffer[8];
FILE *infile;
FILE *outfile;
while (!key_defined_des)
crypt_key_des (KEY_IMMEDIATE, "?");
if ((infile = fopen (source, "rb")) == NULL)
{
fprintf (stderr, "Can not open %s for reading.\n", source);
return 1;
}
if ((outfile = fopen (dest, "wb")) == NULL)
{
fprintf (stderr, "Can not open %s for writing.\n", dest);
fclose (infile);
return 1;
}
for (i = 0; i < count; i++)
buffer[i] = (char) 0x20; /* text files padded with spaces */
while (fread (buffer, sizeof (char), count, infile))
{
des ((unsigned char *) buffer, (unsigned char *) buffer);
if (count != fwrite (buffer, sizeof (char), count, outfile))
{
fprintf (stderr, "Could not write to %s\n", source);
fclose (infile);
fclose (outfile);
return 1;
}
else
{
for (i = 0; i < count; i++)
buffer[i] = (char) 0x20;
}
}
fclose (infile);
fclose (outfile);
return 0;
}
/* DES Weak keys */
static unsigned char DES_weak[32] =
{
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0
};
/* DES Semi-weak keys */
static unsigned char DES_semi_weak[96] =
{
0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe,
0x1f, 0xe0, 0x1f, 0xe0, 0x0e, 0xf1, 0x0e, 0xf1,
0x01, 0xe0, 0x01, 0xe0, 0x01, 0xf1, 0x01, 0xf1,
0x1f, 0xfe, 0x1f, 0xfe, 0x0e, 0xfe, 0x0e, 0xfe,
0x01, 0x1f, 0x01, 0x1f, 0x01, 0x0e, 0x01, 0x0e,
0xe0, 0xfe, 0xe0, 0xfe, 0xf1, 0xfe, 0xf1, 0xfe,
0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01,
0xe0, 0x1f, 0xe0, 0x1f, 0xf1, 0x0e, 0xf1, 0x0e,
0xe0, 0x01, 0xe0, 0x01, 0xf1, 0x01, 0xf1, 0x01,
0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x0e, 0xfe, 0x0e,
0x1f, 0x01, 0x1f, 0x01, 0x0e, 0x01, 0x0e, 0x01,
0xfe, 0xe0, 0xfe, 0xe0, 0xfe, 0xf1, 0xfe, 0xf1
};
/* DES Possibly weak keys are not identified */
/* Convert a string to a key and check for weak keys */
void
process_key_des (char *s, char *key)
{
char string[257];
int i;
int j;
int shift = 1;
int value = 0;
int hex_count = 0;
int nonhex_count = 0;
int white_count = 0;
/* check if a hex number or ascii string was entered */
for (i = 0; (i < 256) && *s; i++)
{
string[i] = *s++;
if (ishex (string[i]))
hex_count++;
else if (string[i] == ' ')
white_count++;
else
nonhex_count++;
}
string[i] = '\0';
/* either convert hex number or process ascii string */
if (hex_count == 16 && nonhex_count == 0)
{
hex_count = 0;
for (i = 0; string[i] != '\0'; i++)
{
if ((value = hextoint (string[i])) != -1)
{
if (shift)
{
key[hex_count >> 1] = (unsigned char) value << 4;
hex_count++;
shift = 0;
}
else
{
key[hex_count >> 1] += (unsigned char) value;
hex_count++;
shift = 1;
}
}
string[i] = '\0';
}
}
else
makekey (string,(unsigned char*) key);
/* warn of weak keys */
for (i = 0; i < 24; i += 8)
{
value = 0;
for (j = 0; j < 8; j++)
if (key[j] == DES_weak[(i + j)])
value++;
if (value == 8)
fprintf (stderr, "A weak key has been detected.\n");
}
/* warn of semi-weak keys */
for (i = 0; i < 96; i += 8)
{
value = 0;
for (j = 0; j < 8; j++)
if (key[j] == DES_semi_weak[(i + j)])
value++;
if (value == 8)
fprintf (stderr, "A semi-weak key has been detected.\n");
}
/* select the key for use */
deskey ((unsigned char*)key, mode);
}
/* D3DES (V5.09) -
*
* A portable, public domain, version of the Data Encryption Standard.
*
* Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge.
* Thanks to: Dan Hoey for his excellent Initial and Inverse permutation
* code; Jim Gillogly & Phil Karn for the DES key schedule code; Dennis
* Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau,
* for humouring me on.
*
* Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge.
*
* (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.
*/
static void scrunch (unsigned char *, unsigned long *);
static void unscrun (unsigned long *, unsigned char *);
static void desfunc (unsigned long *, unsigned long *);
static void cookey (unsigned long *);
static unsigned long KnL[32] =
{0L};
static unsigned long KnR[32] =
{0L};
static unsigned long Kn3[32] =
{0L};
static unsigned char Df_Key[24] =
{
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67};
static unsigned short bytebit[8] =
{
0200, 0100, 040, 020, 010, 04, 02, 01};
static unsigned long bigbyte[24] =
{
0x800000L, 0x400000L, 0x200000L, 0x100000L,
0x80000L, 0x40000L, 0x20000L, 0x10000L,
0x8000L, 0x4000L, 0x2000L, 0x1000L,
0x800L, 0x400L, 0x200L, 0x100L,
0x80L, 0x40L, 0x20L, 0x10L,
0x8L, 0x4L, 0x2L, 0x1L};
/* Use the key schedule specified in the Standard (ANSI X3.92-1981). */
static unsigned char pc1[56] =
{
56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17,
9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35,
62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21,
13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3};
static unsigned char totrot[16] =
{
1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28};
static unsigned char pc2[48] =
{
13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9,
22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1,
40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31};
/* Thanks to James Gillogly & Phil Karn! */
void deskey (unsigned char *key,short edf)
{
register int i,
j,
l,
m,
n;
unsigned char pc1m[56],
pcr[56];
unsigned long kn[32];
for (j = 0; j < 56; j++)
{
l = pc1[j];
m = l & 07;
pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0;
}
for (i = 0; i < 16; i++)
{
if (edf == DE1)
m = (15 - i) << 1;
else
m = i << 1;
n = m + 1;
kn[m] = kn[n] = 0L;
for (j = 0; j < 28; j++)
{
l = j + totrot[i];
if (l < 28)
pcr[j] = pc1m[l];
else
pcr[j] = pc1m[l - 28];
}
for (j = 28; j < 56; j++)
{
l = j + totrot[i];
if (l < 56)
pcr[j] = pc1m[l];
else
pcr[j] = pc1m[l - 28];
}
for (j = 0; j < 24; j++)
{
if (pcr[pc2[j]])
kn[m] |= bigbyte[j];
if (pcr[pc2[j + 24]])
kn[n] |= bigbyte[j];
}
}
cookey (kn);
return;
}
static void
cookey ( register unsigned long *raw1)
{
register unsigned long *cook,
*raw0;
unsigned long dough[32];
register int i;
cook = dough;
for (i = 0; i < 16; i++, raw1++)
{
raw0 = raw1++;
*cook = (*raw0 & 0x00fc0000L) << 6;
*cook |= (*raw0 & 0x00000fc0L) << 10;
*cook |= (*raw1 & 0x00fc0000L) >> 10;
*cook++ |= (*raw1 & 0x00000fc0L) >> 6;
*cook = (*raw0 & 0x0003f000L) << 12;
*cook |= (*raw0 & 0x0000003fL) << 16;
*cook |= (*raw1 & 0x0003f000L) >> 4;
*cook++ |= (*raw1 & 0x0000003fL);
}
usekey (dough);
return;
}
void
cpkey (register unsigned long *into)
{
register unsigned long *from,
*endp;
from = KnL, endp = &KnL[32];
while (from < endp)
*into++ = *from++;
return;
}
void
usekey (register unsigned long *from)
{
register unsigned long *to,
*endp;
to = KnL, endp = &KnL[32];
while (to < endp)
*to++ = *from++;
return;
}
void
des (unsigned char *inblock,unsigned char * outblock)
{
unsigned long work[2];
scrunch (inblock, work);
desfunc (work, KnL);
unscrun (work, outblock);
return;
}
static void
scrunch (register unsigned char *outof,register unsigned long *into)
{
*into = (*outof++ & 0xffL) << 24;
*into |= (*outof++ & 0xffL) << 16;
*into |= (*outof++ & 0xffL) << 8;
*into++ |= (*outof++ & 0xffL);
*into = (*outof++ & 0xffL) << 24;
*into |= (*outof++ & 0xffL) << 16;
*into |= (*outof++ & 0xffL) << 8;
*into |= (*outof & 0xffL);
return;
}
static void
unscrun ( register unsigned long *outof, register unsigned char *into)
{
*into++ = (*outof >> 24) & 0xffL;
*into++ = (*outof >> 16) & 0xffL;
*into++ = (*outof >> 8) & 0xffL;
*into++ = *outof++ & 0xffL;
*into++ = (*outof >> 24) & 0xffL;
*into++ = (*outof >> 16) & 0xffL;
*into++ = (*outof >> 8) & 0xffL;
*into = *outof & 0xffL;
return;
}
static unsigned long SP1[64] =
{
0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L,
0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L,
0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L,
0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L,
0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L,
0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L,
0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L,
0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L,
0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L,
0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L,
0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L,
0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L,
0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L,
0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L,
0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L,
0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L};
static unsigned long SP2[64] =
{
0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L,
0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L,
0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L,
0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L,
0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L,
0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L,
0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L,
0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L,
0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L,
0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L,
0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L,
0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L,
0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L,
0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L,
0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L,
0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L};
static unsigned long SP3[64] =
{
0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L,
0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L,
0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L,
0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L,
0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L,
0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L,
0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L,
0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L,
0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L,
0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L,
0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L,
0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L,
0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L,
0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L,
0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L,
0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L};
static unsigned long SP4[64] =
{
0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L,
0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L,
0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L,
0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L,
0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L,
0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L,
0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L,
0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L,
0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L,
0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L,
0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L,
0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L,
0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L,
0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L};
static unsigned long SP5[64] =
{
0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L,
0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L,
0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L,
0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L,
0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L,
0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L,
0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L,
0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L,
0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L,
0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L,
0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L,
0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L,
0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L,
0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L,
0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L,
0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L};
static unsigned long SP6[64] =
{
0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L,
0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L,
0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L,
0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L,
0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L,
0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L,
0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L,
0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L,
0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L,
0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L,
0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L,
0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L,
0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L,
0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L,
0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L,
0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L};
static unsigned long SP7[64] =
{
0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L,
0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L,
0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L,
0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L,
0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L,
0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L,
0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L,
0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L,
0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L,
0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L,
0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L,
0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L,
0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L,
0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L,
0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L,
0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L};
static unsigned long SP8[64] =
{
0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L,
0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L,
0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L,
0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L,
0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L,
0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L,
0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L,
0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L,
0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L,
0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L,
0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L,
0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L,
0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L,
0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L,
0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L,
0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L};
static void
desfunc (register unsigned long *block, register unsigned long *keys)
{
register unsigned long fval,
work,
right,
leftt;
register int round;
leftt = block[0];
right = block[1];
work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL;
right ^= work;
leftt ^= (work << 4);
work = ((leftt >> 16) ^ right) & 0x0000ffffL;
right ^= work;
leftt ^= (work << 16);
work = ((right >> 2) ^ leftt) & 0x33333333L;
leftt ^= work;
right ^= (work << 2);
work = ((right >> 8) ^ leftt) & 0x00ff00ffL;
leftt ^= work;
right ^= (work << 8);
right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL;
work = (leftt ^ right) & 0xaaaaaaaaL;
leftt ^= work;
right ^= work;
leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL;
for (round = 0; round < 8; round++)
{
work = (right << 28) | (right >> 4);
work ^= *keys++;
fval = SP7[work & 0x3fL];
fval |= SP5[(work >> 8) & 0x3fL];
fval |= SP3[(work >> 16) & 0x3fL];
fval |= SP1[(work >> 24) & 0x3fL];
work = right ^ *keys++;
fval |= SP8[work & 0x3fL];
fval |= SP6[(work >> 8) & 0x3fL];
fval |= SP4[(work >> 16) & 0x3fL];
fval |= SP2[(work >> 24) & 0x3fL];
leftt ^= fval;
work = (leftt << 28) | (leftt >> 4);
work ^= *keys++;
fval = SP7[work & 0x3fL];
fval |= SP5[(work >> 8) & 0x3fL];
fval |= SP3[(work >> 16) & 0x3fL];
fval |= SP1[(work >> 24) & 0x3fL];
work = leftt ^ *keys++;
fval |= SP8[work & 0x3fL];
fval |= SP6[(work >> 8) & 0x3fL];
fval |= SP4[(work >> 16) & 0x3fL];
fval |= SP2[(work >> 24) & 0x3fL];
right ^= fval;
}
right = (right << 31) | (right >> 1);
work = (leftt ^ right) & 0xaaaaaaaaL;
leftt ^= work;
right ^= work;
leftt = (leftt << 31) | (leftt >> 1);
work = ((leftt >> 8) ^ right) & 0x00ff00ffL;
right ^= work;
leftt ^= (work << 8);
work = ((leftt >> 2) ^ right) & 0x33333333L;
right ^= work;
leftt ^= (work << 2);
work = ((right >> 16) ^ leftt) & 0x0000ffffL;
leftt ^= work;
right ^= (work << 16);
work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
leftt ^= work;
right ^= (work << 4);
*block++ = right;
*block = leftt;
return;
}
#ifdef D2_DES
void
des2key (unsigned char *hexkey,short mode)
{
short revmod;
revmod = (mode == EN0) ? DE1 : EN0;
deskey (&hexkey[8], revmod);
cpkey (KnR);
deskey (hexkey, mode);
cpkey (Kn3); /* Kn3 = KnL */
return;
}
void
Ddes (unsigned char *from, unsigned char *into)
{
unsigned long work[2];
scrunch (from, work);
desfunc (work, KnL);
desfunc (work, KnR);
desfunc (work, Kn3);
unscrun (work, into);
return;
}
void
D2des (unsigned char *from,unsigned char * into)
{
unsigned long *right,
*l1,
swap;
unsigned long leftt[2],
bufR[2];
right = bufR;
l1 = &leftt[1];
scrunch (from, leftt);
scrunch (&from[8], right);
desfunc (leftt, KnL);
desfunc (right, KnL);
swap = *l1;
*l1 = *right;
*right = swap;
desfunc (leftt, KnR);
desfunc (right, KnR);
swap = *l1;
*l1 = *right;
*right = swap;
desfunc (leftt, Kn3);
desfunc (right, Kn3);
unscrun (leftt, into);
unscrun (right, &into[8]);
return;
}
void
makekey (register char *aptr, register unsigned char *kptr)
{
register unsigned char *store;
register int first,
i;
unsigned long savek[96];
cpDkey (savek);
des2key (Df_Key, EN0);
for (i = 0; i < 8; i++)
kptr[i] = Df_Key[i];
first = 1;
while ((*aptr != '\0') || first)
{
store = kptr;
for (i = 0; i < 8 && (*aptr != '\0'); i++)
{
*store++ ^= *aptr & 0x7f;
*aptr++ = '\0';
}
Ddes (kptr, kptr);
first = 0;
}
useDkey (savek);
return;
}
void
make2key (register char *aptr,register unsigned char * kptr)
{
register unsigned char *store;
register int first,
i;
unsigned long savek[96];
cpDkey (savek);
des2key (Df_Key, EN0);
for (i = 0; i < 16; i++)
kptr[i] = Df_Key[i];
first = 1;
while ((*aptr != '\0') || first)
{
store = kptr;
for (i = 0; i < 16 && (*aptr != '\0'); i++)
{
*store++ ^= *aptr & 0x7f;
*aptr++ = '\0';
}
D2des (kptr, kptr);
first = 0;
}
useDkey (savek);
return;
}
#ifndef D3_DES /* D2_DES only */
#ifdef D2_DES /* iff D2_DES! */
void
cp2key (into)
register unsigned long *into; /* unsigned long[64] */
{
register unsigned long *from,
*endp;
cpkey (into);
into = &into[32];
from = KnR, endp = &KnR[32];
while (from < endp)
*into++ = *from++;
return;
}
void
use2key (from) /* stomps on Kn3 too */
register unsigned long *from; /* unsigned long[64] */
{
register unsigned long *to,
*endp;
usekey (from);
from = &from[32];
to = KnR, endp = &KnR[32];
while (to < endp)
*to++ = *from++;
cpkey (Kn3); /* Kn3 = KnL */
return;
}
#endif /* iff D2_DES */
#else /* D3_DES too */
static void D3des (unsigned char *, unsigned char *);
void
des3key (unsigned char *hexkey,short mode)
{
unsigned char *first,
*third;
short revmod;
if (mode == EN0)
{
revmod = DE1;
first = hexkey;
third = &hexkey[16];
}
else
{
revmod = EN0;
first = &hexkey[16];
third = hexkey;
}
deskey (&hexkey[8], revmod);
cpkey (KnR);
deskey (third, mode);
cpkey (Kn3);
deskey (first, mode);
return;
}
void
cp3key (register unsigned long *into)
{
register unsigned long *from,
*endp;
cpkey (into);
into = &into[32];
from = KnR, endp = &KnR[32];
while (from < endp)
*into++ = *from++;
from = Kn3, endp = &Kn3[32];
while (from < endp)
*into++ = *from++;
return;
}
void
use3key (register unsigned long *from)
{
register unsigned long *to,
*endp;
usekey (from);
from = &from[32];
to = KnR, endp = &KnR[32];
while (to < endp)
*to++ = *from++;
to = Kn3, endp = &Kn3[32];
while (to < endp)
*to++ = *from++;
return;
}
static void
D3des (unsigned char *from,unsigned char * into)
{
unsigned long swap,
leftt[2],
middl[2],
right[2];
scrunch (from, leftt);
scrunch (&from[8], middl);
scrunch (&from[16], right);
desfunc (leftt, KnL);
desfunc (middl, KnL);
desfunc (right, KnL);
swap = leftt[1];
leftt[1] = middl[0];
middl[0] = swap;
swap = middl[1];
middl[1] = right[0];
right[0] = swap;
desfunc (leftt, KnR);
desfunc (middl, KnR);
desfunc (right, KnR);
swap = leftt[1];
leftt[1] = middl[0];
middl[0] = swap;
swap = middl[1];
middl[1] = right[0];
right[0] = swap;
desfunc (leftt, Kn3);
desfunc (middl, Kn3);
desfunc (right, Kn3);
unscrun (leftt, into);
unscrun (middl, &into[8]);
unscrun (right, &into[16]);
return;
}
void
make3key (register char *aptr,register unsigned char * kptr)
{
register unsigned char *store;
register int first,
i;
unsigned long savek[96];
cp3key (savek);
des3key (Df_Key, EN0);
for (i = 0; i < 24; i++)
kptr[i] = Df_Key[i];
first = 1;
while ((*aptr != '\0') || first)
{
store = kptr;
for (i = 0; i < 24 && (*aptr != '\0'); i++)
{
*store++ ^= *aptr & 0x7f;
*aptr++ = '\0';
}
D3des (kptr, kptr);
first = 0;
}
use3key (savek);
return;
}
#endif /* D3_DES */
#endif /* D2_DES */
/* Validation sets:
*
* Single-length key, single-length plaintext -
* Key : 0123 4567 89ab cdef
* Plain : 0123 4567 89ab cde7
* Cipher : c957 4425 6a5e d31d
*
* Double-length key, single-length plaintext -
* Key : 0123 4567 89ab cdef fedc ba98 7654 3210
* Plain : 0123 4567 89ab cde7
* Cipher : 7f1d 0a77 826b 8aff
*
* Double-length key, double-length plaintext -
* Key : 0123 4567 89ab cdef fedc ba98 7654 3210
* Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff
* Cipher : 27a0 8440 406a df60 278f 47cf 42d6 15d7
*
* Triple-length key, single-length plaintext -
* Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
* Plain : 0123 4567 89ab cde7
* Cipher : de0b 7c06 ae5e 0ed5
*
* Triple-length key, double-length plaintext -
* Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
* Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff
* Cipher : ad0d 1b30 ac17 cf07 0ed1 1c63 81e4 4de5
*
* original source: d3des V5.0a rwo 9208.07 18:44 Graven Imagery
**********************************************************************/