Я недавно забрал копию Прикладной Криптографии Bruce Schneier, и это было хорошее чтение. Я теперь понимаю, как несколько алгоритмов обрисовали в общих чертах в книжной работе, и я хотел бы начать реализовывать несколько из них в C.
Одна вещь, которую имеют общего многие алгоритмы, делит x-bit ключ в несколько меньших y-bit ключей. Например, ключ Шифров, 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;}
Где 64 бита и b, и c составляют 32 бита. Однако компилятор предупреждает меня о том, что я смещаю переменную на 32 бита на 32 бита.
Мои вопросы - они:
Как я сказал, я довольно знаком с C, но побитовые операторы и т.п. все еще дают мне головную боль.
Править
Я выяснил, что мой макрос объединения на самом деле не комбинировал две 32-разрядных переменные, но просто осуществление операции ИЛИ 0 a, и добирался в результате.
Так, сверх моих предыдущих вопросов у меня все еще нет метода объединения двух 32-разрядных переменных для получения 64-разрядной; предложение о том, как сделать это, ценилось бы.
Да, это неопределенное поведение.
ISO / IEC 9899: 1999 6.5.7 Операторы побитового сдвига ¶3
Целочисленные повышения выполняются для каждого из операндов. Тип результата - это тип продвинутого левого операнда. Если значение правого операнда отрицательное или больше или равно ширине выдвинутого левого операнда, поведение не определено.
C11, также известный как 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) )
И, пожалуйста, даже не думайте об использовании собственного шифрования для производственного кода.
Если это не проект «изобретать колесо, чтобы понять, как оно работает», не надо • реализовать свои собственные криптографические функции.
Когда-либо.
Достаточно сложно использовать доступные алгоритмы для работы (и выбрать правильный), не стреляйте себе в ногу, запустив в производство какой-нибудь самодельный криптографический API. Скорее всего ваше шифрование не зашифрует
Сдвиг 32-битного значения на 32 бит или более не определен в C и C ++. Одна из причин, по которой он был оставлен неопределенным, заключается в том, что на некоторых аппаратных платформах 32-битная инструкция сдвига учитывает только 5 младших битов предоставленного счетчика сдвига. Это означает, что какой бы счетчик сдвига вы ни прошли, он будет интерпретироваться по модулю 32.Попытка переключиться на 32 на такой платформе фактически приведет к сдвигу на 0, то есть вообще не сдвинется.
Авторы языка не хотели обременять компиляторы, написанные для такой платформы, задачей анализа количества сдвигов перед выполнением сдвига. Вместо этого в спецификации языка сказано, что поведение не определено. Это означает, что если вы хотите получить значение 0 из 32-битного сдвига на 32 (или более), вы должны распознать ситуацию и обработать ее соответствующим образом.
что плохого в сдвиге 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;