Introduction
As the name suggests, a 'keyless' cipher is a cipher where the user does not
need to provide a key to encrypt or decrypt a piece of text. The key, if there
is one, is implicit from the algorithm used.
This means, of course, that you don't have to worry about how or where to store
the key or key file for your encryption system. However, keyless systems are not
usually secure due to the nature of the algorithms used.
ROT13
This is perhaps the best known keyless cipher. Every letter in the plain text is
rotated by 13 places in the alphabet. When 'Z' is reached, the cipher wraps
around to 'A' so it's really just a simple substitution cipher:
Text |
A |
B |
C |
D |
E |
F |
G |
H |
I |
J |
K |
L |
M |
N |
O |
P |
Q |
R |
S |
T |
U |
V |
W |
X |
Y |
Z |
Code |
N |
O |
P |
Q |
R |
S |
T |
U |
V |
W |
X |
Y |
Z |
A |
B |
C |
D |
E |
F |
G |
H |
I |
J |
K |
L |
M |
Only upper and lower case letters are rotated in this way. All other characters
(include spaces) remain unaltered.
So C# Corner in ROT13 would be : P# Pbeare.
An interesting property of ROT13 is that you can apply the same method for both
encryption and decryption.
Although it's used for various purposes on the Internet, ROT13 has no
pretensions to being secure. If you know that something has been encrypted using
ROT13, then there are several online utilities available which can recover the
plain text and, even if you don't, then it's easily defeated using frequency
analysis.
There is a variation known as ROT5 which can be used for encrypting the numerals
0 to 9 by rotating them 5 places to the right and wrapping around to 0 when 9 is
reached. This can also be used in conjunction with ROT13 to encrypt alphanumeric
text.
ROT47
ROT47 is a keyless cipher based on the same principles as ROT13 which encrypts
all the printable ASCII characters (excluding spaces) between codepoints 33
(exclamation mark) and 126 (tilde), a range of 94 characters, by rotating them
47 places to the right and wrapping around to character 33 when character 126 is
reached.
So C# Corner in ROT47 would be: rR r@C?6C.
As in the case of ROT13, you can apply the same method for both encryption and
decryption and, although the encryption is more thorough, it can still be
defeated using frequency analysis.
Also it can be more error-prone to write down the cipher text than ROT13 because
of the use of symbols as well as letters and numerals.
ROT1035
You won't find this one in the text books as it's my own variation of ROT13.
It differs from it in that the consonants are rotated separately (by 10 places)
from the vowels (by 3 places). The vowels for this purpose include 'Y'. The
numerals are also rotated 5 places, as in ROT5.
So C# Corner in ROT1035 would be : P# Pafbuf.
As each word of the cipher text will include as many vowels as it did in the
first place, the result is something that looks like it could be an obscure
foreign language rather than encrypted text.
Also, if any one attempts to decrypt it using ROT13, the result is gibberish.
You can still apply the same method for both encryption and decryption but it is
just as susceptible to defeat by frequency analysis as the other ROT variants.
ROTA
So is there anything we can do to make ROT1035 more secure?
The problem at the moment is that the various categories of character are always
rotated by the same number of places. Suppose we were to make the number of
places to rotate (or 'offsets') variable depending on the index of the character
in the string and not just in a predictable way but in a more random fashion.
Suppose also that the starting point within this sequence of offsets were made
variable as well depending on the total number of characters in the string.
The result is an encryption scheme I've called ROTA which is much harder to
crack than the other ROT variants though at the expense of requiring different
methods for encryption and decryption.
C# Corner in ROTA would be : J# Bitgiv.
The encrypted text has similar properties to ROT1035 except that repeated words
are (usually) encrypted differently which makes attacks using frequency analysis
much more difficult.
The sequence of 'offsets' for letters was found by using the perfect pangram,
junky qoph-flags vext crwd zimb (see http://en.wikipedia.org/wiki/List_of_pangrams
) and converting the letters to their consonant or vowel numbers in the alphabet
which gives reasonably random results. The sequence for numerals uses the
letters 'a' to 'j' from this pangram. Other pangrams or approaches could, of
course, be used to generate these sequences.
Arguably, it would have been more secure to recombine the vowels and consonants
into a single sequence (as in ROT13) so as not to offer a possible 'way in' by
studying the vowels in single letter or other short words but I decided against
this.
Source Code
I've coded a method for each of these variants (ROTA uses a static class with
two methods) so we can compare the output. The following program is also
available as a download:
using
System;
class
Program
{
static void
Main()
{
string[] s =
new string[2];
s[0] = "The Quick Brown Fox Jumps Over The
Lazy Dog 2012"; // Dog
s[1] = "The
Quick Brown Fox Jumps Over The Lazy Dogs 2012";
// now Dogs
for (int
i = 0; i < 2; i++)
{
Console.WriteLine("Using
ROT13\n");
string t = ROT13(s[i]);
Console.WriteLine(t);
Console.WriteLine(ROT13(t));
Console.WriteLine("\nUsing
ROT47\n");
string u = ROT47(s[i]);
Console.WriteLine(u);
Console.WriteLine(ROT47(u));
Console.WriteLine("\nUsing
ROT1035\n");
string v = ROT1035(s[i]);
Console.WriteLine(v);
Console.WriteLine(ROT1035(v));
Console.WriteLine("\nUsing
ROTA\n");
string w =
ROTA.Encrypt(s[i]);
Console.WriteLine(w);
Console.WriteLine(ROTA.Decrypt(w));
Console.WriteLine("\n"
+ new string('-',
s[i].Length) + "\n");
}
Console.ReadKey();
}
static string
ROT13(string s)
{
if (String.IsNullOrEmpty(s))
return s;
char[] ca = new
char[s.Length];
for (int
i = 0; i < s.Length; i++)
{
char c = s[i];
if (c >= 97 && c <= 122)
{
int j = c + 13;
if (j > 122) j -= 26;
ca[i] = (char)j;
}
else if
(c >= 65 && c <= 90)
{
int j = c + 13;
if (j > 90) j -= 26;
ca[i] = (char)j;
}
else
{
ca[i] = c;
}
}
return new
string(ca);
}
static string
ROT47(string s)
{
if (String.IsNullOrEmpty(s))
return s;
char[] ca = new
char[s.Length];
for (int i = 0;
i < s.Length; i++)
{
char c = s[i];
if (c >= 33 && c <= 126)
{
int j = c + 47;
if (j > 126) j -= 94;
ca[i] = (char)j;
}
else
{
ca[i] = c;
}
}
return new
string(ca);
}
static string
ROT1035(string s)
{
if (String.IsNullOrEmpty(s))
return s;
string consonants =
"bcdfghjklmnpqrstvwxz";
string vowels =
"aeiouy";
char[] ca = new
char[s.Length];
for (int
i = 0; i < s.Length; i++)
{
char c = s[i];
int j;
if ((j = vowels.IndexOf(c)) > -1)
{
j += 3;
if (j > 5) j -= 6;
ca[i] = vowels[j];
}
else if
((j = consonants.IndexOf(c)) > -1)
{
j += 10;
if (j > 19) j -= 20;
ca[i] = consonants[j];
}
else if
((j = vowels.ToUpper().IndexOf(c)) > -1)
{
j += 3;
if (j > 5) j -= 6;
ca[i] = vowels.ToUpper()[j];
}
else if
((j = consonants.ToUpper().IndexOf(c)) > -1)
{
j += 10;
if (j > 19) j -= 20;
ca[i] = consonants.ToUpper()[j];
}
else if
(c >= 48 && c <= 57)
{
j = c + 5;
if (j > 57) j -= 10;
ca[i] = (char)j;
}
else
{
ca[i] = c;
}
}
return new
string(ca);
}
}
static
class
ROTA
{
static int[]
keyC = { 7, 11, 8, 13, 12, 6, 4, 9, 5, 15, 17, 19, 16, 2, 14, 18, 3, 20, 10, 1
};
static int[]
keyV = { 5, 6, 4, 1, 2, 3 };
static int[]
keyN = { 10, 8, 6, 1, 7, 5, 3, 4, 9, 2 };
static string
consonants = "bcdfghjklmnpqrstvwxz";
static string
vowels = "aeiouy";
public static
string Encrypt(string
s)
{
if (String.IsNullOrEmpty(s))
return s;
int lenC = (s.Length - 1) % 20;
int lenV = (s.Length - 1) % 6;
int lenN = (s.Length - 1) % 10;
char[] ca = new
char[s.Length];
for (int
i = 0; i < s.Length; i++)
{
char c = s[i];
int j;
if ((j = vowels.IndexOf(c)) > -1)
{
j += keyV[(i + lenV) % 6];
if (j > 5) j -= 6;
ca[i] = vowels[j];
}
else if
((j = consonants.IndexOf(c)) > -1)
{
j += keyC[(i + lenC) % 20];
if (j > 19) j -= 20;
ca[i] = consonants[j];
}
else if
((j = vowels.ToUpper().IndexOf(c)) > -1)
{
j += keyV[(i + lenV) % 6];
if (j > 5) j -= 6;
ca[i] = vowels.ToUpper()[j];
}
else if
((j = consonants.ToUpper().IndexOf(c)) > -1)
{
j += keyC[(i + lenC) % 20];
if (j > 19) j -= 20;
ca[i] = consonants.ToUpper()[j];
}
else if
(c >= 48 && c <= 57)
{
j = c + keyN[(i + lenN) % 10];
if (j > 57) j -= 10;
ca[i] = (char)j;
}
else
{
ca[i] = c;
}
}
return new
string(ca);
}
public static
string Decrypt(string
s)
{
if (String.IsNullOrEmpty(s))
return s;
int lenC = (s.Length - 1) % 20;
int lenV = (s.Length - 1) % 6;
int lenN = (s.Length - 1) % 10;
char[] ca = new
char[s.Length];
for (int
i = 0; i < s.Length; i++)
{
char c = s[i];
int j;
if ((j = vowels.IndexOf(c)) > -1)
{
j -= keyV[(i + lenV) % 6];
if (j < 0) j += 6;
ca[i] = vowels[j];
}
else if
((j = consonants.IndexOf(c)) > -1)
{
j -= keyC[(i + lenC) % 20];
if (j < 0) j += 20;
ca[i] = consonants[j];
}
else if
((j = vowels.ToUpper().IndexOf(c)) > -1)
{
j -= keyV[(i + lenV) % 6];
if (j < 0) j += 6;
ca[i] = vowels.ToUpper()[j];
}
else if
((j = consonants.ToUpper().IndexOf(c)) > -1)
{
j -= keyC[(i + lenC) % 20];
if (j < 0) j += 20;
ca[i] = consonants.ToUpper()[j];
}
else if
(c >= 48 && c <= 57)
{
j = c - keyN[(i + lenN) % 10];
if (j < 48) j += 10;
ca[i] = (char)j;
}
else
{
ca[i] = c;
}
}
return new
string(ca);
}
}
Results
The following is a screen-shot of the output from this program:
Notice that the second "the" is encoded differently in ROTA but not in the other
variants.
Notice also that changing "Dog" to "Dogs" only changes the encrypted version of
that particular word when using the first three variants. However, when using
ROTA it changes the whole sentence!
Conclusion
It's therefore clear that ROTA is much more secure than the other ROT variants.
However, it's still not cryptographically strong by modern standards - an expert
would have no trouble deciphering it.
It could be made stronger by adding other refinements such as changing the
spacing between words but I didn't think that this would be worthwhile.
The important thing is to produce a keyless cipher which is quick and easy to
use and could be used (for example) to encrypt string literals or small files
and so protect them from casual inspection. I believe that ROTA already achieves
this limited aim.