I am at it again just a little bit. I have a mild interest in encryption. Every so often I will do some random reading about this algorithm or that one. The thing that really gets me is human error. If somebody sends a text message encrypted with a single XOR number, then major human error. Hack the human, not the machine.
How to go about eliminating my human error? Write my own encryption software and keep my mouth shut. Add lots of red herring and salt. That last statement includes having several encryption methods on my harddrive and way tons of data to hide keys in. Even throw in a few false key vaults. Are you sure I used that particular file stream and XOR? Oh, you found a sequence of numbers and you know for a fact that it is the key... but how did I use it? Appealling to my ego won't give you any clues. And neither will checking last access times on the files in my key vaults. Oh, see the funny b64 characters in the meta data of those images? Did I use them or just toss them in there to look suspicious? Why is there a horizontal strip of noise across the top of that bitmap? Real or salted herring?
Never actually wrote my own encrytion software until recently. I now have a laptop with Linux Mint and a copy of Learning Python by Mark Lutz. Seems like a good as time as any. Serendipity at its finest. Not too much of this reflects Python; rather, algorithm notes.
My first stop was creating data sets that can be used for keys. Good starting exercise to learn about data types and data manipulation in Python. And some fileI/O. So, what kind of data sets? I eventually settled on shuffled sequences of (0...255). Seems to be the most versatile. Chain them together or whatever.
One of the more interesting things about shuffled (0...255) is that 149+107=256. Know that 149 and 107 are both prime numbers. This means that a shuffled sequence of (0...255) can be turned into a key that repeats every 149x107x2=31886. Not bad at all.
The real fun part was creating a huge data set. Open a new file named 0x00.raw, dump 256 sets of shuffled, next one named 0x01.raw, dump another 256 sets of shuffled, and so on to 0xff.raw. More than enough data to pick from and way too much for anyone to try to sift through (brute force). The possible starting combinations for a single shuffled set is 256x256=65536. And it just gets bigger from there.
With this huge key vault, I decided to try Enigma. Three plates with counting offsets and a reflector. Each plate is 256 to the 3rd (file, row, offset) and the reflector is 256 to the 2nd (file, row). Three plates plus reflector means pow(256,11) starting positions. Approximately 3.09x10^26 (I know that ^ means XOR, but I'm going back to old school BASIC).
In writing all of this down in text, my style of pseudo-code is all over the place. Pseudo-elements of this, that, and the other. Be glad I haven't learned much of LISP yet.
Now, I did get it all working just fine. Encrypted a few binary files. So far, I'm not sure if I should be impressed or depressed with the speed. A 200k file takes around 12 seconds. It could be because this laptop is 10 years old or because Python is scripted. No idea how this kind of speed compares to other algorithms and machines. Also, I'm not entirely sure how strong all of this is. While I am confident that it will keep my secrets sans human error, I have zero real-world experience (under a rock).
What's to follow are the basics steps. Cobble it together your way. (Maybe one of these days I'll edit together a hard-coded Python script.)
Shuffling a Sequence
Start with t(0...255)
To shuffle, use byte stream of any kind. I just opened up a random mp3 file and read from that. (My actual working method is a little more complex than that, but that is the basic idea.)
for i = 0 to len(rfile)
We now have a shuffled sequence from 0 to 255, each index being unique.
Why did I use an mp3 file? Because I have a way ton available and the shear size of the mp3 file should be way more than enough shuffling. Plus there is the problem of access. That is, no access to a speedy TRNG or Random.org or anything like that. Stictly a case of using what I have available and an oddball method most people wouldn't suspect.
Symmetric Look-Up Table
To make a sysmetric table from the shuffled sequence, we now take them in pairs.
The pairs in S() look like:
I'll leave the interation up to you, but something like this:
a=S(0) # S(i)
b=S(1) # S(i+1)
S() is now a symmetric look-up table.
Make it Relative
This is the logic bomb that really threw me for a loop. Symmetric tables are good, but adding an offset breaks the symmetry. How do you mantain symmetry with an offset? Turns out that the answer is in making it relative.
Again, the inter is up to you:
If all goes well, you should get:
There you go. With some variable savvy, you can now stack the tables. Jump back-n-forth or up-n-down. Throw in some starting positions, some file I/O, and encrypt/decrypt to your heart's content - symmetry and all.
Now, when you get to using offsets and having to wrap-around, use %255 (modulo) or &255 (AND).
getval=(index+offset)&255 /** or gv=(index+offset)%255 **/
Yes, using & or % got me for a bit because I don't normally use bitwise for wrapping. Using if/then for wrapping is a readability habit from back in the day. Why even include this little blurb? I mean, isn't this one of those things that most programmers know about and can handle without having to be explicitly told? I am including it because I find humour in it. A veteran programmer having a scuffle with & && %. Now that's funny.
(Edited by warjournal on 06-06-2015 00:17)