Skip to content

Instantly share code, notes, and snippets.

@jonathanedgecombe
Last active December 23, 2015 09:39
Show Gist options
  • Save jonathanedgecombe/6616264 to your computer and use it in GitHub Desktop.
Save jonathanedgecombe/6616264 to your computer and use it in GitHub Desktop.
EBC (Block Cipher) Implementation
package com.jonathanedgecombe.security;
import java.security.InvalidKeyException;
import java.security.InvalidParameterException;
import javax.crypto.IllegalBlockSizeException;
/**
* EBC (Edgecombe Block Cipher)
* A block cipher making use of substitution, permutation and modular arithmetic.
* @author Jonathan Edgecombe
*/
public final class EBC {
/**
* Constant hard-coded 1-to-1 substitution table for encrypting.
*/
private final static byte[] SUBSTITUTION_TABLE_ENCRYPT = new byte[] {
0x76, 0x79, 0x70, -0x3A, -0x13, 0x5B, -0x1E, -0x6A, 0x54, -0x31, -0x34, -0x5D, -0x18, 0x29, -0x04, -0x48,
0x6B, 0x3E, -0x40, 0x36, 0x23, 0x1A, 0x19, -0x44, 0x78, 0x5A, -0x6B, 0x60, -0x6F, 0x32, -0x60, -0x4E,
-0x4F, 0x46, 0x48, 0x33, -0x0E, 0x14, -0x05, -0x65, 0x62, 0x7F, -0x5F, 0x5D, -0x02, 0x45, -0x57, 0x2D,
0x4B, -0x3B, -0x01, 0x5E, 0x17, 0x69, 0x44, -0x27, 0x1C, 0x55, -0x80, -0x62, 0x74, -0x50, 0x4C, -0x72,
0x00, -0x06, 0x1B, 0x24, -0x2F, 0x6A, -0x7B, 0x35, 0x07, -0x66, -0x0F, 0x03, 0x2F, -0x55, 0x4A, 0x3A,
0x15, 0x16, -0x32, 0x59, 0x34, 0x0D, 0x30, 0x75, -0x20, -0x47, -0x42, 0x37, 0x77, -0x52, 0x58, 0x51,
0x1D, -0x4A, -0x74, 0x49, 0x26, -0x1F, 0x3B, 0x38, -0x37, -0x1C, -0x69, -0x0A, -0x21, 0x08, -0x0B, -0x38,
-0x10, -0x5E, 0x61, 0x28, -0x56, -0x79, 0x1E, -0x15, 0x64, 0x71, -0x17, -0x70, 0x20, 0x50, 0x6E, 0x02,
-0x16, 0x27, -0x1A, -0x54, -0x7A, 0x53, -0x19, -0x7F, -0x71, 0x3C, -0x2C, -0x2B, 0x31, -0x11, 0x22, -0x3F,
-0x77, 0x09, 0x6F, -0x63, 0x0A, 0x18, 0x6C, 0x4E, -0x7D, -0x1B, -0x39, 0x6D, -0x6D, -0x6C, -0x2E, -0x67,
0x05, 0x7D, -0x75, -0x78, 0x3D, -0x12, -0x6E, 0x2E, -0x53, -0x36, 0x13, 0x7C, -0x45, -0x24, 0x01, -0x5B,
0x41, -0x76, 0x42, 0x52, 0x10, 0x66, -0x35, -0x1D, -0x30, -0x26, -0x4B, -0x49, -0x7E, -0x25, 0x06, -0x09,
0x73, 0x7A, -0x29, 0x7B, -0x22, 0x0B, -0x46, 0x40, -0x4D, -0x33, 0x25, -0x3D, 0x12, -0x28, 0x1F, -0x43,
0x67, -0x3C, 0x43, -0x2A, -0x3E, -0x59, -0x7C, -0x68, -0x2D, -0x5C, 0x3F, -0x0D, 0x7E, -0x51, 0x2C, 0x0F,
-0x4C, -0x41, -0x61, 0x68, -0x03, -0x73, 0x5C, -0x0C, 0x2B, -0x64, -0x23, 0x0C, 0x5F, 0x57, -0x08, -0x58,
0x04, 0x4D, 0x4F, -0x07, 0x63, -0x14, 0x56, 0x65, 0x72, 0x21, 0x47, 0x0E, 0x11, 0x39, 0x2A, -0x5A
};
/**
* Constant hard-coded 1-to-1 substitution table for decrypting.
*/
private final static byte[] SUBSTITUTION_TABLE_DECRYPT = new byte[] {
0x40, -0x52, 0x7F, 0x4B, -0x10, -0x60, -0x42, 0x48, 0x6D, -0x6F, -0x6C, -0x3B, -0x15, 0x55, -0x05, -0x21,
-0x4C, -0x04, -0x34, -0x56, 0x25, 0x50, 0x51, 0x34, -0x6B, 0x16, 0x15, 0x42, 0x38, 0x60, 0x76, -0x32,
0x7C, -0x07, -0x72, 0x14, 0x43, -0x36, 0x64, -0x7F, 0x73, 0x0D, -0x02, -0x18, -0x22, 0x2F, -0x59, 0x4C,
0x56, -0x74, 0x1D, 0x23, 0x54, 0x47, 0x13, 0x5B, 0x67, -0x03, 0x4F, 0x66, -0x77, -0x5C, 0x11, -0x26,
-0x39, -0x50, -0x4E, -0x2E, 0x36, 0x2D, 0x21, -0x06, 0x22, 0x63, 0x4E, 0x30, 0x3E, -0x0F, -0x69, -0x0E,
0x7D, 0x5F, -0x4D, -0x7B, 0x08, 0x39, -0x0A, -0x13, 0x5E, 0x53, 0x19, 0x05, -0x1A, 0x2B, 0x33, -0x14,
0x1B, 0x72, 0x28, -0x0C, 0x78, -0x09, -0x4B, -0x30, -0x1D, 0x35, 0x45, 0x10, -0x6A, -0x65, 0x7E, -0x6E,
0x02, 0x79, -0x08, -0x40, 0x3C, 0x57, 0x00, 0x5C, 0x18, 0x01, -0x3F, -0x3D, -0x55, -0x5F, -0x24, 0x29,
0x3A, -0x79, -0x44, -0x68, -0x2A, 0x46, -0x7C, 0x75, -0x5D, -0x70, -0x4F, -0x5E, 0x62, -0x1B, 0x3F, -0x78,
0x7B, 0x1C, -0x5A, -0x64, -0x63, 0x1A, 0x07, 0x6A, -0x29, -0x61, 0x49, 0x27, -0x17, -0x6D, 0x3B, -0x1E,
0x1E, 0x2A, 0x71, 0x0B, -0x27, -0x51, -0x01, -0x2B, -0x11, 0x2E, 0x74, 0x4D, -0x7D, -0x58, 0x5D, -0x23,
0x3D, 0x20, 0x1F, -0x38, -0x20, -0x46, 0x61, -0x45, 0x0F, 0x59, -0x3A, -0x54, 0x17, -0x31, 0x5A, -0x1F,
0x12, -0x71, -0x2C, -0x35, -0x2F, 0x31, 0x03, -0x66, 0x6F, 0x68, -0x57, -0x4A, 0x0A, -0x37, 0x52, 0x09,
-0x48, 0x44, -0x62, -0x28, -0x76, -0x75, -0x2D, -0x3E, -0x33, 0x37, -0x47, -0x43, -0x53, -0x16, -0x3C, 0x6C,
0x58, 0x65, 0x06, -0x49, 0x69, -0x67, -0x7E, -0x7A, 0x0C, 0x7A, -0x80, 0x77, -0x0B, 0x04, -0x5B, -0x73,
0x70, 0x4A, 0x24, -0x25, -0x19, 0x6E, 0x6B, -0x41, -0x12, -0x0D, 0x41, 0x26, 0x0E, -0x1C, 0x2C, 0x32
};
/**
* The number of rounds to apply when encrypting or decrypting a block.
*/
private final int rounds;
/**
* The key to use when encrypting or decrypting a block.
*/
private final byte[] key;
/**
* Create a new block cipher with the specified key and number of rounds.
* @param key The key for the cipher to use.
* @param rounds The rounds of encryption to use (minimum of 4).
* @throws InvalidKeyException If the key is not valid (non-zero length and multiple of 16 bytes [128 bits] length).
*/
public EBC(byte[] key, int rounds) throws InvalidKeyException {
if (!checkKey(key)) throw new InvalidKeyException("Key must be non-zero and a multiple of 16 bytes (128 bits) in length");
if (rounds < 4) throw new InvalidParameterException("Rounds must be greater than or equal to 4.");
this.rounds = rounds;
this.key = key;
}
/**
* Create a new block cipher with the specified key and default (8) number of rounds.
* @param key The key for the cipher to use.
* @throws InvalidKeyException If the key is not valid (non-zero length and multiple of 16 bytes [128 bits] length).
*/
public EBC(byte[] key) throws InvalidKeyException {
this(key, 8);
}
/**
* Encrypt a block of data.
* @param block The block to encrypt.
* @return The encrypted data.
* @throws IllegalBlockSizeException If the block size is not 16 bytes (128 bits).
*/
public byte[] encrypt(byte[] block) throws IllegalBlockSizeException {
if (block.length != 16) throw new IllegalBlockSizeException("Only block sizes of 16 bytes (128 bits) are permitted");
byte[] data1 = new byte[8];
byte[] data2 = new byte[8];
for (int i = 0; i < 8; i++) {
data1[i] = block[i];
data2[i] = block[8 + i];
}
for (int round = 0; round < rounds; round++) {
data1 = xor(encryptRound(data1, key), data2);
data2 = xor(encryptRound(data2, key), data1);
}
byte[] out = new byte[16];
for (int i = 0; i < 8; i++) {
out[i] = data1[i];
out[8 + i] = data2[i];
}
return out;
}
/**
* Decrypt a block of data.
* @param block The block to decrypt.
* @return The decrypted data.
* @throws IllegalBlockSizeException If the block size is not 16 bytes (128 bits).
*/
public byte[] decrypt(byte[] block) throws IllegalBlockSizeException {
if (block.length != 16) throw new IllegalBlockSizeException("Only block sizes of 16 bytes (128 bits) are permitted");
byte[] data1 = new byte[8];
byte[] data2 = new byte[8];
for (int i = 0; i < 8; i++) {
data1[i] = block[i];
data2[i] = block[8 + i];
}
for (int round = 0; round < rounds; round++) {
data2 = decryptRound(xor(data2, data1), key);
data1 = decryptRound(xor(data1, data2), key);
}
byte[] out = new byte[16];
for (int i = 0; i < 8; i++) {
out[i] = data1[i];
out[8 + i] = data2[i];
}
return out;
}
/**
* XOR two byte arrays together sequentially.
* @param a Byte array a.
* @param b Byte array b.
* @return XOR of a and b.
*/
private static byte[] xor(byte[] a, byte[] b) {
byte[] out = new byte[8];
for (int i = 0; i < 8; i++) {
out[i] = (byte) (a[i] ^ b[i]);
}
return out;
}
/**
* Checks if a key is valid (non-zero length and multiple of 128 bits length).
* @param key The key to check.
* @return If the key is valid or not.
*/
private static boolean checkKey(byte[] key) {
if (key.length == 0) return false;
if (key.length%16 != 0) return false;
return true;
}
/**
* Key sheduler. Makes use of the substitution and permutation ciphers.
* @param key The key to use.
* @param keyRound The round of the sub key.
* @return The sub key generated.
*/
private static byte[] getSubKey(byte[] key, int keyRound) {
byte[] out = new byte[8];
for (int i = 0; i < 8; i++) {
out[i] = key[keyRound*8 + i];
}
out = substituteEncrypt(out);
out = permutateEncrypt(out);
return out;
}
/**
* A method for one round of encryption on data.
* @param data The data to encrypt.
* @param key The key to use.
* @return The encrypted data.
*/
private static byte[] encryptRound(byte[] data, byte[] key) {
byte[] out = new byte[8];
for (int i = 0; i < key.length/16; i++) {
// Substitution
out = substituteEncrypt(data);
// Permutation
out = permutateEncrypt(out);
// Key arithmetic
out = addKeyEncrypt(out, getSubKey(key, i*2));
out = xorKeyEncrypt(out, getSubKey(key, i*2 + 1));
}
return out;
}
/**
* A method for one round of decryption on data.
* @param data The data to decrypt.
* @param key The key to use.
* @return The decrypted data.
*/
private static byte[] decryptRound(byte[] data, byte[] key) {
byte[] out = new byte[8];
for (int i = 0; i < 8; i++) {
out[i] = data[i];
}
for (int i = 0; i < key.length/16; i++) {
// Key arithmetic
out = xorKeyEncrypt(out, getSubKey(key, i*2 + 1));
out = subKeyEncrypt(out, getSubKey(key, i*2));
// Permutation
out = permutateDecrypt(out);
// Substitution
out = substituteDecrypt(out);
}
return out;
}
/**
* Applies the sub key to the block using a bitwise XOR.
* @param data The data to encrypt.
* @param subKey The sub key to use.
* @return The encrypted data.
*/
private static byte[] xorKeyEncrypt(byte[] data, byte[] subKey) {
byte[] out = new byte[8];
for (int i = 0; i < 8; i++) {
out[i] = (byte) (data[i] ^ subKey[i]);
}
return out;
}
/**
* Applies the sub key to the block using a bytewise add.
* @param data The data to encrypt.
* @param subKey The sub key to use.
* @return The encrypted data.
*/
private static byte[] addKeyEncrypt(byte[] data, byte[] subKey) {
byte[] out = new byte[8];
for (int i = 0; i < 8; i++) {
out[i] = (byte) (data[i] + subKey[i]);
}
return out;
}
/**
* Applies the sub key to the block using a bytewise subtract.
* @param data The data to encrypt.
* @param subKey The sub key to use.
* @return The encrypted data.
*/
private static byte[] subKeyEncrypt(byte[] data, byte[] subKey) {
byte[] out = new byte[8];
for (int i = 0; i < 8; i++) {
out[i] = (byte) (data[i] - subKey[i]);
}
return out;
}
/**
* Applies a substitution encryption to the block.
* @param data The data to substitute.
* @return The substituted data.
*/
private static byte[] substituteEncrypt(byte[] data) {
byte[] out = new byte[8];
for (int i = 0; i < 8; i++) {
out[i] = SUBSTITUTION_TABLE_ENCRYPT[data[i] & 0xFF];
}
return out;
}
/**
* Applies a substitution decryption to the block.
* @param data The data to decrypt.
* @return The decrypted data.
*/
private static byte[] substituteDecrypt(byte[] data) {
byte[] out = new byte[8];
for (int i = 0; i < 8; i++) {
out[i] = SUBSTITUTION_TABLE_DECRYPT[data[i] & 0xFF];
}
return out;
}
/**
* Applies a permutation encryption to the block.
* @param data The data to permutate.
* @return The permutated data.
*/
private static byte[] permutateEncrypt(byte[] data) {
byte[] out = new byte[8];
out[0] = (byte) (data[1] ^ data[2] ^ data[3] ^ data[4] ^ data[5] ^ data[6] ^ data[7]);
out[1] = (byte) (data[0] ^ data[2] ^ data[3] ^ data[4] ^ data[5] ^ data[6] ^ data[7]);
out[2] = (byte) (data[0] ^ data[1] ^ data[3] ^ data[4] ^ data[5] ^ data[6] ^ data[7]);
out[3] = (byte) (data[0] ^ data[1] ^ data[2] ^ data[4] ^ data[5] ^ data[6] ^ data[7]);
out[4] = (byte) (data[0] ^ data[1] ^ data[2] ^ data[3] ^ data[5] ^ data[6] ^ data[7]);
out[5] = (byte) (data[0] ^ data[1] ^ data[2] ^ data[3] ^ data[4] ^ data[6] ^ data[7]);
out[6] = (byte) (data[0] ^ data[1] ^ data[2] ^ data[3] ^ data[4] ^ data[5] ^ data[7]);
out[7] = (byte) (data[0] + out[0] + out[1] + out[2] + out[3] + out[4] + out[5] + out[6]);
return out;
}
/**
* Applies a permutation decryption to the block.
* @param data The data to decrypt.
* @return The decrypted data.
*/
private static byte[] permutateDecrypt(byte[] data) {
byte[] out = new byte[8];
out[0] = (byte) (data[7] - data[0] - data[1] - data[2] - data[3] - data[4] - data[5] - data[6]);
out[1] = (byte) (data[0] ^ data[1] ^ out[0]);
out[2] = (byte) (data[1] ^ data[2] ^ out[1]);
out[3] = (byte) (data[2] ^ data[3] ^ out[2]);
out[4] = (byte) (data[3] ^ data[4] ^ out[3]);
out[5] = (byte) (data[4] ^ data[5] ^ out[4]);
out[6] = (byte) (data[5] ^ data[6] ^ out[5]);
out[7] = (byte) (out[1] ^ out[2] ^ out[3] ^ out[4] ^ out[5] ^ out[6] ^ data[0]);
return out;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment