2

我正在尝试做一个Feistel Cipher的小实现。这是我一直在尝试的:

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;
}

圆函数scramble为:

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

我试图首先加密明文的左右两半,然后通过解密轮运行它 - 所以到最后,数组的值应该是 [1,2,3] 和 [4,5,6] (回到明文)。使用 8 的密钥输入,解密后我得到 [15, 13, 0] 和 [8, 12, 1] 的值。我哪里错了?

为简单起见,我现在只是使用常量作为键以及整数的输入,而不是从文件中读取/使用字节数组。

编辑:

循环计数不正确。将“加密循环”更改为:

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;
}

循环现在计算第 1,2,3 轮(加密)和 3,2,1(解密)。但是,解密仍然没有得到正确的明文。

4

3 回答 3

3

Sometimes it is easier to see things if they are stripped down to the minimum. This pseudocode minimal Feistel cipher may help:

function FeistelEncipher(plaintextBlock)

  left <- left hand half of plaintextBlock
  right <- right hand half of plaintextBlock

  // Note the half-open interval.
  for (roundNumber in [0 .. number of rounds[)

    if (roundNumber != 0)
      swap(left, right)
    end if

    right <- right XOR F(left, roundNumber)

  end for

  // Return ciphertext block.
  return join(left, right)

end function


function F(data, roundNumber)

  return some combination of the data and the round key for this round

end function

An even number of rounds is assumed, and the reversed closing '[' indicates an open ended interval.

于 2016-11-01T17:11:08.007 回答
2

Feistel 的工作原理是将右侧的函数应用于左侧,即 left = left ^ F(right) 然后交换。这等价于 right 2 = left 1 ^ F(right1), left 2 = right 1但该公式在 Java 没有的并行或解构赋值的语言中效果更好。请参阅https://en.wikipedia.org/wiki/Feistel_cipher上的图片。此外,您的代码组织在解密结束时会进行太多交换。修复这两个:

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));
    }
}

结果:

=====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]

此外,通常 F 使用整个右半部分并产生适用于整个左半部分的结果;通过在 32 位 int 块上单独执行,您实际上是在并行运行三个独立的 32 位分组密码,有效地在 ECB 模式下。如果这是一个真正的密码,32 位块和 ECB 都将是严重的弱点。

于 2016-10-31T01:45:53.730 回答
2

你的圆形计数器不是对称的。

for(int r = 0; r < 3; r++)

计数:0、1、2。

for(int r = 3; r > 0; r--)

计数:3、2、1。

于 2016-10-30T16:38:42.990 回答