Сдвиг клев - PullRequest
       56

Сдвиг клев

1 голос
/ 22 сентября 2011

Я работал над алгоритмом шифрования, и мне интересно, как я могу преобразовать следующий код во что-то более простое и как перевернуть этот код.

typedef struct 
{
    unsigned low : 4;
    unsigned high : 4;
} nibles;

static void crypt_enc(char *data, int size)
{
    char last = 0;

    //...

    // Pass 2
    for (i = 0; i < size; i++)
    {
        nibles *n = (nibles *)&data[i];

        n->low = last;
        last = n->high;
        n->high = n->low;
    }
    ((nibles *)&data[0])->low = last;
}

данные - это вход и выход для этого кода.

Ответы [ 5 ]

3 голосов
/ 22 сентября 2011

Вы устанавливаете оба куска каждого байта на одну и ту же вещь, потому что вы устанавливаете верхний клев равным низкому клеву в конце. Я предполагаю, что это ошибка, и что вы намеревались сдвинуть все клочки данных, перенося их с одного байта на другой и вращаясь. То есть , ABCDEF (порядок отрывков от низкого до высокого) станет FABCDE. Пожалуйста, поправьте меня, если я ошибся.

Код должен быть примерно таким:

static void crypt_enc(char *data, int size)
{
    char last = 0;

    //...

    // Pass 2
    for (i = 0; i < size; i++)
    {
        nibles *n = (nibles *)&data[i];

        unsigned char old_low = n->low;
        n->low = last;
        last = n->high;
        n->high = old_low;
    }
    ((nibles *)&data[0])->low = last;
}

Теперь все в порядке? Нет. Приведение к nibbles* является четким, только если выравнивание nibbles не является более строгим, чем выравнивание char. И , что не гарантируется (однако при небольшом изменении GCC генерирует тип с таким же выравниванием).

Лично я бы вообще избежал этой проблемы. Вот как я это сделаю:

void set_low_nibble(char& c, unsigned char nibble) {
    // assumes nibble has no bits set in the four higher bits)
    unsigned char& b = reinterpret_cast<unsigned char&>(c);
    b = (b & 0xF0) | nibble;
}

void set_high_nibble(char& c, unsigned char nibble) {
    unsigned char& b = reinterpret_cast<unsigned char&>(c);
    b = (b & 0x0F) | (nibble << 4);
}

unsigned char get_low_nibble(unsigned char c) {
    return c & 0x0F;
}

unsigned char get_high_nibble(unsigned char c) {
    return (c & 0xF0) >> 4;
}

static void crypt_enc(char *data, int size)
{
    char last;

    //...

    // Pass 2
    for (i = 0; i < size; ++i)
    {
        unsigned char old_low = get_low_nibble(data[i]);
        set_low_nibble(data[i], last);
        last = get_high_nibble(data[i]);
        set_high_nibble(data[i], old_low);
    }
    set_low_nibble(data[0], last);
}

Выполнение обратного действия означает изменение «низкого» уровня на «высокий» и наоборот; катится до последнего клева, а не до первого; и проходя данные в обратном направлении:

for (i = size-1; i >= 0; --i)
{
    unsigned char old_high = get_high_nibble(data[i]);
    set_high_nibble(data[i], last);
    last = get_low_nibble(data[i]);
    set_low_nibble(data[i], old_high);
}
set_high_nibble(data[size-1], last);

При желании вы можете избавиться от всех переводов на временный last. Вам просто нужно сохранить последний кусочек из всех, а затем переложить кусочек напрямую, без использования другой переменной:

last = get_high_nibble(data[size-1]);
for (i = size-1; i > 0; --i) // the last one needs special care
{
    set_high_nibble(data[i], get_low_nibble(data[i]));
    set_low_nibble(data[i], get_high_nibble(data[i-1]));
}
set_high_nibble(data[0], get_low_nibble(data[0]));
set_low_nibble(data[0], last);
1 голос
/ 22 сентября 2011

Похоже, вы просто смещаете каждый кусок на одно место, а затем берете младший кусок последнего байта и перемещаете его в начало.Просто сделайте обратное, чтобы расшифровать (начать с конца data, перейти к началу)

0 голосов
/ 22 сентября 2011

Обращение кода невозможно, поскольку алгоритм полностью обрабатывает первый байт и отбрасывает нижнюю половину остальных.

На первой итерации цикла for нижняя часть первого байта устанавливается равной нулю.

n->low = last;

Это никогда нигде не сохраняется.Это просто исчезло.

// I think this is what you were trying for
last = ((nibbles *)&data[0])->low;
for (i = 0; i < size-1; i++)
{
    nibbles *n = (nibbles *)&data[i];
    nibbles *next = (nibbles *)&data[i+1];
    n->low = n->high;
    n->high = next->low;
}
((nibbles *)&data[size-1])->high = last;

Чтобы изменить это:

last = ((nibbles *)&data[size-1])->high;
for (i = size-1; i > 0; i--)
{
    nibbles *n = (nibbles *)&data[i];
    nibbles *prev = (nibbles *)&data[i-1];
    n->high = n->low;
    n->low = prev->high;
}
((nibbles *)&data[0])->low = last;

... если только я не достиг высокого и низкого уровня назад.

Но в любом случае, это НИЧЕГО рядомполе шифрования.Это в лучшем случае запутывание.Безопасность через неизвестность - это ужасная ужасная практика, а самодельное шифрование доставляет людям неприятности.Если вы играете вокруг, тем больше сил вам.Но если вы действительно хотите, чтобы что-то было защищено, пожалуйста, для блага всех ваших байтов используйте хорошо известную и безопасную схему шифрования.

0 голосов
/ 22 сентября 2011

Ответ Кевина прав в том, что вы пытаетесь сделать.Тем не менее, вы сделали элементарную ошибку.Конечный результат состоит в том, что весь ваш массив заполнен нулями, а не вращающимися полубайтами.

Чтобы понять, почему это так, я бы посоветовал вам сначала выполнить вращение байтов ({a, b, c} -> {c, a, b}) таким же образом -который с помощью счетчика цикла увеличивается от 0 до размера массива.Посмотрите, сможете ли вы добиться большего успеха, сократив переводы в переменную last.

Как только вы увидите, как вы можете это сделать, вы можете просто применить ту же логику к клевам ({al:ah, bl:bh, cl:ch} -> {ch:al, ah:bl, bh:cl}).Мое представление здесь неверно, если вы думаете с точки зрения шестнадцатеричных значений.Шестнадцатеричное значение 0xXY равно Y:X в моей записи.Если вы думаете о том, как вы выполняли ротацию байтов, вы можете выяснить, как сохранить только один полубайт и просто перевести полубайты, фактически не перемещая их в last.

0 голосов
/ 22 сентября 2011

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

...