使用Java中的BigIntegers进行BitShifting

我正在使用BigIntegers在Java中实现DES加密。

我通过使用BigInteger.leftShift(int n)方法将Java二进制密钥与Java BigIntegers一起移位。 N(Kn)的关键取决于Kn-1的移位结果。 我得到的问题是,我在每个键生成后打印出结果,并且移位不是预期的输出。 密钥分为2 Cn和Dn(分别为左和右)。

我特意尝试这个:“要做左移,将每个位移到左边一个位置,除了第一个位,循环到块的末尾。”

根据转变,它似乎最终会对O进行攻击。 不知道如何纠正这个问题。

结果:

c0:11110101010100110011000011110

d0:11110001111001100110101010100

c1:111101010101001100110000111100

d1:111100011110011001101010101000

c2:11110101010100110011000011110000

d2:11110001111001100110101010100000

c3:1111010101010011001100001111000000

d3:1111000111100110011010101010000000

c4:111101010101001100110000111100000000

d4:111100011110011001101010101000000000

c5:11110101010100110011000011110000000000

d5:11110001111001100110101010100000000000

c6:1111010101010011001100001111000000000000

d6:1111000111100110011010101010000000000000

c7:111101010101001100110000111100000000000000

d7:111100011110011001101010101000000000000000

c8:1111010101010011001100001111000000000000000

d8:1111000111100110011010101010000000000000000

c9:111101010101001100110000111100000000000000000

d9:111100011110011001101010101000000000000000000

c10:11110101010100110011000011110000000000000000000

d10:11110001111001100110101010100000000000000000000

c11:1111010101010011001100001111000000000000000000000

d11:1111000111100110011010101010000000000000000000000

c12:111101010101001100110000111100000000000000000000000

d12:111100011110011001101010101000000000000000000000000

c13:11110101010100110011000011110000000000000000000000000

d13:111100011110011001101010101000000000000000000000000000000

c14:1111010101010011001100001111000000000000000000000000000

d14:1111000111100110011010101010000000000000000000000000000

c15:11110101010100110011000011110000000000000000000000000000

d15:111100011110011001101010101000000000000000000000000000000000

BigInteger实现了无限精度的整数,因此向左移动将继续向左添加零。 你需要一个旋转:

private static BigInteger rotateLeft(BigInteger bi) { BigInteger ret = bi.shiftLeft(1); if (ret.testBit(32)) { ret = ret.clearBit(32).setBit(0); } return ret; } 

对于32位数字来说,这将是相当低效的,所以你也可以使用原语来旋转DES的28位数。 我不熟悉DES算法,所以我假设你需要BigInteger。

 private static BigInteger rotateLeftPrimitive(BigInteger bi) { int value = bi.intValue(); return BigInteger.valueOf(((value << 1) & 0xffffffe) | ((value >>> 27) & 1)); } 

看来你需要一个循环左移。 BigInteger.shiftLeft不是循环的。 你必须结合使用shiftLeftshiftRight and和,就像你使用int<<

 static BigInteger allOnes(int L) { return BigInteger.ZERO .setBit(L) .subtract(BigInteger.ONE); } static BigInteger cyclicLeftShift(BigInteger n, int L, int k) { return n.shiftLeft(k) .or(n.shiftRight(L - k)) .and(allOnes(L)); } 

现在, cyclicLeftShift(n, L, k)向左返回n循环移位的k位,其中循环窗口为L

这是如何工作的如下:

  _________L__________ / \ n : [ABCDE][FG...........] \__k__/\_____L-k_____/ n.shiftLeft(k) : [ABCDE][FG...........][00000] .or n.shiftRight(L - k) : [ABCDE] = [ABCDE][FG...........][ABCDE] _________L__________ .and / \ allOnes(L) : [111..............111] = [FG...........][ABCDE] 

也可以看看


注意 :如果你有一个固定的L ,你可以通过缓存allOnes(L)而不是每次都计算它来优化它。

解决更大的问题1)DES被破坏,除了使用遗留系统之外不应该用于其他任何事情,2)Sun JCE已经提供了一个实现(如BouncyCastle和其他加密提供者),以及3)实现任何加密算法是具有挑战性,你真的希望采用经过良好测试的生产用途。

如果这是一个课堂练习,我会使用byte []而不是BigInteger。 你需要手工做更多的事情,但它更接近DES的精神,因为它的设计很容易在硬件中实现。

我认为你使用位串实现DES的想法作为一种教育工具是合理的。 我建议你不要直接使用BigIntegers来表示这些位串,而是创建一个BitString类,它实现了项目所需的那些位串方法。 在BitString类中,您可以使用BigIntegers,但您可能会发现每个数组元素1位的简单int数组同样简单或容易,或者可能是链表。