//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
/* tinyRSA.c */
/* RSA cipher: tiny version with 4-5 digit keys and cipher block chaining */
/* Unless otherwise noted Copyright 1995 Willis E. Howard, III */
/* Willis E. Howard, III email: WEHoward@aol.com mail: POB 1473 Elkhart, IN 46515 */
/* RSA cipher under U.S. patent 4405829 will expire September 20, 2000 */
/* tinyRSA should be considered only an educational tool because the */
/* small number of digits used in the key make decryption trivial. */
/* Use of this program is not in violation of U.S. patent 4405829 */
/* because it does not perform public key cryptography. */
/* Program TINYKEY should be used to generate public and private keys. */
/* Program TINYSOLV can generate private keys from public keys. */
/* If a version of TINYSOLV could be written for 200 digit keys, */
/* no current version of RSA would be secure. */
/* Theory of RSA:
Choose two really large prime numbers p and q.
(This program uses really small prime numbers p and q.)
Then, p * q = n, where modulus n should have 150-200 digits.
Select a random number e subject to the condition that
e and (p-1)(q-1) are relatively prime, or gcd(e,(p-1)(q-1)) = 1.
Finally, solve for d where e * d = 1 mod((p-1)(q-1)).
We have e and n as public keys, d and n as private keys.
The above procedure is done by key selection software.
To encrypt message block x, calculate y = x^e mod(n).
Tell everybody -- even your brother -- the values e and n.
They can use the above formula to send you encrypted messages.
To decrypt message block y, calculate x = y^d mod(n).
Don't tell anybody the value of d. As long as n is over
120 digits, state of the art can not get d from e and n.
The message blocks should have a length just short of the
length of n.
*/
/* under MSDOS, NMAKE /F TINYRSA.MAK all clean */
/* Note:
Encrypted files double in size. This is a side effect of the
way that tinyRSA is implemented. With a little bit packing,
the size of the encrypted files could be made smaller. But,
this is such an insecure implementation that you shouldn't
be using it for anything serious anyway.
*/
#include
#include
#include "crypt.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.
*/
static int key_defined_tinyrsa = 0; /* Set to 1 after a valid key has been defined */
static int encrypt_or_decrypt_tinyrsa = ENCRYPTION_SELECT;
static char key_string_tinyrsa[257];
static unsigned int key_1;
static unsigned int key_2;
int process_key ( char * );
long modexp_l ( long, long, long );
/*
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 patented RSA cipher with 4-5 digit keys.",
" 16 bit keys are is used to encrypt an 8 bit block with CBC.",
" For decryption, the 16 bit keys decrypt a 16 bit block to 8 bits.",
" Cipher block chaining uses zero based vector initialization.",
" Integer (16 bit or 4-5 digit) keys are used in this version.",
" The RSA cipher needs about 150 digits to be really secure.",
" This version is completely insecure and even includes a utility",
" to generate the private key from the public key. However, the",
" program may be educational for learning about the cipher.",
"",
" Use the -d option for decryption.",
"",
"KEY",
" The key consists of two decimal numbers in the range 2-65535.",
" The keys must be generated using the program TINYKEY. Use the",
" public key pair with the -e option for encrytion and the private",
" key pair with the -d option for decryption.",
"",
" On the command line with the -k option, enclose the two",
" decimal numbers in quotes.",
"",
" If a key file exists, only the first line is read, and",
" it is used as the key pair. Quotes are not needed.",
"",
" If there is no key pair, you will be prompted for one.",
NULL
};
char **
crypt_help_tinyrsa ()
{
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_tinyrsa (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_tinyrsa = 0;
return 0;
}
s = key_string_tinyrsa;
i = 0;
for (;;)
{
*s = fgetc (fp);
if ((*s == '\n') || (*s == EOF))
{
*s = '\0';
if (i == 0)
{
key_defined_tinyrsa = 0;
break;
}
else
{
key_defined_tinyrsa = process_key (key_string_tinyrsa);
qDebug("crypt_key_tinyrsa:key_defined_tinyrsa=%d", key_defined_tinyrsa);
system("pause");
break;
}
}
else if (i == 255)
{
*++s = '\0';
key_defined_tinyrsa = process_key (key_string_tinyrsa);
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_tinyrsa;
i = 0;
for (;;)
{
*s = fgetc (stdin);
if ((*s == '\n') || (*s == EOF))
{
*s = '\0';
key_defined_tinyrsa = process_key (key_string_tinyrsa);
break;
}
else if (i == 255)
{
*++s = '\0';
key_defined_tinyrsa = process_key (key_string_tinyrsa);
break;
}
s++;
i++;
}
}
else
/* copy string up to 256 characters */
{
strncpy (key_string_tinyrsa, key_text, 256);
key_string_tinyrsa[256] = '\0';
key_defined_tinyrsa = process_key (key_string_tinyrsa);
}
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_tinyrsa ()
{
int i;
for (i = 0; i < 257; i++)
key_string_tinyrsa[i] = '\0';
key_1 = 0;
key_2 = 0;
key_defined_tinyrsa = 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_tinyrsa (int selection)
{
if (selection == ENCRYPTION_SELECT)
encrypt_or_decrypt_tinyrsa = ENCRYPTION_SELECT;
if (selection == DECRYPTION_SELECT)
encrypt_or_decrypt_tinyrsa = DECRYPTION_SELECT;
return encrypt_or_decrypt_tinyrsa;
}
/*
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_tinyrsa (char *source, char *dest)
{
int cbc;
int fcbc;
int count;
int buffer;
FILE *infile;
FILE *outfile;
qDebug("crypt_file_tinyrsa:key_defined_tinyrsa=%d, key_string_tinyrsa=%s ",key_defined_tinyrsa, key_string_tinyrsa);
system("pause");
while (!key_defined_tinyrsa)
crypt_key_tinyrsa (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;
}
cbc = fcbc = buffer = 0; /* zero initialization vector */
if (encrypt_or_decrypt_tinyrsa == ENCRYPTION_SELECT)
count = 1;
else
count = 2;
while (count = fread ((char *) &buffer, sizeof (char), count, infile))
{
if (encrypt_or_decrypt_tinyrsa == ENCRYPTION_SELECT)
{
buffer ^= ((cbc & 0xff) & (cbc << 8)) ;
buffer = (int) modexp_l((long) buffer, (long) key_1, (long) key_2);
cbc = buffer;
}
else
{
cbc = buffer;
buffer = (int) modexp_l((long) buffer, (long) key_1, (long) key_2);
buffer ^= ((fcbc & 0xff) & (fcbc << 8));
fcbc = cbc;
}
/* encrypt 1 byte into 2 bytes; decrypt 2 bytes to 1 byte */
if ((3 - count) != fwrite ((char *) &buffer, sizeof (char), 3 - count, outfile))
{
fprintf (stderr, "Could not write to %s\n", source);
fclose (infile);
fclose (outfile);
return 1;
}
else
buffer = 0;
}
fclose (infile);
fclose (outfile);
return 0;
}
int
process_key(char *p)
{
unsigned int i;
char *s;
s = p;
qDebug("process_key:p=%s", p);
system("pause");
/* skip non-digits */
while (!isdigit(*s))
if (*s != '\0')
s++;
else
return 0;
/* get first number */
key_1 = 0;
while (isdigit(*s))
key_1 = (key_1 * 10) + (*s++ - '0');
/* skip non-digits */
while (!isdigit(*s))
if (*s != '\0')
s++;
else
return 0;
/* get second number */
key_2 = 0;
while (isdigit(*s))
key_2 = (key_2 * 10) + (*s++ - '0');
/* force key_1 less than key_2 (n larger than e or d) */
if (key_2 < key_1)
{
i = key_1;
key_1 = key_2;
key_2 = i;
}
/* error if either is zero */
return key_1;
}
long
modexp_l(long a, long x, long n)
{
long r = 1;
while (x > 0)
{
if (x & 1) /* is x odd? */
r = (r * a) % n;
a = (a*a) % n;
x /= 2;
}
return r;
}