Click here to Skip to main content
Email Password   helpLost your password?

Introduction

In this article, I'll show how to do a simple but robust encryption/decryption, with the algorithm of Gilbert Sandford, Vernam. This kind of encryption is truly unbreakable as long the key is maintained a secret.

Background

Vernam cipher is a stream cipher where the original or plain data is XORed with a random (actually pseudorandom) stream of data of the same length to generate the encrypted data. When the stream of data used as key is truly random and used only once, it is called a one-time pad. A widely used implementation of the Vernam cipher is RC4.

Advantages

The Vernam cipher with one-time pads is the only known encryption procedure where, in theory, information is secure and can't be deciphered, if the key is randomly and only once used for encryption . For decrypting, only the secret key and the encrypted data is used.

Other encryption methods (such as AES) achieve their security with the immense burden of calculating theoretically conceivable decoding, which is practically not feasible. In other words, a potential attacker lacks the necessary resources (computing capacity or time) to perform his attack successfully. The security of one-time pad, on the other hand, is based on the unique use of the key and sufficient randomness of the used key. Even with increasing computing power, it can't be broken.

Due to the fact that encryption is done by XOR, the algorithm is pretty fast. For decrypting data, the same algorithm can be used - it's symmetric.

Disadvantages

The Vernam cipher requires a key with the same length as the original data. For example, the encryption of a hard disk requires a second hard disk (with at lest the same size) to store the key.

Another disadvantage of one-time pads is that the data of the key has to be, ideally, completely randomly chosen. Most computers are not able to generate really random keys.

How the algorithm works

First, the bytes of the input file are read:

byte[] originalBytes;
using (FileStream fs = new FileStream(originalFile, FileMode.Open))
{
    originalBytes = new byte[fs.Length];
    fs.Read(originalBytes, 0, originalBytes.Length);
}

Then, the one-time pad - the key - is created. This is done by generating random bytes that are of the same length as the original (plain) bytes. The key bytes get written to the specified file.

byte[] keyBytes = new byte[originalBytes.Length];
Random random = new Random();
random.NextBytes(keyBytes);

// Write the key to the file:
using (FileStream fs = new FileStream(keyFile, FileMode.Create))
{
    fs.Write(keyBytes, 0, keyBytes.Length);
}

The encryption - for decryption the same algorithm is used - is straightforward, by using XOR.

private void DoVernam(byte[] inBytes, byte[] keyBytes, ref byte[] outBytes)
{
    // Check arguments:
    if ((inBytes.Length != keyBytes.Length) ||
        (keyBytes.Length != outBytes.Length))
        throw new ArgumentException("Byte-array are not of same length");

    // Encrypt/decrypt by XOR:
    for (int i = 0; i < inBytes.Length; i++)
        outBytes[i] = (byte)(inBytes[i] ^ keyBytes[i]);
}

Using the code

To encrypt/decrypt data, the class provided is quite simple. See the example below.

using gfoidl.Security;

// Create an instance of the class:
Vernam vernam = new Vernam();

// Test with an image:
vernam.EncryptFile("Image.gif", "Image_encrypted.gif", "Key01.dat");
vernam.DecryptFile("Image_encrypted.gif", "Key01.dat", 
                   "Image_decrypted.gif");

// Test with text file:
vernam.EncryptFile("Text.txt", "Text_encrypted.txt", "Key02.dat");
vernam.DecryptFile("Text_encrypted.txt", "Key02.dat", 
                   "Text_decrypted.txt");

// Test with pdf file:
vernam.EncryptFile("Text.pdf", "Text_encrypted.pdf", "Key03.dat");
vernam.DecryptFile("Text_encrypted.pdf", "Key03.dat", 
                   "Text_decrypted.pdf");

The key is produced by the class and has the same length as the original data. Randomly generated bytes are used as keys.

For decryption the same key has to be used as for encrypting the file.

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralQuestion
kma69
8:14 11 Feb '09  
Instead of using random key of the same length, why not use the file contents? I've used this encryption model before and find it a tad more "secure" to encrypt the contents with the contents of the file instead of some random key (same length as the contents). Just some thoughts.

Otherwise, good article. Big Grin
GeneralRe: Question
kma69
8:21 11 Feb '09  
Nevermind...My bad. You are reading in the bytes of the file and randomizing the bytes (encrypting). What I meant to say in my earlier message post was I embedded a key in the file at random locations. So, if I moved the file or transported it, I was able to decrypt the file by extracting the key. Maybe if I explained myself properly the first time, I would have had to write this post Sigh
General"Cracking" a Random Number Generator
jcdege
3:23 30 Sep '08  
Jim Reeds published an article entitled "Cracking a Random Number Generator" in the very first issue of Cryptologia, back in 1977.

In it, he shows a cipher similar to yours, based on the commonly used linear congruential PRNG, and shows how little information is needed to reconstruct the seed and modulus used in the PRNG. All you need is to successfully guess a handful of bytes.

The problem with non-crypto-secure PRNGs is that they don't have very much internal state, so it isn't hard to reconstruct them.

"Cracking" a Random Number Generator by James Reeds. Volume I, Number 1, January 1977.20-26[^]
GeneralRe: "Cracking" a Random Number Generator
Günther M. FOIDL
4:02 30 Sep '08  
Hi,

thanks for the article - very interesting.

Look at the answer of the previous message.

Kind regards

GeneralUse of Random class
Aelthegrin
9:08 29 Sep '08  
Hi Gunther, nice articleSmile

I made OTP program myself in python some time ago, it had an option to send encrypted messages over e-mail and import it directly from POP3 server for decryption. On Linux it was using /dev/(u)random, and on Windows I can't really remember, but I think it was RNG provided with crypto++. Unfortunately I lost it somewhere, though I think I could find it on one of my older hard disksSmile

MSDN states that Random class:
"Represents a pseudo-random number generator, a device that produces a sequence of numbers that meet certain statistical requirements for randomness"

And:
"To generate a cryptographically secure random number suitable for creating a random password, for example, use a class derived from System.Security.Cryptography.RandomNumberGenerator such as System.Security.Cryptography.RNGCryptoServiceProvider."

As you know, OTP is COMPLETELY USELESS if the pad itself is vulnerable, and by using somewhat easily predictable numbers it certainly is.

I don't know the internals of RNGCryptoServiceProvider, but I assume it is the wrapper around CryptGenRandom which is also used by most of the crypto libraries on Windows, though it's not very secure:(

GeneralRe: Use of Random class
Günther M. FOIDL
11:03 29 Sep '08  
Hi,

I know that the random-generator I've implemented isn't really random - it is based on Donald E. Knuth's subtractive random number generator algorithm.

More than implementing a real random generator I wanted to show how simple encryption/decryption can be. It's up to you to implement better random generators. As you mentioned the Windows crypto generators aren't really secure too.

For real security the key has to be produced by other methods. Let's quote John von Neumann: "Anyone who uses arithmetic methods to produce random numbers is in a state of sin."

Thanks for your post and your thoughts about pseudo random numbers.

regards Gü
GeneralInteresting article
rht341
5:12 28 Sep '08  
Very interesting article, thanks!

Rich
GeneralRe: Interesting article
Günther M. FOIDL
11:57 22 Oct '09  
Hi Rich,

thanks for feedback!

Cheers,
Günther


Last Updated 27 Sep 2008 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010