Я реализую шифрование DES в Java с использованием BigIntegers.
Меня оставляют, смещая двоичные ключи с Java BigIntegers путем выполнения BigInteger.leftShift (интервал n) метод. Ключ 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: 11110001111001100110101010100000000000000000000000000
c14: 1111010101010011001100001111000000000000000000000000000
d14: 1111000111100110011010101010000000000000000000000000000
c15: 11110101010100110011000011110000000000000000000000000000
d15: 11110001111001100110101010100000000000000000000000000000
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-битных чисел, поэтому вы можете просто использовать примитивы для вращения 28-битных половин DES. Я не знаком с алгоритмом DES, поэтому предполагаю, что вам понадобится BigInteger для чего-то еще.
private static BigInteger rotateLeftPrimitive(BigInteger bi) {
int value = bi.intValue();
return BigInteger.valueOf(((value << 1) & 0xffffffe) | ((value >>> 27) & 1));
}
Похоже, вам нужен циклический сдвиг влево. BigInteger.shiftLeft
не является циклическим. Вам нужно будет объединить shiftLeft
, shiftRight
, и
и или
, как если бы вы использовали 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, но вы можете обнаружить, что простой массив int с 1 битом на элемент массива так же просто или проще, или, возможно, связанный список.