unsigned int x = pn.CCA; // извлекаем битовое поле CCA
Если бы для представления тех же самых битов мы использовали целое число типа
int
с именем
pni
, то нам пришлось бы написать такой код:
unsigned int y = (pni>>4)&0x7; // извлекаем битовое поле CCA
Иначе говоря, этот код сдвигает структуру
pn
вправо, так чтобы поле
CCA
стало крайним левым битом, а затем накладывает на оставшиеся биты маску
0x7
(т.е. устанавливает последние три бита).
Если вы посмотрите на машинный код, то скорее всего обнаружите, что сгенерированный код идентичен двум строкам, приведенным выше.
Смесь аббревиатур (
CCA
,
PPN
,
PFN
) типична для низкоуровневых кодов и мало информативна вне своего контекста.
25.5.6. Пример: простое шифрование
В качестве примера манипулирования данными на уровне битов и байтов рассмотрим простой алгоритм шифрования: Tiny Encryption Algorithm (TEA). Он был изобретен Дэвидом Уилером (David Wheeler) в Кембриджском университете (см. раздел 22.2.1). Он небольшой, но обеспечивает превосходную защиту от несанкционированной расшифровки.
Не следует слишком глубоко вникать в этот код (если вы не слишком любознательны или не хотите заработать головную боль). Мы приводим его просто для того, чтобы вы почувствовали вкус реального приложения и ощутили полезность манипулирования битами. Если хотите изучать вопросы шифрования, найдите другой учебник. Более подробную информацию об этом алгоритме и варианты его реализации на других языках программирования можно найти на веб-страницеили на сайте, посвященному алгоритму TEA и созданному профессором Саймоном Шепердом (Simon Shepherd) из Университета Брэдфорда (Bradford University), Англия. Этот код не является самоочевидным (без комментариев!).
Основная идея шифрования/дешифрования (кодирования/декодирования) проста. Я хочу послать вам некий текст, но не хочу, чтобы его прочитал кто-то другой. Поэтому я преобразовываю свой текст так, чтобы он стал непонятным для людей, которые не знают, как именно я его модифицировал, но так, чтобы вы могли произвести обратное преобразование и прочитать мой текст. Эта процедура называется шифрованием. Для того чтобы зашифровать текст, я использую алгоритм (который должен считать неизвестным нежелательным соглядатаям) и строку, которая называется ключом. У вас этот ключ есть (и надеемся, что его нет у нежелательного соглядатая). Когда вы получите зашифрованный текст, вы расшифруете его с помощью ключа; другими словами, восстановите исходный текст, который я вам послал.
Алгоритм TEA получает в качестве аргумента два числа типа
long
без знака (
v[0]
,
v[1]
), представляющие собой восемь символов, которые должны быть зашифрованы; массив, состоящий из двух чисел типа
long
без знака (
w[0]
,
w[1]
), в который будет записан результат шифрования; а также массив из четырех чисел типа
long
без знака (
k[0]..k[3]
), который является ключом.
void encipher(
const unsigned long *const v,
unsigned long *const w,
const unsigned long * const k)
{
unsigned long y = v[0];
unsigned long z = v[1];
unsigned long sum = 0;
unsigned long delta = 0x9E3779B9;
unsigned long n = 32;
while(n–– > 0) {
y += (z << 4 ^ z >> 5) + z ^ sum + k[sum&3];
sum += delta;
z += (y << 4 ^ y >> 5) + y ^ sum + k[sum>>11 & 3];
}
w[0]=y; w[1]=z;
}
}
Поскольку
все данные не имеют знака, мы можем выполнять побитовые операции, не опасаясь сюрпризов, связанных с отрицательными числами. Основные вычисления выполняются с помощью сдвигов (
<<
и
>>
), исключительного “или” (
^
) и побитовой операции “и” (
&
) наряду с обычным сложением (без знака). Этот код написан специально для машины, в которой тип long занимает четыре байта. Код замусорен “магическими” константами (например, он предполагает, что значение
sizeof(long)
равно
4
). Обычно так поступать не рекомендуется, но в данном конкретном коде все это ограничено одной страницей, которую программист с хорошей памятью должен запомнить как математическую формулу. Дэвид Уиллер хотел шифровать свои тексты, путешествуя без ноутбуков и других устройств. Программа кодирования и декодирования должна быть не только маленькой, но и быстрой. Переменная
n
определяет количество итераций: чем больше количество итераций, тем сильнее шифр. Насколько нам известно, при условии
n==32
алгоритм TEA никогда не был взломан.
Приведем соответствующую функцию декодирования.
void decipher(
const unsigned long *const v,
unsigned long *const w,
const unsigned long * const k)
{
unsigned long y = v[0];
unsigned long z = v[1];
unsigned long sum = 0xC6EF3720;
unsigned long delta = 0x9E3779B9;
unsigned long n = 32;
// sum = delta<<5, в целом sum = delta * n
while(n–– > 0) {
z –= (y << 4 ^ y >> 5) + y ^ sum + k[sum>>11 & 3];
sum –= delta;
y –= (z << 4 ^ z >> 5) + z ^ sum + k[sum&3];
}
w[0]=y; w[1]=z;
}
}
Мы можем использовать алгоритм TEA для того, чтобы создать файл, который можно передавать по незащищенной линии связи.
int main // отправитель
{
const int nchar = 2*sizeof(long); // 64 бита
const int kchar = 2*nchar; // 128 битов
string op;
string key;
string infile;
string outfile;
cout << "введите имя файлов для ввода, для вывода и ключ:\n";
cin >> infile >> outfile >> key;
while (key.size<kchar) key += '0'; // заполнение ключа
ifstream inf(infile.c_str);
ofstream outf(outfile.c_str);
if (!inf || !outf) error("Неправильное имя файла");