Skip to content

Instantly share code, notes, and snippets.

@hakatashi
Created October 23, 2014 06:06
Show Gist options
  • Select an option

  • Save hakatashi/3d3351cec8c509d5097c to your computer and use it in GitHub Desktop.

Select an option

Save hakatashi/3d3351cec8c509d5097c to your computer and use it in GitHub Desktop.
import java.util.Arrays;
import edu.rit.util.Hex;
import edu.rit.util.Packing;
public class FEALCipher implements BlockCipher {
//Set up parameters and default values
public int R = 8;
byte deltaParam = 0;
int numOfSubKeys = (this.R + 8);
short[] subKey = new short[numOfSubKeys];
//Returns the block size of FEAL in bytes
public int blockSize() {
return 8;
}
//Returns the key size in Bytes
public int keySize() {
return 8;
}
//Function to set the number of rounds. This is used in our attack
//It also sets up the appropriate number of subkeys which need to be generated
public void setRounds(int R) {
this.R = R;
this.numOfSubKeys = (this.R + 8);
this.subKey = new short[numOfSubKeys];
}
//Method to access the subkeys used in the encryption process
public short[] getSubKeys() {
return subKey;
}
//Method to set the key and extend keys to get the subkeys
//Takes in a 64-bit key
//Extends it based on how many rounds are needed
//Makes use of the FK function to generate the key
public void setKey(byte[] key) {
//Set up the necessary parameters to extend the key using the Fiestel rounds
int roundsLimit = ((this.R + 8) / 2) + 1;
int[] A = new int[roundsLimit + 1]; // Left part of the 64 bits Key (MSB)
int[] B = new int[roundsLimit + 1]; // Right part of the 64 bits Key (LSB)
int[] D = new int[roundsLimit + 1]; // Result from functionFK
int fkOutput = 0;
// Spliting the 64 bits key into two 32 bits ints (A and B) to pass those to functionFK
A[0] = A[0] |= ((key[0] & 255) << 24);
A[0] = A[0] |= ((key[1] & 255) << 16);
A[0] = A[0] |= ((key[2] & 255) << 8);
A[0] = A[0] |= (key[3] & 255);
B[0] = B[0] |= ((key[4] & 255) << 24);
B[0] = B[0] |= ((key[5] & 255) << 16);
B[0] = B[0] |= ((key[6] & 255) << 8);
B[0] = B[0] |= (key[7] & 255);
// Getting the subkeys: Using the key schedule
for (int r = 1; r < (roundsLimit); r++) {
D[r] = A[r - 1];
A[r] = B[r - 1];
B[r] = functionFK(A[r - 1], (B[r - 1] ^ D[r - 1]));
subKey[2 * (r - 1)] = (short)(B[r] >> 16);
subKey[(2 * (r - 1) + 1)] = (short) B[r];
}
//Checks to see final case if our R is odd. We need an extra key than what is normally used
if (this.R % 2 == 1) {
D[roundsLimit] = A[roundsLimit - 1];
A[roundsLimit] = B[roundsLimit - 1];
B[roundsLimit] = functionFK(A[roundsLimit - 1], (B[roundsLimit - 1] ^ D[roundsLimit - 1]));
subKey[2 * (roundsLimit - 1)] = (short)(B[roundsLimit] >> 16);
}
}
//Method for encrypting a single plaintext block of 64 bits
public void encrypt(byte[] text) {
//Set up side Arrays
int[] RightArray = new int[R + 2];
int[] LeftArray = new int[R + 2];
//Pack text into Right and Left 32-bit integers
LeftArray[0] |= ((text[0] & 255) << 24);
LeftArray[0] |= ((text[1] & 255) << 16);
LeftArray[0] |= ((text[2] & 255) << 8);
LeftArray[0] |= (text[3] & 255);
RightArray[0] |= ((text[4] & 255) << 24);
RightArray[0] |= ((text[5] & 255) << 16);
RightArray[0] |= ((text[6] & 255) << 8);
RightArray[0] |= (text[7] & 255);
//Set up the initial keys for use
int leftInitKey = 0;
int rightInitKey = 0;
leftInitKey |= ((subKey[R] & 65535) << 16);
leftInitKey |= ((subKey[R + 1] & 65535));
rightInitKey |= ((subKey[R + 2] & 65535) << 16);
rightInitKey |= ((subKey[R + 3] & 65535));
LeftArray[0] = LeftArray[0] ^ leftInitKey;
RightArray[0] = RightArray[0] ^ rightInitKey;
//Initial xor
RightArray[0] = RightArray[0] ^ LeftArray[0];
//Feistel rounds
for (int i = 1; i <= R; i++) {
RightArray[i] = LeftArray[i - 1] ^ functionF(RightArray[i - 1], subKey[i - 1]);
LeftArray[i] = RightArray[i - 1];
}
//Final xor of he left and right sides
LeftArray[R + 1] = LeftArray[R] ^ RightArray[R];
RightArray[R + 1] = RightArray[R];
//Set up final keys for xor
int leftFinalKey = 0;
int rightFinalKey = 0;
rightFinalKey |= ((subKey[R + 4] & 65535) << 16);
rightFinalKey |= ((subKey[R + 5] & 65535));
leftFinalKey |= ((subKey[R + 6] & 65535) << 16);
leftFinalKey |= ((subKey[R + 7] & 65535));
//Xor the last subkeys
LeftArray[R + 1] = LeftArray[R + 1] ^ leftFinalKey;
RightArray[R + 1] = RightArray[R + 1] ^ rightFinalKey;
//pack the results back into the encryption array
for (int i = 3; i >= 0; i--) {
text[i] = (byte) RightArray[R + 1];
RightArray[R + 1] = RightArray[R + 1] >>> 8;
}
for (int i = 7; i >= 4; i--) {
text[i] = (byte) LeftArray[R + 1];
LeftArray[R + 1] = LeftArray[R + 1] >>> 8;
}
}
//Function F used for encryption
//Inputs: A, B, where A is the plaintext and B is the subkey
private int functionF(int A, short B) {
//set up and pack int and short inputs into byte arrays for convinence and set up a output array
byte[] subA = new byte[4];
byte[] subB = new byte[2];
subA[0] = (byte)(A >>> 24);
subA[1] = (byte)(A >>> 16);
subA[2] = (byte)(A >>> 8);
subA[3] = (byte)(A >>> 0);
subB[0] = (byte)(B >>> 8);
subB[1] = (byte)(B >>> 0);
byte[] fOut = new byte[4];
//Do some initial xoring
fOut[1] = (byte)((subA[1] & 255) ^ (subB[0] & 255) ^ (subA[0] & 255));
fOut[2] = (byte)((subA[2] & 255) ^ (subB[1] & 255) ^ (subA[3] & 255));
//Call the S function given a particular path through the Function
fOut[1] = functionS(fOut[1], fOut[2], (byte) 1);
fOut[2] = functionS(fOut[2], fOut[1], (byte) 0);
fOut[0] = functionS(subA[0], fOut[1], (byte) 0);
fOut[3] = functionS(subA[3], fOut[2], (byte) 1);
//Set up and pack the result into an output integer
int output = 0;
output |= (fOut[0] & 255);
output = output << 8;
output |= (fOut[1] & 255);
output = output << 8;
output |= (fOut[2] & 255);
output = output << 8;
output |= (fOut[3] & 255);
return output;
}
//Function FK which is used in the key generation phase
//Inputs: A and B which are both 32-bit integers
private int functionFK(int A, int B) {
//Set up substitute bytes and pack in the two inputs
byte[] subA = new byte[4];
byte[] subB = new byte[4];
subA[0] = (byte)(A >>> 24);
subA[1] = (byte)(A >>> 16);
subA[2] = (byte)(A >>> 8);
subA[3] = (byte)(A >>> 0);
subB[0] = (byte)(B >>> 24);
subB[1] = (byte)(B >>> 16);
subB[2] = (byte)(B >>> 8);
subB[3] = (byte)(B >>> 0);
//Set up the output byte array for convinence
byte[] fKOut = new byte[4];
fKOut[1] = (byte)((subA[1] & 255) ^ (subA[0] & 255));
fKOut[2] = (byte)((subA[2] & 255) ^ (subA[3] & 255));
//Do the appropriate xor functions
fKOut[1] = functionS(fKOut[1], (byte)((fKOut[2] & 255) ^ (subB[0] & 255)), (byte) 1);
fKOut[2] = functionS(fKOut[2], (byte)((fKOut[1] & 255) ^ (subB[1] & 255)), (byte) 0);
fKOut[0] = functionS(subA[0], (byte)((fKOut[1] & 255) ^ (subB[2] & 255)), (byte) 0);
fKOut[3] = functionS(subA[3], (byte)((fKOut[2] & 255) ^ (subB[3] & 255)), (byte) 1);
//Pack the output into an integer
int output = 0;
output |= (fKOut[0] & 255);
output = output << 8;
output |= (fKOut[1] & 255);
output = output << 8;
output |= (fKOut[2] & 255);
output = output << 8;
output |= (fKOut[3] & 255);
return output;
}
//S Function used in both F and FK
//Takes in 2 bytes and a 1 or zero for delta.
//Sums them then mods by 256 and left rotates by 2
private byte functionS(byte A, byte B, byte delta) {
//Sum inputs
byte T = (byte)(((A & 255) + (B & 255) + (delta & 255)) % 256);
//Left Rotate by 2
return (byte)(((T & 255) << (byte) 2) | ((T & 255) >>> (byte) 6));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment