Сдвиг битов с помощью BigIntegers в Java

Я реализую шифрование DES на Java с использованием BigIntegers.

Я смещаю бинарные ключи влево с помощью Java BigIntegers, выполняя метод BigInteger.leftShift(int n). Тональность N (Kn) зависит от результата сдвига Kn-1. Проблема, с которой я сталкиваюсь, заключается в том, что я распечатываю результаты после создания каждого ключа, и сдвиг не является ожидаемым результатом. Тональность разделена на 2 Cn и Dn (левый и правый соответственно).

Я специально пытаюсь сделать это: «Чтобы сделать сдвиг влево, переместите каждый бит на одну позицию влево, за исключением первого бита, который циклически перемещается в конец блока».

Кажется, что буквы О на конце прибавляются в зависимости от смены. Не уверен, как это исправить.

Полученные результаты:

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


person ThePinkPoo    schedule 28.04.2010    source источник


Ответы (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));
}
person Brett Kail    schedule 28.04.2010
comment
Но разве это не ограниченная точность? Что, если bi имеет 100 бит? - person polygenelubricants; 28.04.2010
comment
Да, это ограниченная точность. Однако c0 — это 29 бит, а c15 — 56, поэтому я предположил, что пользователю нужна точность меньше 64. Проверяя Wiki на предмет алгоритма DES, я вижу, что 28-битные половинки в этом алгоритме чередуются, поэтому я обновил свой отвечать. Спасибо. - person Brett Kail; 28.04.2010

Кажется, вам нужен циклический сдвиг влево. BigInteger.shiftLeft не циклический. Вам нужно будет объединить shiftLeft, shiftRight, and и or точно так же, как если бы вы использовали 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) вместо того, чтобы вычислять его каждый раз.

person polygenelubricants    schedule 28.04.2010
comment
Нет, это не работает по той причине, которую он опубликовал: BigInteger с бесконечной точностью будет продолжать добавлять 0 справа. Вашему алгоритму требуется and(BigInteger.valueOf(0xffffffffL). - person Brett Kail; 28.04.2010
comment
Нет, алгоритмы по-прежнему не работают для целых чисел произвольной точности, потому что они требуют установки старшего бита. Например, многократное применение cycloLeftShift к BigInteger.valueOf(1) всегда возвращает 1, что, конечно же, не предназначено. Извините, но на этот раз голосую против. Исправьте, чтобы позволить пользователю пройти в L, и я удалю. - person Brett Kail; 28.04.2010
comment
@bkail: я признаю, что не понимаю приложение (DES?), но это было то, к чему я стремился. Теперь я понял, что окно с фиксированным циклом может быть тем, что нужно OP, поэтому я пояснил это в своем ответе. Спасибо за отзыв. - person polygenelubricants; 28.04.2010
comment
Убрал минусовку. Я полагаю, что он реализует это: en.wikipedia.org/wiki/Data_Encryption_Standard - person Brett Kail; 28.04.2010

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

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

person bgiles    schedule 28.04.2010

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

person President James K. Polk    schedule 29.04.2010