javacryptographyfeistel-cipher

Small implementation of a Feistel Cipher in Java


I'm trying to do a small implementation of a Feistel Cipher. This is what I've been trying:

int[] left = {1,2,3};//left half of plaintext
int[] right = {4,5,6};//right half of plaintext
int temp[];//temp for swapping values

//encrypt the plaintext (left and right arrays)
for(int r = 0; r < 3; r++) {//the number of rounds
    for(int i = 0; i < right.length; i++){
        right[i] = left[i] ^ (scramble(right[i], KEY, r));
    }
    temp = left;
    left = right;
    right = temp;
}

//swap left and right array before decryption
temp = left;
left = right;
right = temp;
for(int r = 3; r > 0; r--) {//start from the last round
    for(int i = 0; i < right.length; i++) {
        right[i] = left[i] ^ (scramble(right[i], KEY, r));
    }

    //again, swap arrays to do the next round
    temp = left;
    left = right;
    right = temp;
}

The round function, scramble is:

private static int scramble(int character, int key, int roundNumber) {
    return (int) Math.pow(2 * roundNumber * key, character) % 15;
}

I am attempting to first encrypt the left and right halves of the plaintext, and then run it through the decryption rounds - so by the end, the array's values should be [1,2,3] and [4,5,6] (back to the plaintext). Using a key input of 8, after decryption I'm getting values of [15, 13, 0] and [8, 12, 1]. Where am I going wrong with this?

For simplicity I'm just using a constant as the key right now as well as input of integers as opposed to reading from a file/using byte arrays.

edit:

counting for the loops was incorrect. Changed the "encryption loop" to:

for(int r = 1; r < 4; r++) {//the number of rounds
        for(int i = 0; i < right.length; i++){
            right[i] = left[i] ^ (scramble(right[i], KEY, r));
        }

        temp = left;
        left = right;
        right = temp;
}

The loops now count rounds 1,2,3 (encryption) and 3,2,1 (decryption). However, the decryption still isn't resulting in the correct plaintext.


Solution

  • Feistel works by applying a function of the right side TO the left side, i.e. left = left ^ F(right) then swap. This is equivalent to right2 = left1 ^ F(right1), left2 = right1 but that formulation works better in languages with parallel or destructuring assignment which Java doesn't have. See the picture at https://en.wikipedia.org/wiki/Feistel_cipher . In addition your code organization does one too many swap at the end of decrypt. Fixing both of those:

    static void SO40331050Feistel (){ 
        final int KEY = 8;
        int[] left = {1,2,3}, right = {4,5,6}, temp;
        System.out.println ("=====WRONG=====");
        for(int r = 1; r <= 3; r++) {
            for(int i = 0; i < right.length; i++){
                right[i] = left[i] ^ (scramble(right[i], KEY, r));
            }
            System.out.println ("ENC"+r +" "+Arrays.toString(left) +" "+Arrays.toString(right));
            temp = left; left = right; right = temp;
        }
        temp = left; left = right; right = temp; // swap before decrypt
        for(int r = 3; r >= 1; r--) {
            for(int i = 0; i < right.length; i++) {
                right[i] = left[i] ^ (scramble(right[i], KEY, r));
            }
            System.out.println ("DEC"+r + " "+Arrays.toString(left) +" "+Arrays.toString(right));
            temp = left; left = right; right = temp;
        }
        left = new int[]{1,2,3}; right = new int[]{4,5,6}; // reset
        System.out.println ("=====RIGHT=====");
        for(int r = 1; r <= 3; r++) {
            for(int i = 0; i < right.length; i++){
                left[i] ^= (scramble(right[i], KEY, r));
            }
            System.out.println ("ENC"+r +" "+Arrays.toString(left) +" "+Arrays.toString(right));
            temp = left; left = right; right = temp; // swap after
        }
        for(int r = 3; r >= 1; r--) {
            temp = left; left = right; right = temp; // swap before on decrypt
            for(int i = 0; i < right.length; i++) {
                left[i] ^= (scramble(right[i], KEY, r));
            }
            System.out.println ("DEC"+r + " "+Arrays.toString(left) +" "+Arrays.toString(right));
        }
    }
    

    RESULTS:

    =====WRONG=====
    ENC1 [1, 2, 3] [0, 3, 2]
    ENC2 [0, 3, 2] [2, 7, 10]
    ENC3 [2, 7, 10] [3, 11, 3]
    DEC3 [2, 7, 10] [14, 0, 6]
    DEC2 [14, 0, 6] [10, 7, 1]
    DEC1 [10, 7, 1] [13, 6, 0]
    =====RIGHT=====
    ENC1 [0, 3, 2] [4, 5, 6]
    ENC2 [5, 13, 2] [0, 3, 2]
    ENC3 [3, 4, 11] [5, 13, 2]
    DEC3 [0, 3, 2] [5, 13, 2]
    DEC2 [4, 5, 6] [0, 3, 2]
    DEC1 [1, 2, 3] [4, 5, 6]
    

    Also, it is usual for F to use the whole right half and produce a result that applies to the whole left half; by doing it separately on 32-bit int pieces you are actually running three independent 32-bit block ciphers in parallel, effectively in ECB mode. Both 32-bit block and ECB would be serious weaknesses if this were a real cipher.