Криптография: Шифр Вернама и его реализация на C++ и Delphi

В криптографии шифр Вернама известен также как «схема одноразовых блокнотов». Решение является системой симметричного шифрования, которая была изобретена в 1917 году сотрудниками AT&T Мейджором Джозефом Моборном и Гильбертом Вернамом.

В 1949 годах была опубликована работа Клода Шеннона, где Шеннон доказал абсолютную стойкость шифра Вернама. В этой работе, Шеннон показал что не существует других шифров с подобными свойствами и его выводом стало следующее утверждение: шифр Вернама – самая безопасная криптосистема из всех имеющихся.

Однако, следует заметить, что для того чтобы шифр действительно был стойким необходимо выполнение следующих трех правил:

  1. Ключ для шифрования выбирается случайным образом.
  2. Длина ключа должна быть равна длине открытого текста.
  3. Ключ должен использоваться ТОЛЬКО один раз.

А теперь поподробней о самом шифре и процессе шифрования. Так как этот шифр был придуман для компьютерных систем, то следует заметить что базируется он на двоичной арифметике. Надеюсь что вы знакомы с ней ;). Основным объектом рассмотрения в данном методе шифрования является логическая операция XOR (взаимоисключающее ИЛИ). Таким образом, так как у нас двоичная арифметика, то все операции будут осуществляется над нулем (0) и единицей (1). Логическая операция XOR в отличие от операции OR при логическом сравнении 0 и 1 дает 1, при сравнении 1 с 1 дает 0, а при 0 с 0 дает 0. Следовательно, если мы выполним операцию XOR над числами 10110 и 11010 то получим: 10110 xor 11010 = 01100. Надеюсь что принцип работы операции XOR понятен.

Далее, так как шифр работает с двоичной системой исчисления, необходимо понимать что буквы это всего лишь некоторая интерпретация числа, то есть число является кодом символа некоторой таблицы кодировок. К примеру, наиболее популярные таблицы кодировок это: ANSI, ASCII и UTF(unicode). Естественно, что в каждой таблицы один и тот же символ может иметь разный код, поэтому во избежании путаницы имейте это ввиду и используйте одну и ту же кодировку при шифровании и дешифровании. Замечу, что использовать можно и свою (придуманную) кодировку. Кроме того, данный шифр может использоваться не только на компьютерах. Его можно применить и к тексту написанному на бумаге. Только перед применением надо сделать некие преобразования.

Таким образом, перед тем как осуществить шифрование необходимо перевести все символы в их однозначную числовую интерпретацию. Если Вы решили применить шифр в компьютерных системах то для вас уже существуют соответствующие кодировки, и язык программирования выбранный Вами скорее всего поддерживает явное или неявное преобразование. И вам остается только произвести над каждой парой операцию XOR. В различных языках это операция определяется по разному, приведу пример для Pasсal/Delphi/Assembler — xor, C/C++ — ^. Однако, если же Вы решили применить шифр Вернама к письменному тексту, то к примеру дайте каждой букве используемого вами алфавита, соответствующий ей порядковый номер в двоичной системе исчисления. Например, если вы используете русский алфавит (без учета буквы Ё) то это будет выглядеть так: а -> 00000, б -> 00001, в -> 00010, г -> 00011, … я -> 111111. Тем самым мы определили свою таблицу кодировки. После этого, написав сообщение и придумав ключ, преобразуйте, каждый символ в их числовое значение, соответствующее вашей таблице кодировки, и после этого осуществляйте операцию XOR над каждой соответствующей парой. Так как данный метод шифрования является симметричным, следовательно применив операция XOR каждой паре символов шифр-текста (шифрограммы) и ключа, мы получим открытый текст.

Программная реализация шифра Вернама (C/C++ и Delphi).

На основе изученного материала, я покажу как реализовать шифр Вернама на С/С++ и Pascal/Delphi. Программу целиком писать нет надобность, поэтому будем рассматривать блочную структуру, для того чтобы каждый мог без особого труда заточить ее под сви надобности. А теперь, от слов к делу.

