Introduction
Encryption is a hot topic in the news currently, with Dutch headlines talking about a possible dragnet to spy on the entire population. It would mean that those currently governing can spy on political opponents.
Background
This tip shows a very simple example implementation of a "one time pad" (see wiki). This is an unbreakable encryption. As long as your key remains private, no government will ever decypher it.
Using the code
Think of a character, any character. Add a random number. If the result is not a valid character, subtract the amount of different characters in your characterset. The result is your encrypted version, the random number you picked is the key, and the character was the original data. It is that simple.
The reason this is not the default encryption on the internet is the fact that the key becomes as large as the data you are encrypting. Next problem is that you can't send them over the same channel, as that would compromise the key - anyone listening would be able to decode the original.
So this is not very practical for your average webhost. For those who feel they need this level of security, there's an easy alternative. While it may have been impractical to use in the past, it is rather easy to generate a terrabyte worth of random data and put it on a portable harddisk, given to some idiot tourist. Once you need to encrypt a message you use part thereof as your current message. If you both have a copy of the Pad, and the Pad has never been transmitted electronically, you are safe.
You may vary ofcourse; perhaps you feel "safe enough" by protecting the Pad with a PkZip password and sending it using SSL to your own server. I'd always recommend not to transmit it at all; someone can carry a USB stick and deliver it in a day - and you'd instantly have a Pad that is several Gb big.
So, on to the easy code example. First we need code to generate random data that we will use as a Pad.
public static byte[] GeneratePad(int size, int seed)
{
var random = new Random(Seed: seed);
var bytesBuffel = new byte[size];
random.NextBytes(bytesBuffel);
return bytesBuffel;
}
That's nice and easy, isn't it? Now comes the hard part, implementing an unbreakable encryption algo. The example on wikipedia uses only a subset of printable characters. I was thinking about using the entire byte.
public static byte[] Encrypt(byte[] data, byte[] pad)
{
var result = new byte[data.Length];
for (int i = 0; i < data.Length; i++)
{
var sum = (int)data[i] + (int)pad[i];
if (sum > 255)
sum -= 255;
result[i] = (byte)sum;
}
return result;
}
And the counterpart, which is as complex as the previous example. Seriously, try not to laugh as we look at the method that subtracts the noise we added to our data;
public static byte[] Decrypt(byte[] encrypted, byte[] pad)
{
var result = new byte[encrypted.Length];
for (int i = 0; i < encrypted.Length; i++)
{
var dif = (int)encrypted[i] - (int)pad[i];
if (dif < 0)
dif += 255;
result[i] = (byte)dif;
}
return result;
}
Yes, using those three methods is equally simple.
byte[] originalBytes = Encoding.Unicode.GetBytes(textBoxOriginal.Text);
byte[] pad = PadGenerator.GeneratePad(size: originalBytes.Length, seed: 1);
textBoxPad.Text = Convert.ToBase64String(inArray: pad);
byte[] encrypted = PadGenerator.Encrypt(originalBytes, pad);
textBoxEncrypted.Text = Convert.ToBase64String(inArray: encrypted);
byte[] encryptedFromBase64 = Convert.FromBase64String(textBoxEncrypted.Text);
byte[] decrypted = PadGenerator.Decrypt(encryptedFromBase64, pad);
textBoxDecrypted.Text = Encoding.Unicode.GetString(decrypted);
That's it, as they say.
Points of Interest
This works best for IM/Email messages, in places where you can transmit your key physically and protect it. With the current number of bytes you can store for a dollar, there's no reason not to generate a pad. Once both locations share their secret key (and do NOT reuse it) one can talk in private.
I've decided to share the interesting part of the project, instead of an entire solution that can be run directly. The latter would be more popular, but by sharing the idea and not the project there will be multiple implementations. Each with its own weird quircks.
If you do, then forget about the base64-conversions in this example; they're only there for me to make it easy with copy/pasting and testing. It's a nice way of displaying data that may contain non-printable characters. If you want to be really fancy, you use a hex-viewer to show those bytes :)
History
- September 15th, 2017 - initial draft.
<!--
"X-Clacks-Overhead" content="GNU Terry Pratchett"
-->