//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
/* khufu.c */
/* Encrypt input file with the KHUFU cipher */
/* 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 KHUFU.MAK all clean */
#include
#include
#include "crypt.h"
#include "rnd.h"
#include
#include
#include
#ifndef uint32
typedef unsigned long uint32;
typedef unsigned char ubyte;
#endif
#ifndef bcopy
#define bcopy(src, dst, n) memcpy ((dst), (src), (n))
#endif
/*
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_khufu = 0; /* Set to 1 after a valid key has been defined */
static int encrypt_or_decrypt_khufu = ENCRYPTION_SELECT;
static char key_string_khufu[257];
/* implementation specific defines */
#define ENOUGH 16
#define OCTETS ((ENOUGH+7)/8)
uint32 SBoxes_khufu[OCTETS][256];
uint32 AuxKeys_khufu[4];
void hash128 (int, unsigned char *, unsigned char *, unsigned char *);
long hash_string( char * );
void khufu( uint32 * );
void khufuinv( uint32 * );
void hashfilename( char *, char * );
void initialize_SBoxes_khufu( void );
/*
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 KHUFU cipher uses a 64 bit block cipher.",
" The 256 entry S-boxes are generated from a hashed",
" key phrase. Sixteen rounds are used. This is a",
" variation of the Zachariassen implementation. S-boxes",
" are not modified between rounds in this version.",
" To increase security, the simple file name of the",
" encrypted file is used as part of the key. The source",
" file name for encryption and destination name for",
" decryption should be the same. Use -d for decryption.",
" Because input is processed in blocks of 8 bytes, files",
" not a multiple of 8 may increase in size with spaces",
" appended to the end.",
"",
"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 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_khufu()
{
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_khufu ( int key_type, char *key_text )
{
int i;
char *s;
FILE *fp;
for (i=0; i<257; i++) /* initialize key string */
key_string_khufu[i] = '\0';
if (key_type == KEY_FILE) /* a file name has been given */
{
if ((fp=fopen(key_text, "r")) == NULL)
{
key_defined_khufu = 0;
return 0;
}
s = key_string_khufu;
i = 0;
for (;;)
{
*s = fgetc( fp );
if ((*s == '\n') || (*s == EOF))
{
*s = '\0';
if (i == 0)
{
key_defined_khufu = 0;
break;
}
else
{
initial_seed = hash_string( key_string_khufu );
key_defined_khufu = 1;
break;
}
}
else if (i == 255)
{
*++s = '\0';
initial_seed = hash_string( key_string_khufu );
key_defined_khufu= 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_khufu;
i = 0;
for (;;)
{
*s = fgetc( stdin );
if ((*s == '\n') || (*s == EOF))
{
*s = '\0';
if (i == 0)
{
key_defined_khufu = 0;
break;
}
else
{
initial_seed = hash_string( key_string_khufu );
key_defined_khufu = 1;
break;
}
}
else if (i == 255)
{
*++s = '\0';
initial_seed = hash_string( key_string_khufu );
key_defined_khufu = 1;
break;
}
s++;
i++;
}
}
else /* copy string up to 256 characters */
{
strncpy( key_string_khufu, key_text, 256 );
key_string_khufu[256] = '\0';
initial_seed = hash_string( key_string_khufu );
key_defined_khufu = 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_khufu()
{
int i;
int j;
for (i=0; i<257; i++)
key_string_khufu[i] = '\0';
initial_seed = 0;
rnd_seed = 0;
for (i=0; i<256; i++)
for (j=0; j 16)
block_count = 16;
}
hash128 (block_count, (unsigned char*)s, init, output.array);
k = ( output.k[0] ^ output.k[1] ^ output.k[2] ^ output.k[3] );
return k;
}
/* hashfilename:
The filename can be of any format, but it must be guaranteed to
exist and be findable. In this implementation, this routine is
not called until there is a successful open of the file. We will
use MSC functions to scan the file name and obtain the simple
file name. It will be forced to a length of 8 with padding
of spaces if necessary. The name will then be doubled up to
get 16 bytes, hashed, and saved in the destination, which must
hold 16 characters, or 4 longs.
*/
void
hashfilename( char * filename, char * destination )
{
unsigned char init[16] =
{ 0x7d, 0xe1, 0x27, 0xdc, 0x78, 0x79, 0x5f, 0xe4,
0xda, 0xb9, 0x96, 0x82, 0x50, 0x5a, 0xe7, 0x81
} ;
unsigned char name[16];
char sDrive[_MAX_DRIVE];
char sDir[_MAX_DIR];
char sFname[_MAX_FNAME];
char sExt[_MAX_EXT];
int i;
_splitpath( filename, sDrive, sDir, sFname, sExt );
for (i=0; i<16; i++)
name[i] = ' ';
for (i=0; i<8; i++)
if (sFname[i] == '\0')
break;
else
name[i] = name[i+8] = toupper(sFname[i]);
hash128 (1, name, init, (unsigned char*)destination);
return;
}
/*
* Copyright 1989 by Rayan Zachariassen. Use and distribute as you see fit
* as long as you send code/cipher improvements or interesting results
* back to me.
*/
void
khufu(uint32 * datap)
{
register uint32 L, R;
register int octet;
L = *datap++ ^ AuxKeys_khufu[0];
R = *datap ^ AuxKeys_khufu[1];
for (octet = OCTETS-1; octet >= 0; --octet) {
#define ROUND(LEFT,RIGHT,ROTN) \
RIGHT ^= SBoxes_khufu[octet][LEFT & 0xff]; \
LEFT = (LEFT)>>(ROTN) | (LEFT)<<(32-ROTN);
ROUND(L,R,16);
ROUND(R,L,16);
ROUND(L,R,8);
ROUND(R,L,8);
ROUND(L,R,16);
ROUND(R,L,16);
ROUND(L,R,24);
ROUND(R,L,24);
}
*datap = R ^ AuxKeys_khufu[3];
*--datap = L ^ AuxKeys_khufu[2];
}
void
khufuinv(uint32 * datap)
{
register uint32 L, R;
register int octet;
L = *datap++ ^ AuxKeys_khufu[2];
R = *datap ^ AuxKeys_khufu[3];
for (octet = 0; octet < OCTETS; ++octet) {
#define ROUNDINV(LEFT,RIGHT,ROTN) \
LEFT = (LEFT)<<(ROTN) | (LEFT)>>(32-ROTN); \
RIGHT ^= SBoxes_khufu[octet][LEFT & 0xff]; \
ROUNDINV(R,L,24);
ROUNDINV(L,R,24);
ROUNDINV(R,L,16);
ROUNDINV(L,R,16);
ROUNDINV(R,L,8);
ROUNDINV(L,R,8);
ROUNDINV(R,L,16);
ROUNDINV(L,R,16);
}
*datap = R ^ AuxKeys_khufu[1];
*--datap = L ^ AuxKeys_khufu[0];
}
void
initialize_SBoxes_khufu( void )
{
/* First fill the S-boxes with pseudo random numbers with a seed
from the hashed key phrase. Then hash each block of the S-boxes.
This is not the recommended initialization. */
unsigned char init[16] =
{ 0x5e, 0xc1, 0xe1, 0x4e, 0xc7, 0x3c, 0x73, 0x07,
0xcb, 0xe7, 0x74, 0x1b, 0x27, 0x2d, 0x04, 0x49
} ;
char * s;
long * l;
int c;
l = (long *) SBoxes_khufu;
set_rnd_seed( initial_seed );
for (c=0; c