分类: C/C++
2006-06-23 13:30:44
==============================================================================
Simple File Encrytion Using a One-Time-Pad and Exclusive OR
==============================================================================
/*
Simple File Encryption using a One-Time-Pad and Exclusive OR
or
"How I learned to love bitwise logical operations in C."
by
Aegis (Glen E. Gardner, Jr.)
Aegis@
ggardner@ace.cs.ohiou.edu
for
C-scene Magazine
I'm no expert in encryption, so if I abuse the technical jargon a bit, please
excuse me. If my methods turn out to be completely idiotic, please feel free to
send me your scathing remarks and I will be more than glad to promptly forward
them to my circular file.
Let Us Begin
The black art of encryption has always amazed me. It's all about
concealment and decption. Hiding information in plain sight while
making it too confusing, too complicated or too slow a job for
the bad guys to crack.
There are a number of heavy-duty encryption schemes in the world
that are known to work well. In recent years, more and more of them
have fallen under the onslaught from persistent coders armed with
increasingly sophisticated and powerful combinations of hardware
and software.
With the almost exponential growth in the speed and power of today's
software and hardware, one understandibly gets the impression that no system
is secure and that almost no encryption scheme is uncrackable
(Be very afraid, it's worse than you think).
Almost amazingly, there are some surprisingly simple encryption methods
that are really very good. In fact, if used carefully, they are about
as "secure" as anthing else.
One of these schemes (the one I'm going to cover here) involves
logically ORing the bytes in a target file with randomly generated numbers,
resulting in an encrypted file. This sceme is often called an "OTP", or,
"One-Time-Pad", because it generates a key only once.
Here Is How It Works
We'll be using a bitwise EXCLUSIVE OR , XOR to do the encryption.
XOR sets the result to 1 only if either bit is 1, but not if both are 1.
Here is an excerpt from "ANSI C PROGRAMMING" by Steven C. Lawlor ,
West Publishing, ISBN 0-314-02839-7
from pages 316,317
BITWISE EXCLUSIVE OR
Using the bitwise exclusive OR , or bitwise XOR (^), the resultant bit is 1 if
either , but not both, of the examined bits are 1. In other words, if the bits
are different, the results will be 1. Sample results from value1^value2 are:
value1 00110100 10111000 11000010
^ value2 01000110 00001100 10001100
= result 01110010 10110100 01001110
The XOR has three interesting properties. First, any value XORed with itself
(value ^ value) will result in zero.
value 00110100 10111000 11000010
^ value 00110100 10111000 11000010
= result 00000000 00000000 00000000
This can be used as a test for equality; value1^value2 is zero if the values
are equal. Assembly language programmers sometimes use this as a method of
setting a value to zero, because it is slightly more efficient than a straight
assignment. Since program clarity is, in most cases, more important than
small increases in efficiency, we should probably use value=0 rather than
value ^=value.
A second property is that a value XORed twice with a specific value returns to
it's original value. The expression value1^value2^value2 always equals value1.
value1 00110100 10111000 11000010
^ value2 01000110 00001100 10001100
= 01110010 10110100 01001110
^ value2 01000110 00001100 10001100
= result 00110100 10111000 11000010
This is sometimes used as a part of a simple encryption routine. To encrypt
data each byte is XORed with a specific encryption byte. To decrypt it, the
data is put through the same process.
Carrying this a step further, the following can be used to swap two values
without the need for a temporary variable.
value1 ^= value2;
value2 ^= value1;
value1 ^= value2;
A third property is that any bit XORed with a 1 bit will be reversed. This
is used to toggle bits--set them to 0 if they were 1, or 1 if they were 0. The
following examples toggle bits two and six....
value 10010100 00111011 11001010
^ toggle 01000100 01000100 01000100
= result 01010000 01111111 10001110
And that is all we will borrow from Mr. Lawlor today...
About The Program
The program opens the key and the source files, reads a byte from both , XOR's
the two numbers together, then saves the result to the destination file. The
process is repeated over until the end of the source file is reached.
If the default key was found at runtime a new key is not made , and the program
uses the existing default key. Upon completion, the default key is deleted.
If no default key was found, and no key name was provided on the command line,
a default key will be made prior to encryption and will not be deleted.
Likewise, if a key name was provided on the command line, the key will not be
deleted when the program completes.
The program requires a key the same length as the source file. If a file is not
found, a suitable key is generated. Each byte of the source is XORed
with a byte from the key and saved to the destination file. In the case of
the key generated by the program, the pseudorandom numbers range from 0 through
255d. You can use any file as a key, but be careful. Key file bytes with the
decimal value of 0 will not encrypt the source. You might be better using a
chapter from the Holy Bible , or Principia Discordia as a key , than use a
binary. When in doubt, use the program to generate a psuedorandom key.
Using The Program
The user inputs the source file name, destination file name, and the name of the
key to be used. The program uses the key to encrypt the source file, and if no
key name is supplied, generates a new key using a psuedo-random number generator
that has been seeded from the real time clock. The encrypted data is then
saved to the destination file.
To decrypt a file, you will need to have the encrypted file and the same key it
was encrypted with. Run the program, providing the name of the encrypted file,
followed by the desired destination file name and the key file name. The
unencrypted file will then be saved as the destination file. If no key name was
provided to the program, it will look for a key called "newkey" and use it.
If newkey exists (it must if you are using the default and want to decrypt) it
will be used and then deleted.
You will probably need to know the original filename and extension of the file,
since the encryption program does not keep track of that.
If no name is specified for the key, or the file is not found, the program will
generate a key of it's own , using pseudorandom numbers. If the program finds a
key with the same name as the default name (newkey) it uses the existing file
then deletes it to prevent the key from being reused.
Bugs & Quirks
The program will allow you to use a key that is shorter than the source.
This means that once the end of the key file is reached, all of the remaining
source bytes will be encrypted with the same key value (FFh), possibly making
a portion of the file easy to crack. BE SURE THE KEY IS AS BIG AS THE SOURCE,
OR BIGGER.
This was a bit of a stupid oversight on my part. As of press time, there
was not really enough time to change the program so that it would refuse a key
that was too small. Just be aware of the bug, or make your own fix to the
source code.
Using keys over is a bad thing. Since the computer can not generate "true"
random numbers, there is a pattern to the pseudorandom numbers it generates.
Using a key over and over gives crackers a chance at discovering the key
by making a few guesses about the contents of a file. If they get enough files
that use the same key, you will almost certainly end up getting cracked.
DON'T REUSE KEYS!
I suspect that encrypting really long files might make them easier to crack
because of the slight tendency of some random number generators to eventually
repeat a sequence of "random" numbers. So, beware of encrypting really big
files unless you know your key is truly "random".
This program was test compiled on FreeBSD using GCC and on Windows NT 4.0 ,
using BC5.01. Linux or OS/2 users should have no problems compiling the source.
DOS users will probably be able to make it work with a minimum of fussing, but I
strongly reccomend that those users to move up to a 32-bit operating system.
*/
/* CRYPTIC.C V 1.0 Copyright 1998 by Glen E. Gardner, Jr. */
/* Encrypts a file using a random key and saves the key. */
/* Automatically generates a new key when needed. The new */
/* key is deleted on the second use (decryption) to prevent */
/* accidental reuse of the same key for encryption. */
/* This program is freeware, use it freely and enjoy! */
/* Be sure to cite the author and include the original */
/* source in all distributions. */
/* Written and compiled in ANSI C using Borland C++ V 5.02 */
/* Tested on Windows NT 4.0 and FreeBSD 2.2.5 (using gcc). */
/* Run this program once to encrypt and agin, using the */
/* same key, to decrypt. */
/* Any file can be used as a key provided it is the */
/* same size (or larger) as the file being encrypted. */
/* (small,repeating keys are for whimps) */
/* You need to be careful what you use as a key. If you */
/* don't believe this, try encrypting a file using a windows*/
/* dll file as a key and looking at the output with a text */
/* editor. */
/* The encrypted output is binary. You can use cryptic to */
/* encrypt any file. */
#include
#include
#include
/* Use this include with GCC on FreeBSD machines. */
/* #include */
/* Use this include instead of the one above for Windows NT. */
#include
void makekey(long int,char *);
int main(int argc,char **argv)
{
struct stat statbuf;
time_t t;
int key;
int data;
int output;
int count=0;
int FLAG=0;
FILE * mykeyfile;
FILE * sourcefile;
FILE * destfile;
if(argc<3)
{
printf("CRYPTIC Coyright 1998 by Glen E. Gardner, Jr.\n");
printf("USE: CRYPTIC\n");
return(0);
}
/* Note that if no key name is given, the program generates and uses a new key. */
/* Be sure the right key is present when decrypting (duh). The program does not*/
/* know if it is encrypting or decrypting. It just crunches the source file with*/
/* whatever key it has and spits out the result. */
/* Bail out if the wrong number of arguments are used. */
if(argc>4){printf("Too many arguments.");return(1);}
/* Seed the random number generator for later use. */
srand((unsigned) time(&t));
/* get the size of the source file */
if ((sourcefile = fopen(argv[1], "rb"))== NULL)
{
printf("Can't open source file.\n");
return(4);
}
fflush(sourcefile);
fstat(fileno(sourcefile), &statbuf);
fclose(sourcefile);
/* Look for default key file if none is given */
if(argv[3]==NULL){argv[3]="newkey";}
/* If the key is not found make a new one. */
if ((mykeyfile = fopen(argv[3], "r"))== NULL)
{
FLAG=1;
printf("Can't open key file.\n");
printf("Making a new key...\n");
makekey(statbuf.st_size,"newkey");
}else{fclose(mykeyfile);}
/* open all the necessary files. */
mykeyfile=fopen(argv[3],"rb");
sourcefile=fopen(argv[1],"rb");
destfile=fopen(argv[2],"wb");
/* Use the key to encrypt/decrypt the source file. */
while (count < (statbuf.st_size))
{
key=fgetc(mykeyfile);
data=fgetc(sourcefile);
/* This is all there is to it. */
output=(key^data);
/* XOR the data byte once with a byte from a key and it encrypts. */
/* XOR the resultant byte again with the same byte from the same key, and it decrypts. */
/* write the result to the output file. */
fputc(output,destfile);
count++;
}
/* close the files. */
fclose(mykeyfile);
fclose(sourcefile);
fclose(destfile);
/* Delete the default key on the second time around to prevent it being reused. */
/* The key is deleted only if a key was not specified and if the default */
/* key is not new. */
if(FLAG==0)
{
/* use this for Windows NT */
system("erase newkey");
/* use this for FreeBSD */
/* system("rm newkey"); */
}
return(0);
}
/* MAKEKEY() makes a key using random numbers. */
/* The random number generator is seeded from the real time clock. */
/* It is fairly random, but the nature of the pseudorandom generator is not */
/* completely random. This means that a clever programmer will */
/* eventually crack your key. */
/* Don't reuse keys, and consider investing time in a better way of generating */
/* random number strings to use as a key. */
void makekey(long int size,char *name)
{
int byte;
int count=0;
FILE * filein;
filein=fopen(name,"wb");
while(count<size)
{
byte=rand() % 256;
fprintf(filein,"%c",byte);
count++;
}
fclose(filein);
}
This page is Copyright © 1997 By
. All Rights Reserved