Допусти что у нас есть строка или массив символов — oStr. Это будет открытый текст, который надо зашифровать. Теперь нам надо определить случайный ключ, длиной равной длине открытого текста. Для простоты понимания, мы воспользуемся стандартной функцией генерации случайных чисел: random для Pascal/Delphi и rand для C/C++. Но замечу сразу что это не лучший вариант, в случае если вы хотите реализовать действительно стойкий шифр. Данный пример выбран из соображения простоты. Теперь покажем как это будет выглядеть в исходном коде:

Pascal/Delphi

C/C++

Так, самое основное мы сделали. Теперь нам осталось лишь реализовать шифрование, для этого мы опишем цикл в котором мы будем посимвольно осуществлять операцию XOR. Но для этого нам понадобиться еще объявить массив приемник, в который мы поместим зашифрованный текст. Смотрим:

Pascal/Delphi

C/C++

На этом всё, реализация шифрования закончена. Надеюсь, что вы догадаетесь как реализовать дешифровку(Подсказка: те же действия нужно провести для шифрованного текста). Спасибо за внимание.

Понравилась статья? Поделиться с друзьями:
Комментариев: 17
  1. Константин

    Выдает ошибку

    [Error] Unit1.pas(69): Operator not applicable to this operand type

    на shStr[i]:=oStr[i] xor key[i];
    как исправить?

    1. lizz

      Я в дельфи 0, но попробуйте так:
      shStr[i] := Char(byte(oStr[i]) xor byte(key[i]));

      Отпишитесь, если помогло — поправим статью. :)

  2. Константин

    теперь на неё ругается
    key[i]:=Chr(random(255));

  3. Константин

    так вроде разобрался что то шифрует

    только так и не понял для чего первый кусок Delphi кода и куда его втыкнуть на какой компонент или обработчик

    и теперь вопрос как дешифруется всё это дело тоже не понял

  4. lizz

    Это симметричная система шифрования. Дешифровка происходит так же, как и шифрование: берём тот же ключ и вместо открытого текста — зашифрованный, производим те же операции, что и при шифровании, и получаем открытый текст. Как описано в статье, вся прелесть этого шифра в том, что результат полностью зависит от ключа, т.е. обычным брутфорсом его не сломать — вы получите сколько угодно много (в пределах заданной длины) вполне осмысленных текстов, в зависимости от ключа. Хоть стихи Пушкина можете расшифровать, подобрав соответствующий ключ к моему комменту. :)

  5. Dasha Kepp

    Я так и не поняла, как придумывать ключ ._______.

    1. lizz

      Никаких особых требований нет. Если вам нужен именно шифр Вернама, то есть только 3 пункта, которые описаны в статье (например, можно взять число «пи» с нужным количеством знаков после запятой в качестве ключа). Для не «боевого» применения можно этими пунктами пренебречь и выбрать вообще любой ключ (хоть стихотворение Пушкина: «Я вас любил…» или «А шутку не могу придумать я другую…», хоть текст этой статьи).

  6. я

    Зачем дважды повторять строку? Можно же написать так:
    const char *oStr=»Holo word!»;
    int len = strlen(oStr);

  7. я

    И счетчик цикла не обязательно было объявлять заранее.

    1. RENSER

      Слушайте вы, умники, человек старался, писал интересную статью, а вы прицепились к объявлению переменных. Сами хоть напишите что-нибудь???

      1. lizz

        Ну почему же, конструктивная критика всегда полезна. Тем более она написана не в агрессивном стиле и без перехода на личности. :)

  8. Nikfel

    Спасибо большое. Попробовал интересный пример. Компилировал на C++. Вот только мусор появляется при выводе ключа и зашифрованного текста, т.к. не хватает нулевого символа конца строки.
    Ключ можно формировать без функции rand или с ней надёжнее будет ключ? По идее дешифровка данных будет возможна если иметь саму программу и сам зашифрованный файл, т.е. изучив код самой программы можно будет расшифровать файл или это не так просто будет?

    1. lizz

      Ответы насчёт безопасности зависит от требований. Если говорить о каких-то серъёзных системах (или о строгом соблюдении требований к ключу), то «стандартная» функция rand скорее всего не подойдёт, т.к. обычно имеет перекосы в распределении. Но вряд ли вы собираетесь использовать какие-нибудь аппаратные генераторы случайных чисел (ГСЧ), поэтому можете хоть с rand’ом работать, хоть самому придумывать ключ. Кстати, по этой же причине серъёзные онлайн-казино также пользуются аппаратными ГСЧ.

      Насчёт возможности расшифровать текст вы заблуждаетесь. По Шеннону (если мне не изменяет память), безопасность шифра должна зависеть исключительно от безопасности ключа, а не от секретности алгоритма. И шифр Вернама — единственный (!) абсолютно безопасный при соблюдении всех 3х вышеперечисленных условий. Т.е. результат дешифровки полностью зависит от введённого ключа. При методе перебора вы можете хоть стихи Пушкина найти в зашифрованном тексте, только нужно подобрать ключ. Насколько я помню, с этим связан один куръёз: именно этот шифр удалось «вскрыть» в фильме «Пароль рыба-меч», что технически невозможно (сам я не смотрел фильм, только слышал о таком забавном факте).

      1. Nikfel

        Спасибо. Я просто хотел хранить ключ в самом exe и exe упаковывать каким-нибудь упаковщиком для защиты, но это похоже очень не надежно будет. Тогда вижу только один вариант хранения ключа — в отдельном файле и ещё раз шифровать другим ключом. А файл с ключом закрыть на доступ, т.е. при запуске exe файл с ключом будем не доступен для других программ кроме моей. Но тогда проблема будет — если прога не будет запущена то этот файл будет доступен для других программ. Или есть способ по надежнее для хранения ключа? Хранить планирую пароль от учетной записи администратора. Ещё как вариант можно запрашивать ввод ключа от пользователя, но хотелось бы без пароля обойтись.

  9. lizz

    Между безопасностью и удобством почти всегда приходится делать выбор. Как сказано выше, безопасность зашифрованного текста полностью зависит от безопасности ключа. ssh обычно хранит свои ключи просто в папочке ~/.ssh/, при этом принудительно требуя установить соответствующие права на доступ к ним. Но если вам так хочется спрятать ключ или пароль, то можно ещё посмотреть в сторону стеганографии, но и тут тоже не всё так просто и однозначно (особенно если предположить что злоумышленнику доступен алгоритм вашей программы).

    А зачем вам вообще хранить пароль администратора в зашифрованном виде? Чем принципиально будет отличаться знание ключа от знания пароля?

    Кстати, двойное шифрование — это достаточно неоднозначный ход. Можете погуглить на эту тему.

    1. Nikfel

      Спасибо. Пароль администратора шифрую из-за того чтобы потом запускать программы от имени администратора без ввода пароля. Просто сижу под учёткой пользователя, а некоторые программы запускаются только от имени администратора. Знаю что есть программа AdmiLink, которая умеет запускать программы от имени другого пользователя и она написана на языке Delphi и в ней используется шифрование из исходников DCP Crypt, но увы мне такая программа не нравится, поэтому решил написать свою на C++ для большего удобства. Решил в качестве ключа гененрировать определенный ключ по данным в системе, т.е. для расшифровки потребуется получить сведения о установленной системе Windows. Ещё как вариант есть идея ставить пароль на запуск программы, чтобы её использовать, т.е. пароль(ключ расшифровки) будет нужен для расшифровки пароля, который будет храниться в файле.

      1. lizz

        В линуксе с этим как-то проще. Можно разрешить выполнять определённые программы или команды от имени root’а без ввода пароля через sudo. По windows увы, ничего не подскажу. Хотя порт sudo (или другие альтернативы) гуглится легко, но не знаю насколько он хорош. Тем более его сырцы лежат на sourceforge, а лично у меня это ассоциируется со свалкой мёртвых проектов.

Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: