BitShifting с BigIntegers в Java

Я реализую шифрование 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

7
задан ThePinkPoo 28 April 2010 в 05:20
поделиться

4 ответа

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));
}
10
ответ дан 6 December 2019 в 14:01
поделиться

Похоже, вам нужен циклический сдвиг влево. 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) вместо того, чтобы вычислять его каждый раз.

4
ответ дан 6 December 2019 в 14:01
поделиться

Решение более важного вопроса 1) DES сломан и никогда не должен использоваться ни для чего, кроме работы с устаревшими системами, 2) Sun JCE уже предоставляет реализацию (как и BouncyCastle и другие крипто-провайдеры), и 3) реализация любого крипто-алгоритма является сложной задачей, и вы действительно хотите пойти с хорошо проверенной реализацией для производственного использования.

Если это классное упражнение, я бы использовал byte[] вместо BigInteger. Вам нужно будет сделать немного больше вручную, но это намного ближе к духу DES, поскольку он был разработан, чтобы быть легко реализованным в аппаратном обеспечении.

1
ответ дан 6 December 2019 в 14:01
поделиться

Думаю, ваша идея реализации DES использование битовых строк является разумным в качестве учебного пособия. Вместо того, чтобы напрямую использовать BigIntegers для представления этих битовых строк, я рекомендую вам создать класс BitString, который реализует именно те методы битовых строк, которые вам нужны для вашего проекта. Внутри класса BitString вы можете использовать BigIntegers, но вы можете обнаружить, что простой массив int с 1 битом на элемент массива так же просто или проще, или, возможно, связанный список.

0
ответ дан 6 December 2019 в 14:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: