Что плохого в перестановке 32-битной переменной 32 бит?
Недавно я получил копию прикладной криптографии Брюса Шнайера, и это было хорошо прочитано. Теперь я понимаю, как работают несколько алгоритмов, описанных в книге, и я хотел бы начать реализацию некоторых из них в C.
Одна вещь, с которой связаны многие алгоритмы, - это разделение х-битового ключа на несколько меньших y-бит ключей. Например, ключ Blowfish, X, является 64-битным, но вы должны разбить его на две 32-разрядные половины; Xl и Xr.
Здесь я застреваю. Я довольно приличный с C, но я не самый сильный, когда речь идет о побитовых операторах и т.п.
После некоторой помощи в IRC мне удалось найти эти два макроса:
#define splitup(a, b, c) {b = a >> 32; c = a & 0xffffffff; }
#define combine(a, b, c) {a = (c << 32) | a;}
Если a - 64 бита, а b и c - 32 бита. Однако компилятор предупреждает меня о том, что я переставляю 32-битную переменную на 32 бита.
Мои вопросы таковы:
- Что плохого в перестановке 32-битной переменной 32 бита? Я предполагаю, что это undefined, но эти макросы действительно работают.
- Кроме того, предложите ли вы мне пойти по этому пути?
Как я уже сказал, я довольно хорошо знаком с C, но побитовые операторы и тому подобное все еще дают мне головную боль.
ИЗМЕНИТЬ
Я понял, что мой комбинированный макрос фактически не объединяет две 32-битные переменные, а просто ORing 0 на a и получает результат.
Итак, помимо моих предыдущих вопросов, у меня до сих пор нет метода комбинирования двух 32-битных переменных, чтобы получить 64-битный; предложение о том, как это сделать, будет оценено.
Ответы
Ответ 1
Да, это поведение undefined.
ISO/IEC 9899: 1999 6.5.7 Операторы побитового сдвига ¶3
Целочисленные рекламные акции выполняются для каждого из операндов. Тип результата - это продвинутый левый операнд. Если значение правильного операнда отрицательное или больше или равно ширине продвинутого левого операнда, поведение undefined.
C11 aka ISO/IEC 9899: 2011 говорит то же самое.
Сначала вы должны указать b
для целевого целочисленного типа. Другим моментом является то, что вы должны поместить круглые скобки вокруг параметров макроса, чтобы избежать неожиданностей по приоритетам операторов. Кроме того, здесь очень полезен оператор запятой, позволяющий избежать фигурных скобок, так что макрос можно использовать как обычную команду, закрытую точкой с запятой.
#define splitup(a,b,c) ( (b) = (a) >> 32, (c) = (a) & 0xffffffff )
#define combine(a,b,c) ( (a) = ((unsigned long long)(b) << 32) | (c) )
Дополнительные отклики могут потребоваться для `splitup для отключения предупреждений о прецизионных потерях с помощью сверхпараноидных компиляторов.
#define splitup(a,b,c) ( (b) = (unsigned long)((a) >> 32), (c) = (unsigned long)((a) & 0xffffffff) )
И, пожалуйста, даже не думайте о том, как использовать самозаписываемое шифрование для производственного кода.
Ответ 2
Сдвиг 32-битного значения на 32 бит и более составляет undefined в C и С++. Одной из причин, по которым он остался undefined, является то, что на некоторых аппаратных платформах инструкция 32-разрядного сдвига учитывает только 5 младших бит поставленного количества сдвига. Это означает, что независимо от того, какой счет вы пройдете, он будет интерпретироваться по модулю 32. Попытка сдвига на 32 на такой платформе будет фактически сдвигаться на 0, т.е. Не сдвигаться вообще.
Авторы языка не захотели обременять компиляторы, написанные для такой платформы, задачей анализа счетчика сдвига перед выполнением сдвига. Вместо этого в спецификации языка указано, что поведение undefined. Это означает, что если вы хотите получить значение 0 из 32-битного сдвига на 32 (или более), вам решать, чтобы определить ситуацию и обработать ее соответственно.
Ответ 3
Что плохого в перестановке 32-битной переменной 32 бита?
Лучше назначить 0
n-битовому целому, чем сдвинуть его на n-биты.
Пример:
0 0 1 0 1 ----- 5 bit Integer
0 1 0 1 0 ----- 1st shift
1 0 1 0 0 ----- 2nd shift
0 1 0 0 0 ----- 3rd shift
1 0 0 0 0 ----- 4th shift
0 0 0 0 0 ----- 5th shift (all the bits are shifted!)
У меня до сих пор нет метода объединения двух 32-битных переменных, чтобы получить 64-разрядную версию
Рассмотрим: a
- 64 бит, b
и c
- 32 бит
a = b;
a = a << 32; //Note: a is 64 bit
a = a | c;
Ответ 4
Если это не "изобретать колесо, чтобы понять, как это работает", не выполняйте свои собственные криптографические функции.
Ever.
Достаточно сложно использовать доступные алгоритмы для работы (и выбрать правильный), не стрелять себе в ногу, введя в производство некоторый домашний криптографический API. Скорее всего, ваше шифрование не будет шифроваться
Ответ 5
Что плохого в перестановке 32-битной переменной 32 бита?
В дополнение к тому, что уже было сказано, 32-й бит является битом знака, и вы можете получить расширение знака для сохранения пения, тем самым теряя значимые биты.