Битовые манипуляции с символами в Java или C? - PullRequest
3 голосов
/ 05 августа 2011

Я студент, пытающийся реализовать алгоритм DES.У меня есть выбор из 2 языков: C & Java.Я понял алгоритм, но в самом начале застрял в манипуляциях с ключом.

Вот в чем проблема.В DES у нас есть 64-битный ключ (8 символов в C и 4 в Java, хотя я могу преобразовать символ в байт, чтобы получить только часть ASCII), из которых каждый 8-й бит является битом четности и должен быть удаленсделать его 56-битным ключом и выполнить дальнейшую обработку.Я долго думал об этом, но не могу найти способ обрезать каждый 8-й бит и сохранить результат в другом массиве символов (как в Java, так и в C).Я попытался использовать java.util.BitSet class, но запутался.

Любые предложения относительно того, как можно удалить каждый 8-й бит и объединить смежные байты (Java) или символы (C), чтобы получить 56-битный ключ?

Я знаю о битовых операциях и сдвиге, но для конкретного примера:
Предположим, у меня есть 16-битный ключ: 1100 1001 1101 1000.
Мне нужно удалить 8-й и 16-й бит, делаяключ: 1100 100 1101 100.

Если я объявляю 2 байта, как мне усечь 8-й бит и добавить к нему 9-й бит, сделав первый байт: 1100 1001

Итак, чтоМне нужна помощь: как мне заменить 8-й бит на 9-й, заменить 16-й на 17-й и так далее, чтобы извлечь 56-битный ключ из 64-битного ключа?

Если кто-то может объяснить этоя, возможно, смогу реализовать это независимо от языка.

Ответы [ 4 ]

3 голосов
/ 05 августа 2011

Будьте осторожны с 16-битными символами в Java. Многие методы конвертируют только младшие 8 бит. Внимательно прочитайте документацию. Криптографический ключ более обычен для Java как byte[] из-за более сильной типизации, чем в C.

Что касается битов четности, внимательно проверьте алгоритм DES и посмотрите, где они используются. Это должно дать вам подсказку о том, что вам нужно делать с ними.

1 голос
/ 05 августа 2011

В C вы можете манипулировать битами с помощью побитовых операторов, таких как & и |, а также операторов сдвига битов << и >>.

Например, чтобы отключить старший бит данного байта, вы можете сделать это.

char c = 0xBF;  // initial value is bit pattern 10111111
c &= 0x7F;      // perform AND against the bit pattern 01111111
                // final value is bit pattern 00111111 (0x3F)

Это имеет смысл? Очевидно, вам нужно иметь возможность преобразовывать битовый паттерн в шестнадцатеричный, но это не так уж сложно.

Вы можете использовать похожую маскировку для извлечения нужных битов и помещения их в выходной буфер.

Обновление:

У вас есть 64 бита (8 байтов) ввода, и вы хотите 56 бит (7 байт) вывода.

Давайте представим ваши входные данные следующим образом, где каждая буква представляет один бит Буквы «х» - это те, которые вы хотите выбросить.

xAAAAAAA xBBBBBBB xCCCCCCC xDDDDDDD xEEEEEEE xFFFFFFF xGGGGGGG xHHHHHHH

Итак, вы хотите, чтобы ваш окончательный ответ был:

AAAAAAAB BBBBBBCC CCCCCDDD DDDDEEEE EEEFFFFF FFGGGGGG GHHHHHHH

Так что в C у нас может быть такой код:

unsigned char data[8] = {/* put data here */};

// chop off the top bit of the first byte
data[0] <<= 1;

// the bottom bit of data[0] needs to come from the top data bit of data[1]
data[0] |= (data[1] >> 6) & 0x01;

// use similar transformations to fill in data[1], data[2], ... data[6]
// At the end, data[7] will be useless

Конечно, это совсем не оптимизировано, но, надеюсь, вы поняли идею.

0 голосов
/ 07 августа 2011

@ jwd, @jscode Большое спасибо за вашу помощь. To JWD: я понял идею из вашего кода. Казалось, довольно простая логика после того, как я прочитал это .. :-) Интересно, почему я не думал об этом. Ну, я немного отполировал вашу идею, и теперь она отлично работает в Java. Если у кого-то есть предложения, пожалуйста, дайте мне знать. СПАСИБО.. П.С .: Тестовая часть очень примитивна. Я печатаю значения битов. Я сделал это вручную для пары примеров и использовал то же самое, что и ввод, и он отлично работает.

=============================================

public static void main(String[] args) {

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("Enter an 8 char key: ");
        String input;
        try {
            // get key, key.length()>=8 chars
            input = br.readLine();
            if (input.length() < 8) {
                System.out.println("Key < 8B. Exiting. . .");
                System.exit(1);
            }
            // java char has 16 bits instead of 8 bits as in C,
            // so convert it to 8 bit char by getting lower order byte &
            // discarding higher order byte
            char[] inputKey = input.toCharArray();
            byte[] key64 = new byte[8];
            byte[] key56 = new byte[7];

            // consider only first 8 chars even if input > 8
            for (int counter = 0; counter < 8; counter++)
                key64[counter] = (byte) inputKey[counter];

            System.out.print("\n$$ " + new String(key64) + "  $$\n");

            // converting 64bit key to 56 bit key
            for (int counter = 0; counter < KEY_LENGTH - 1; counter++) {
                key64[counter] = (byte) (key64[counter] >>> 1);
                key64[counter] = (byte) (key64[counter] << 1);
            }

            for (int counter = 0; counter < KEY_LENGTH - 1; counter++) {
                key56[counter] = (byte) (key64[counter] << counter);
                key56[counter] = (byte) (key56[counter] | (key64[counter + 1] >>> (KEY_LENGTH - 1 - counter)));
            }

            /*Conversion from 64 to 56 bit testing code
             System.out.println(new String(key56));

            System.out.println();
            for (int counter1 = 0; counter1 < 7; counter1++) {
                for (int counter2 = 7; counter2 >= 0; counter2--) {
                    System.out.println(key56[counter1] & (1 << counter2));
                }
                System.out.println();
            }*/

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
0 голосов
/ 06 августа 2011

Я могу кратко рассказать о способе .... я объясню, если потребуется ...

Сдвиг вправо всех 8 символов на 1, т.е. c1 = c1 >> 1 и т. Д.

Multiplyc1 с общим количеством байтов (т.е. 56), т.е. c1 * 0x0000000000 (не уверен, сколько нулей)

Затем добавьте 0x0000 + к следующим символам, т.е. c2 = c2 + 0x0000; c3 = c3 + 0x000000 и так далее (продолжайте добавлять 2 0 для последующих символов)

Теперь начните добавлять c1 + c2 + c3 .......

Идея заключается в том, что сначала заполните число нулями и начните добавлять другие символы, чтобы они продолжали правильно лежать

00 00 00 00 00 00 00 00 00
34 00 00 00 00 00 00 00 00   (c1 = c1>>1) . Here c1=0x34, c2=0x67
00 67 00 00 00 00 00 00 00   (c2 = c2>>1)
so on...............

Добавить выше; Я надеюсь, что это поможет.

...