Hi there.
In my never-ending quest for knowledge, I've decided to implement a (very) simple and (very) weak encryption algorithm, to teach myself the extreme basics of cryptography. What I decided to do is this:
Take a byte array, which could represent a file, or user input, or whatever, and XOR each byte with a byte from an encryption key provided by the user.
This produces a garbled set of bits that represent the encrypted message. This also has the (dis)advantage that decryption is the same process as encryption, since XOR is symmetric. So in order to decrypt an encrypted message, you simply supply the same encryption key, and re-encrypt it. This is the code:
public static byte[] encryptOrDecrypt(byte[] key, byte[] data)
{
byte[] digest = new byte[data.length];
for (int i = 0; i < data.length; i++)
digest[i] = new Integer(key[i % key.length] ^ data).byteValue();
// wipe the arrays for security.
Arrays.fill(key, (byte) 0x00);
Arrays.fill(data, (byte) 0x00);
return digest;
}Note also that I am blanking the key and data arrays so they do not remain in memory. Perhaps overkill for such a simple encryption, but it seems like a good habit to get into.
Now that works just fine; the encryption and decryption produce the proper output. However, I would like the encryption and decryption processes to be different, so that if the user wanted to double-encrypt a file, it wouldn't produce just a decrypted file as output. My idea was this:
First encrypt with a static array of nothing-up-my-sleeve bytes (which I called a Rubicon), then encrypt with the user's encryption key.
Thus to decrypt, just decrypt with the user's encryption key, then with the Rubicon.
private static byte[] RUBICON = {0x08, 0x29, 0x3A, 0x4B, 0x5C, 0x6D, 0x7E, 0x0F};
public static byte[] encrypt(byte[] key, byte[] data)
{
byte[] digest = new byte[data.length];
for (int i = 0; i < data.length; i++)
digest[i] = new Integer(RUBICON[i % RUBICON.length] ^ data[i]).byteValue();
for (int i = 0; i < data.length; i++)
digest[i] = new Integer(key[i % key.length] ^ digest[i]).byteValue();
// wipe the arrays for security.
Arrays.fill(key, (byte) 0x00);
Arrays.fill(data, (byte) 0x00);
return digest;
}
// and the decrypt method would work in the reverse
I thought I was being pretty clever. Turns out that because of the symmetry of XOR, it doesn't matter whether you use the Rubicon or user's key first, you'll get the same output.
I am trying to think of a way that is simpler than RSA-level algorithms, but more realistically secure than a Caesar cipher (example: shifting 1 byte right on encryption, then 1 byte left on decryption is way too simple). Any ideas for methods to differentiate between encryption and decryption, while staying simple but not too simple?