//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
/* enigma.c */
/* enigma encryption cipher from Henry Tieman implementation */
/* 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 ENIGMA.MAK all clean */
#include
#include
#include "crypt.h"
#include "enigma.h"
#include
#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.
*/
void init_mach (void);
int encipher (int);
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
static int key_defined_enigma = 0; /* Set to 1 after a valid key has been defined */
static int encrypt_or_decrypt_enigma = ENCRYPTION_SELECT;
/* Define SAVE_CASE to (0) for all upper case, and to (1) to retain case */
#define SAVE_CASE (1)
/* key information */
#define NUM_ROTORS 5
static char ref_rotor[27] = "YRUHQSLDPXNGOKMIEBFZCWVJAT";
static char rotor[NUM_ROTORS][27] =
{ /* pre defined rotors */
"EKMFLGDQVZNTOWYHXUSPAIBRCJ",
"AJDKSIRUXBLHWTMCQGZNPYFVOE",
"BDFHJLCPRTXVZNYEIWGAKMUSQO",
"ESOVPZJAYQUIRHXLNFTGKDCMWB",
"VZBRGITYUPSDNHLXAWMJQOFECK",
};
static int step_data[NUM_ROTORS] =
{
16, 4, 21, 9, 25 /* steps at: q, e, v, j, z */
};
/*
* enigma key default settings
*/
static int order[3] =
{0, 1, 2}; /* rotor order, user input is +1 */
static char ring[8] =
{ /* ring settings */
'\0', 'A', 'A', 'A', /* default: AAA */
'\0', '\0', '\0', '\0'};
static int n_plugs = 0; /* number of plugs */
static char plugs[80] = ""; /* plug string */
static int pos[3] =
{0, 0, 0}; /* rotor positions */
/*
* simulation data and machine state data
*/
static int data[8][26]; /* working array for machine */
static int rdata[8][26]; /* reverse array */
static int step[3]; /* steps coresponding to rotors */
static int double_step; /* rotor 2 step twice */
/*
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 ENIGMA cipher uses multiple rotors. It was originally",
" implemented as a mechanical rotor device, and was used by",
" Germany during the second World War. Each rotor moves at a",
" different rate, giving a large period for the combination.",
" This version retains upper and lower case.",
"",
"KEY",
" A key file name is expected as the argument for the -k option.",
"",
" The key contains the following information:",
" n n n - for rotor order (1 to 5)",
" x x x - for ring setting, x is a letter",
" n - Number of plugs (0 to 13)",
" xx xx xx ... - Plug letter pairs, one for each n",
" x x x - initial rotor position, x is a letter",
"",
" If the '-k ?' option is given, or if there is no key file,",
" you will be prompted for key data.",
NULL
};
char **
crypt_help_enigma ()
{
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_enigma (int key_type, char *key_text)
{
FILE *fp; /* input file */
int num; /* dummy returned from fscanf() */
int idx; /* index/counter */
char a[4]; /* dummy for input */
char buffer[132]; /* used with sscanf */
if (key_type == KEY_FILE) /* a file name has been given */
{
if ((fp = fopen (key_text, "r")) == NULL)
{
key_defined_enigma = 0;
return 0;
}
num = fscanf (fp, "%d %d %d\n", &order[0], &order[1], &order[2]);
num = fscanf (fp, "%c %c %c\n", &ring[1], &ring[2], &ring[3]);
num = fscanf (fp, "%d\n", &n_plugs);
if (n_plugs != 0)
{
num = fscanf (fp, "%[^\n]\n", plugs);
}
num = fscanf (fp, "%c %c %c\n", &a[0], &a[1], &a[2]);
for (idx = 0; idx < 3; idx++)
{
(order[idx])--;
ring[idx + 1] = toupper (ring[idx + 1]);
pos[idx] = toupper (a[idx]) - 'A';
}
fclose (fp);
key_defined_enigma = 1;
return 0;
}
else if (key_type == KEY_IMMEDIATE) /* a key string has been given */
{
if (!strcmp (key_text, "?")) /* prompt for key */
{
printf ("Rotor order (3 numbers from 1 to 5 separated by spaces): ");
(void) gets(buffer);
num = sscanf (buffer, "%d %d %d", &order[0], &order[1], &order[2]);
printf ("Ring settings (3 letters separated by spaces): ");
(void) gets(buffer);
num = sscanf (buffer, "%c %c %c", &ring[1], &ring[2], &ring[3]);
printf ("Number of plugs (number from 0 to 13): ");
(void) gets(buffer);
num = sscanf (buffer, "%d", &n_plugs);
if (n_plugs != 0)
{
printf ("Plug letter pairs (one pair per plug): ");
(void) gets(buffer);
num = sscanf (buffer, "%[^\n]", plugs);
}
printf ("Initial rotor position (3 letters separated by spaces): ");
(void) gets(buffer);
num = sscanf (buffer, "%c %c %c", &a[0], &a[1], &a[2]);
for (idx = 0; idx < 3; idx++)
{
(order[idx])--;
ring[idx + 1] = toupper (ring[idx + 1]);
pos[idx] = toupper (a[idx]) - 'A';
}
key_defined_enigma = 1;
return 0;
}
else
return crypt_key_enigma (KEY_FILE, key_text);
}
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 for the key can not be obtained from
an examination of memory.
*/
void
crypt_key_erase_enigma ()
{
int i;
order[0] = 0;
order[1] = 1;
order[2] = 2;
for (i = 0; i < 8; i++)
ring[i] = '\0';
for (i = 1; i < 4; i++)
ring[i] = 'A';
n_plugs = 0;
for (i = 0; i < 80; i++)
plugs[i] = '\0';
pos[0] = 0;
pos[1] = 0;
pos[2] = 0;
key_defined_enigma = 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_enigma (int selection)
{
if (selection == ENCRYPTION_SELECT)
encrypt_or_decrypt_enigma = ENCRYPTION_SELECT;
if (selection == DECRYPTION_SELECT)
encrypt_or_decrypt_enigma = DECRYPTION_SELECT;
return encrypt_or_decrypt_enigma;
}
/*
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_enigma (char *source, char *dest)
{
char *s;
int c;
int case_char;
FILE *infile;
FILE *outfile;
qDebug("crypt_file_enigma: key_defined_enigma = %d, y el encrypt_or_decrypt_enigma=%d", key_defined_enigma, encrypt_or_decrypt_enigma);
while (!key_defined_enigma)
crypt_key_enigma (KEY_IMMEDIATE, "?");
init_mach_enigma ();
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;
}
while ((c = fgetc (infile)) != EOF)
{
if (isalpha (c)) /* only letters changed */
{
case_char = c;
c = encipher_enigma ((int) (toupper (c))); /* and with a loss of case */
if (SAVE_CASE && islower(case_char)) /* restore case if requested */
c = tolower(c);
}
if (fputc (c, outfile) == EOF)
{
fprintf (stderr, "Could not write to output file %s\n", dest);
fclose (infile);
fclose (outfile);
return 1;
}
}
fclose (infile);
fclose (outfile);
return 0;
}
/*
* init_mach - set up data according to the input data
*/
static void
init_mach_enigma (void)
{
int i, j; /* indices */
int ds; /* used during ring settings */
int u, v; /* temps for plugboard input */
/* setup rotor data */
for (j = 0; j < 26; j++)
data[4][j] = ((int) ref_rotor[j] - 'A' + 26) % 26;
for (i = 1; i < 4; i++)
{
step[i - 1] = step_data[order[i - 1]];
for (j = 0; j < 26; j++)
{
data[i][j] = ((int) (rotor[order[i - 1]][j]) - 'A' + 26) % 26;
data[8 - i][data[i][j]] = j;
}
}
/* setup ring settings */
ring[7] = ring[1];
ring[6] = ring[2];
ring[5] = ring[3];
for (i = 1; i < 8; i++)
if (i != 4)
{
ds = (int) (ring[i]) - 'A';
if (ds != 0)
{
for (j = 0; j < 26; j++)
data[0][j] = data[i][j];
for (j = 0; j < 26; j++)
data[i][j] = data[0][(26 - ds + j) % 26];
}
}
/* setup plug data */
if (n_plugs != 0)
{
j = 0;
for (i = 0; i < 26; i++)
data[0][i] = i;
for (i = 0; i < n_plugs; i++)
{
while (!isalpha (plugs[j]))
{
j++;
if (plugs[j] == '\0')
break;
}
u = toupper (plugs[j++]) - 'A';
v = toupper (plugs[j++]) - 'A';
data[0][u] = v;
data[0][v] = u;
}
}
/* convert all moving rotor data to displacements */
for (i = 1; i < 8; i++)
{
if (i != 4)
for (j = 0; j < 26; j++)
data[i][j] = (data[i][j] - j + 26) % 26;
}
/* compute reverse */
if (n_plugs != 0)
for ( i=0; i<26; i++ )
rdata[0][(data[0][i])%26] = i;
for ( i=0; i<26; i++ )
rdata[4][(data[4][i])%26] = i;
for ( i=1; i<8; i++ )
if (i != 4)
for ( j=0; j<26; j++ )
rdata[i][(j + data[i][j])%26] = j;
/* setup rotor starting positions */
double_step = FALSE; /* no previous rotor position */
/* input function has already done the rotor positions */
}
/*
* encipher - c implementation of the enigma cipher function
*/
static int
encipher_enigma (int c)
{
int j; /* index for counting */
int idx; /* rotor index */
if (isalpha (c))
{
pos[0] = (pos[0] + 1) % 26; /* first, advances the rotors */
if (pos[0] == step[0])
pos[1] = (pos[1] + 1) % 26;
if (double_step)
{
pos[1] = (pos[1] + 1) % 26;
pos[2] = (pos[2] + 1) % 26;
double_step = FALSE;
}
if (pos[1] == step[1])
double_step = TRUE;
c -= 'A'; /* start to encipher */
if (encrypt_or_decrypt_enigma == ENCRYPTION_SELECT)
{
if (n_plugs != 0)
c = data[0][c];
for (j = 0; j < 3; j++) /* do rotors forward */
{
idx = (c + pos[j]) % 26;
c = (c + data[j + 1][idx]) % 26;
}
c = (data[4][c]) % 26; /* reflecting rotor */
for (j = 0; j < 3; j++) /* do rotors reverse */
{
idx = (c + pos[2 - j]) % 26;
c = (c + data[j + 5][idx]) % 26;
}
if (n_plugs != 0)
c = data[0][c];
}
else
{
if (n_plugs != 0)
c = rdata[0][c];
for (j=2; j>=0; j--)
c = ( 26 + rdata[j + 5][(c + pos[2 - j]) % 26 ] - pos[2 - j] ) %26;
c = rdata[4][c] % 26;
for (j=2; j>=0; j--)
c = ( 26 + rdata[j + 1][(c + pos[j]) % 26 ] - pos[j] ) %26;
if (n_plugs != 0)
c = rdata[0][c];
}
c += 'A';
}
return (c);
}