Среди огромного кол-ва алгоритмов шифрования имеется и шифр "Цезаря", который по-сути и открыл эпоху крипта в целом (Рим, 50-ые годы до нашей эры). Не нужно искать в нём скрытый смысл – его там попросту нет, а скрытие текста от посторонних глаз осуществляется обычной заменой одного символа, другим. Такие алго называют ещё "шифр с подстановкой". Ключ представляет собой обычное число, кредитный портфель которого ограничен диапазоном алфавита текущей кодировки текста (для кириллицы это Win-1251, с макс.ключом =32). Например если ключ равен единице, то на место символа "А" подставляется следующий "Б" и т.д. На рисунке ниже представлена общая схема, где в качестве ключа я выбрал значение(4):
Здесь видно, что алгоритм примитивен как амёба и в наше время источает уже запах давно непроветриваемых помещений. Однако в начальных учебных заведениях этот "труп" по-прежнему ворошат, делая ставку именно на простоту его реализации. Нужно отметить, что на основе алгоритма "Цезаря" 15-столетий спустя был придуман шифр "Виженера", роль ключа в котором играет не обычное число, а уже осмысленное слово типа "Привет" (или вообще целое предложение) с подстановочной таблицей. Но Виженер пока нам не интересен – остановимся на Цезаре..
------------------------------------------------
Пролог
Если в реальной жизни строить намного труднее, чем махая кувалдой крушить всё на своём пути, то с расшифровкой текста всё в точности, да наоборот. Попробуйте вооружившись ручкой и листом бумаги "сломать" зашифрованный даже ключом(8) текст Цезаря, не говоря уже о более "длинном" ключе типа 29. Перебор займёт у вас как-минимум пару часов, причём если в тексте не будет коротких слов как: "Я", "ОН", "ОНИ" (обычно выбирают одно, самое короткое слово из всего текста), то время увеличивается в геометрической прогрессии, и тогда вообще пиши-пропало. Для наглядности, вот так выглядит текст, закодированный ключом(4):
Как видим, текст попал в миксер и вернуть его в читабельный вид если и не составит труда, то займёт уйму времени. Чтобы не пыхтеть над этой элементарной задачей, попробуем автоматизировать процесс, написав универсальную программу для крипта и сразу декрипта алгоритма Цезаря, в зависимости от выбора пользователя (как на рис.выше, зашифровать по клавише(1), или расшифровать по двойке). Тут имеются несколько нюансов – остановимся на них подробнее..
1. Поскольку код носит демонстрационный характер, привяжем его исключительно к кириллице Win-1251. То-есть все латинские символы и знаки-препинания будем отсеивать, выбирая только русские буквы. Для этого нужно обратиться к таблице ASCII, причём обязательно к её кодировке СР-1251 (Code-Page), т.к. русский текст может быть набран и в досовском стиле ОЕМ-866 (Original Equipment Manufacturer).
Посмотрите на
Данная таблица отображает, в каком виде будет храниться русский текст в памяти нашей программы. К примеру слово "Цезарь" примет 16-тиричный вид:
Значит при шифровании нужно обязательно следить за диапазоном кириллицы
Будем считать, что строку зашифровали. А как быть с обратным преобразованием в исходный вид, ведь софт планируем писать универсальный? В этом случае, на каждой итерации цикла будем осуществлять перебор, отнимания от текущего значения единицу, поскольку при шифровании мы прибавляли неизвестное число. Здесь так-же требуется коррекция при выходе символа за границы 40h-байтного блока кириллицы. Только теперь нужно будет прибавлять не код символа "А", а просто константу 40h по такому алго:
Метаморфозы символов (переход из одной формы в другую) удобно наблюдать в отладчике, который является глазами и руками любого реверсера. Кроме того, нужно предусмотреть и выход из цикла расшифровки по какой-нибудь клавише. Задачи такого характера решает функция GetAsyncKeyState(). На входе она принимает всего один аргумент с кодом виртуальной клавиши (для пробела "Space" это 20h), а на выходе возвращает в регистре EAX значение, в котором старший бит информирует о нажатом состоянии указанной клавиши, а младший – о нажатии и отпускании. Если на момент вызова этой функции юзер вообще не тискал клаву (её код запоминается в системной очереди-сообщений клавиатуры), то в регистре EAX получим нуль:
2. Другим немало/важным моментом является кириллица в консоли Win, поскольку изначально она заточена под досовскую кодировку OEM-866. Если не принять каких-либо мер, то загрузив файл 1251 в окно консоли, вместо символов получим непонятный мусор (крякозябры). На своём-то узле мы сможем заточить её под кириллицу, а как быть с удалённой машиной, куда попадёт наш код? Вот две ветки реестра, в которых скрыты рычаги управления дефолтным видом командной строки:
• HKCU\Console – глобальные свойства окна интерпретатора cmd.exe;
• HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont – добавление своих шрифтов.
Система предлагает нам две API-функции для смены кодировки, но без дополнительных "танцев с бубном" они не оказывают должного воздействия на консоль, хотя и отрабатывают исправно без ошибки:
Оказывается эти функции требуют консольного "True-Type" шрифта с кириллицей, а по-умолчанию, для всех запускаемых программ там установлен "точечный шрифт" без поддержки русского языка. Таким образом мало сменить кодировку на Win-1251, так ещё нужно поменять и шрифт ком.строки. А ведь редиска Microsoft этого даже не обозначила в своей документации на MSDN, в результате чего подобные глюки приходится отлавливать опытным путём.
На системах Win-XP включительно, смена шрифта из своего приложения представляло собой нерешаемую проблему. Зато начиная с Висты, в библиотеку Kernel32.dll была добавлена функция SetCurrentConsoleFontEx(), которая в качестве аргумента ждёт указатель на структуру "CONSOLE_FONT_INFOEX", где и задаются свойства необходимого шрифта. Пример этой структуры с поддерживающим кириллицу векторным шрифтом "Lucida Console", представлен ниже:
Размер этой структуры должен быть строго 54h байтов (указывается в первом члене), иначе функция будет возвращать ошибку
Ну и теперь немного о самом алгоритме программы..
Значит предлагаем юзеру выбрать файл для шифрования или обратного процесса расшифровки. Получаем его размер и выделив память, читаем данные в буфер. Дальше запрашиваем действие с файлом, и в зависимости от выбора, зовём свои процедуры "Crypt" или "DeCrypt". Если это шифрование, то дополнительно запрашиваем у юзера ключ в диапазоне алфавита кириллицы 1..32, после чего шифруем до самого подвала и сбрасываем результат в лог-файл Crypt.txt.
На всякий/пожарный, при вводе ключа нужно предусмотреть "защиту от дурака" на случай, если юзер введёт ключ больше чем 32, например 100. Поскольку 32 кратно двум, мы просто берём остаток от деления на 32 логикой
Позже можно будет проверить функционал, обратно подсунув программе этот-же зашифрованный файл Crypt.txt, чтобы прожка попыталась его расшифровать. В процессе декрипта, даём юзеру возможность осмотреться и в случае попадания в яблочко, нажать пробел для останова. Реализуем это посредством скважности вывода данных на консоль = 5-сек через Sleep(). Остальные мелочи прокомментированы в коде, надеюсь разберётесь – вот пример:
Эпилог
Не смотря на то, что алгоритмы Цезаря и Виженера уже давно покрылись мхом, они несут в себе основы шифрования данных. Как-нибудь в следующий раз рассмотрим и Виженера, с его таблицей подстановок. Это уже двойное шифрование, когда по маске ключа выбирается символ из специальной таблицы. Здесь интерес представляют не сами алгоритмы, а реализация их в виде программ для наработки собственного скилла. Так-что несмотря ни на что, доминанта пользы от этого дела, всё-таки присутствует. В скрепке лежит демонстрационный исполняемый файл этого кода, который позволит как зашифровать, так и расшифровать шифр Цезаря. Удачи и до скорого.
Здесь видно, что алгоритм примитивен как амёба и в наше время источает уже запах давно непроветриваемых помещений. Однако в начальных учебных заведениях этот "труп" по-прежнему ворошат, делая ставку именно на простоту его реализации. Нужно отметить, что на основе алгоритма "Цезаря" 15-столетий спустя был придуман шифр "Виженера", роль ключа в котором играет не обычное число, а уже осмысленное слово типа "Привет" (или вообще целое предложение) с подстановочной таблицей. Но Виженер пока нам не интересен – остановимся на Цезаре..
------------------------------------------------
Пролог
Если в реальной жизни строить намного труднее, чем махая кувалдой крушить всё на своём пути, то с расшифровкой текста всё в точности, да наоборот. Попробуйте вооружившись ручкой и листом бумаги "сломать" зашифрованный даже ключом(8) текст Цезаря, не говоря уже о более "длинном" ключе типа 29. Перебор займёт у вас как-минимум пару часов, причём если в тексте не будет коротких слов как: "Я", "ОН", "ОНИ" (обычно выбирают одно, самое короткое слово из всего текста), то время увеличивается в геометрической прогрессии, и тогда вообще пиши-пропало. Для наглядности, вот так выглядит текст, закодированный ключом(4):
Как видим, текст попал в миксер и вернуть его в читабельный вид если и не составит труда, то займёт уйму времени. Чтобы не пыхтеть над этой элементарной задачей, попробуем автоматизировать процесс, написав универсальную программу для крипта и сразу декрипта алгоритма Цезаря, в зависимости от выбора пользователя (как на рис.выше, зашифровать по клавише(1), или расшифровать по двойке). Тут имеются несколько нюансов – остановимся на них подробнее..
1. Поскольку код носит демонстрационный характер, привяжем его исключительно к кириллице Win-1251. То-есть все латинские символы и знаки-препинания будем отсеивать, выбирая только русские буквы. Для этого нужно обратиться к таблице ASCII, причём обязательно к её кодировке СР-1251 (Code-Page), т.к. русский текст может быть набран и в досовском стиле ОЕМ-866 (Original Equipment Manufacturer).
Посмотрите на
Ссылка скрыта от гостей
– диапазон кириллицы в ней занимает ровно 40h байт, от C0h
(заглавная "А") и вплоть до последнего FFh
(прописная "я"). Пара ёжиков "Ё/ё" с кодами A8/В8h
отбилась от стада, и чтобы не усложнять программный фильтр, мы просто оставим их как-есть и будем считать знаками-препинания (они всё-равно встречаются редко):Данная таблица отображает, в каком виде будет храниться русский текст в памяти нашей программы. К примеру слово "Цезарь" примет 16-тиричный вид:
D6.E5.E7.E0.F0.FC
. Что получится, если мы закодируем эту строку ключом(8)? Поскольку нужно будет прибавлять к каждому коду-символа значение(8), то большинство из этих букв останутся внутри данного 40h-байтного блока кириллицы. А вот последний символ "ь" улетит в штрафбат и его ASCII-код примет запрещённое значение(4), т.к. FCh+08h=04h
. Вообще-то получим 104h
, но мы имеем дело с байтами (макс.FFh), поэтому не учитываем перенос.Значит при шифровании нужно обязательно следить за диапазоном кириллицы
C0h..FFh
, и если символ вылетает за его пределы, то прибавляя к нему код первой "А"=С0h, отправлять обратно внутрь данного блока. Вот пример такого фильтра:
C-подобный:
mov bl,[key] ;// BL = ключ шифрования
@@: lodsb ;// AL = очередной байт из буфера
cmp al,'А' ;// проверить его на первую букву кирилицы
jb @next ;// если меньше, значит это знак-препинания – игнорируем
add al,bl ;// иначе: шифрование и прибавить к символу ключ
cmp al,'А' ;// проверить на переполнение
ja @next ;// норма, если больше (в диапазоне А..я) Jump-Above
add al,'А' ;// иначе: прибавить код символа "А" (коррекция)
@next: stosb ;// перезаписать зашифрованный символ в буфер!
loop @b ;// прогнать цикл ECX-раз..
Будем считать, что строку зашифровали. А как быть с обратным преобразованием в исходный вид, ведь софт планируем писать универсальный? В этом случае, на каждой итерации цикла будем осуществлять перебор, отнимания от текущего значения единицу, поскольку при шифровании мы прибавляли неизвестное число. Здесь так-же требуется коррекция при выходе символа за границы 40h-байтного блока кириллицы. Только теперь нужно будет прибавлять не код символа "А", а просто константу 40h по такому алго:
C-подобный:
@@: lodsb ;// AL = очередной/зашифрованный байт из буфера
cmp al,'А' ;// проверить на знак-препинания,
jb @skip ;// ..пропустить, если он.
dec al ;// иначе: AL-1 (брут в обратную сторону)
cmp al,'А' ;// проверить выход символа за пределы блока
jae @skip ;// пропустить, если больше/равно (Jump-Above-Equal)
add al,40h ;// иначе: отправить символ в диапазон кирилицы
@skip: stosb ;// перезаписать его в буфере!
loop @b ;// крутим цикл по всей строке..
Метаморфозы символов (переход из одной формы в другую) удобно наблюдать в отладчике, который является глазами и руками любого реверсера. Кроме того, нужно предусмотреть и выход из цикла расшифровки по какой-нибудь клавише. Задачи такого характера решает функция GetAsyncKeyState(). На входе она принимает всего один аргумент с кодом виртуальной клавиши (для пробела "Space" это 20h), а на выходе возвращает в регистре EAX значение, в котором старший бит информирует о нажатом состоянии указанной клавиши, а младший – о нажатии и отпускании. Если на момент вызова этой функции юзер вообще не тискал клаву (её код запоминается в системной очереди-сообщений клавиатуры), то в регистре EAX получим нуль:
C-подобный:
invoke GetAsyncKeyState,0x20 ;// парсим клавишу "Space"
or eax,eax ;// проверить EAX на нуль
jnz @stop ;// если No-Zero, значит был нажат пробел.
2. Другим немало/важным моментом является кириллица в консоли Win, поскольку изначально она заточена под досовскую кодировку OEM-866. Если не принять каких-либо мер, то загрузив файл 1251 в окно консоли, вместо символов получим непонятный мусор (крякозябры). На своём-то узле мы сможем заточить её под кириллицу, а как быть с удалённой машиной, куда попадёт наш код? Вот две ветки реестра, в которых скрыты рычаги управления дефолтным видом командной строки:
• HKCU\Console – глобальные свойства окна интерпретатора cmd.exe;
• HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont – добавление своих шрифтов.
Система предлагает нам две API-функции для смены кодировки, но без дополнительных "танцев с бубном" они не оказывают должного воздействия на консоль, хотя и отрабатывают исправно без ошибки:
C-подобный:
invoke SetConsoleOutputCP,1251 ;// для вывода на консоль "STD_OUTPUT_HANDLE"
invoke SetConsoleCP,1251 ;// для ввода с клавы "STD_INPUT_HANDLE"
Оказывается эти функции требуют консольного "True-Type" шрифта с кириллицей, а по-умолчанию, для всех запускаемых программ там установлен "точечный шрифт" без поддержки русского языка. Таким образом мало сменить кодировку на Win-1251, так ещё нужно поменять и шрифт ком.строки. А ведь редиска Microsoft этого даже не обозначила в своей документации на MSDN, в результате чего подобные глюки приходится отлавливать опытным путём.
На системах Win-XP включительно, смена шрифта из своего приложения представляло собой нерешаемую проблему. Зато начиная с Висты, в библиотеку Kernel32.dll была добавлена функция SetCurrentConsoleFontEx(), которая в качестве аргумента ждёт указатель на структуру "CONSOLE_FONT_INFOEX", где и задаются свойства необходимого шрифта. Пример этой структуры с поддерживающим кириллицу векторным шрифтом "Lucida Console", представлен ниже:
C-подобный:
struct CONSOLE_FONT_INFOEX
cbSize dd sizeof.CONSOLE_FONT_INFOEX
nFont dd 5 ;// индекс шрифта в таблице шрифтов
FontWidth dw 7 ;// ширина символов
FontHight dw 12 ;// высота, итого = 12x7 пикселей
FontFamily dd 54 ;// семейство шрифтов
FontWeight dd 600 ;// толщина 100...1000 (попугаев)
FaceName du 'Lucida Console',0 ;// Unicode имя шрифта
rw 32-15 ;// байты выравнивания (резерв)
ends
Размер этой структуры должен быть строго 54h байтов (указывается в первом члене), иначе функция будет возвращать ошибку
0x57 "Неверный аргумент"
. Чтобы получить все эти данные, мне пришлось сначала мышью настроить консоль через свойства её окна, после чего вызвать функцию GetCurrentConsoleFontEx(), которая заполнила эту структуру текущими настройками. Кстати эти функции читают и пишут в реестр, по указанной ветке [HKCU\Console].Ну и теперь немного о самом алгоритме программы..
Значит предлагаем юзеру выбрать файл для шифрования или обратного процесса расшифровки. Получаем его размер и выделив память, читаем данные в буфер. Дальше запрашиваем действие с файлом, и в зависимости от выбора, зовём свои процедуры "Crypt" или "DeCrypt". Если это шифрование, то дополнительно запрашиваем у юзера ключ в диапазоне алфавита кириллицы 1..32, после чего шифруем до самого подвала и сбрасываем результат в лог-файл Crypt.txt.
На всякий/пожарный, при вводе ключа нужно предусмотреть "защиту от дурака" на случай, если юзер введёт ключ больше чем 32, например 100. Поскольку 32 кратно двум, мы просто берём остаток от деления на 32 логикой
AND EAX,31
и получаем значение в нужном диапазоне.Позже можно будет проверить функционал, обратно подсунув программе этот-же зашифрованный файл Crypt.txt, чтобы прожка попыталась его расшифровать. В процессе декрипта, даём юзеру возможность осмотреться и в случае попадания в яблочко, нажать пробел для останова. Реализуем это посредством скважности вывода данных на консоль = 5-сек через Sleep(). Остальные мелочи прокомментированы в коде, надеюсь разберётесь – вот пример:
C-подобный:
format pe console
include 'win32ax.inc'
entry start
;//--------
.data
struct CONSOLE_FONT_INFOEX
cbSize dd sizeof.CONSOLE_FONT_INFOEX
nFont dd 5 ;// индекс шрифта в таблице шрифтов
FontWidth dw 7 ;// ширина символов
FontHight dw 12 ;// высота = 12x7
FontFamily dd 54 ;// семейство шрифтов
FontWeight dd 600 ;// толщина 100...1000
FaceName du 'Lucida Console',0 ;// Unicode имя шрифта
rw 32-15 ;// байты выравнивания (резерв)
ends
cfi CONSOLE_FONT_INFOEX
capt db '"Caesar cipher" ver 0.1',0
hello db " (\___/) ",10
db " (='.'=) ",10
db " E[:]|||[:]З",10
db ' (")_(") ',10
db 10
db ' Открыть файл: ',0
error db ' Ошибка! Не правильный выбор!',0
info db ' OK! Размер..: %d байт' ,10
db ' -------------------------',10,0
job db 10,' ----------------------'
db 10,' Выбор задачи:'
db 10,' * Зашифровать = 1'
db 10,' * Расшифровать = 2',10
db 10,' * Команда = ',0
key db ' * Ключ [1..32] = ',0
line db 10,' ----------------------',10,0
writeOk db 10,' ----------------------'
db 10,' OK! Смотри файл "Crypt.txt"',0
brute db 10,' ==== Ключ: %02d. Жми пробел для останова ======='
db 10,' ==============================================',10,0
fName db 'Crypt.txt',0
frmtS db '%s',0 ;// спецификатор строки для scanf()
frmtD db '%d',0 ;// спецификатор числа DEC
fileBuff dd 0 ;// под адрес выделенной памяти
jobInp dd 0 ;// флаг выбора задачи
keyInp dd 0 ;// ключ шифрования
counter dd 1 ;// длина перебора (алфавита кирицы)
inHndl dd 0 ;// хэндл открытого файла
outHndl dd 0 ;// хэндл файла для записи
fSize dd 0 ;// размер файла с данными
buff db 0
;//--------
.code
start:
;//--- Ставим шрифт: "Lucida Console", 12x7, Normal
invoke GetStdHandle,STD_OUTPUT_HANDLE
invoke SetCurrentConsoleFontEx,eax,0,cfi
;//--- Обзываем консоль и кодировка Win-1251 (кирилица)
invoke SetConsoleTitle,capt
invoke SetConsoleOutputCP,1251 ;// для вывода на консоль
invoke SetConsoleCP,1251 ;// для ввода с клавы
;//--- Запрос на выбор файла
cinvoke printf,hello
cinvoke scanf,frmtS,buff
;//--- Пытаемся открыть выбранный файл
invoke _lopen,buff,OF_READWRITE
mov [inHndl],eax ;// дескриптор
cmp eax,-1 ;// ошибка?
jne @ok ;// нет..
cinvoke printf,error ;// иначе: мессага,
jmp @exit ;// ..и на выход.
;//--- ОК! Размер и выделение памяти под файл
@ok: invoke GetFileSize,eax,0
mov [fSize],eax
invoke VirtualAlloc,0,eax,MEM_COMMIT,PAGE_READWRITE
mov [fileBuff],eax
cinvoke printf,info,[fSize]
;//--- Чтение открытого файла в буфер, и вывод его на консоль
invoke _lread,[inHndl],[fileBuff],[fSize]
cinvoke printf,[fileBuff]
;//--- Запрашиваем действие с файлом: Crypt(1), DeCrypt(2)
@job: cinvoke printf,job
cinvoke scanf,frmtD,jobInp
;//--- Проверяем выбор действия
cmp [jobInp],1 ;//
je @01 ;// если нажата клавиша #1
cmp [jobInp],2 ;//
je @02 ;// если #2
cinvoke printf,error ;// иначе: ошибка,
jmp @exit ;// ...и на выход.
@01: stdcall GetCrypt ;// зовём процедуру шифрования!
jmp @exit ;// ...после чего на выход.
@02: stdcall GetDeCrypt ;// зовём процедуру брута!
@exit:
cinvoke scanf,frmtS,buff ;//<--- КОНЕЦ ПРОГРАММЫ -------
cinvoke exit,0 ;//
;//ннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннн
;//--- Юзер выбрал(1) = шифрование
proc GetCrypt
cinvoke printf,key ;//
cinvoke scanf,frmtD,keyInp ;// запросить ключ 1..32
mov ebx,[keyInp] ;// EBX = ключ
and ebx,31 ;// взять остаток от 32 (рус.алфавит)
mov ecx,[fSize] ;// ECX = длина файла (цикла)
mov esi,[fileBuff] ;// ESI = источник данных
mov edi,esi ;// EDI = приёмник (он-же)
@@: lodsb ;// AL = очередной байт из ESI
cmp al,'А' ;// проверить его на первую букву кирилицы
jb @next ;// если меньше, значит это знак-препинания
add al,bl ;// иначе: прибавить к символу ключ
cmp al,'А' ;// проверить на переполнение
ja @next ;// норма, если больше (в диапазоне А..я)
add al,'А' ;// иначе: коррекция
@next: stosb ;// перезаписать символ в буфере
loop @b ;// прогнать цикл ECX-раз..
cinvoke printf,line ;// (линия-разделитель)
cinvoke printf,frmtS,[fileBuff] ;// Показать результат из буфера!
;//--- Сбрасываем зашифрованные данные в файл "Crypt.txt"
invoke _lcreat,fName,0 ;// создать его
push eax ;// дескриптор
invoke _lwrite,eax,[fileBuff],[fSize] ;// записать в него данные
pop eax ;//
invoke _lclose,eax ;// закрыть файл.
cinvoke printf,frmtS,writeOk ;// мессага ОК!
ret ;// на выход
endp
;//ннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннн
;//--- Юзер выбрал(2) = брут зашифрованного файла
proc GetDeCrypt
@find:
cinvoke flushall ;// очистить буферы всех сообщений
mov ecx,[fSize] ;// длина файла и цикла
mov esi,[fileBuff];// источник,
mov edi,esi ;// ..он-же приёмник.
@@: lodsb ;// AL = очередной байт из ESI
cmp al,'А' ;// проверить на знак-препинания,
jb @skip ;// ..пропустить, если он.
dec al ;// иначе: AL-1 (брут в обратную сторону)
cmp al,'А' ;// проверить выход символа за пределы
jae @skip ;// пропустить, если больше/равно
add al,40h ;// иначе: отправить символ в диапазон кирилицы
@skip: stosb ;// перезаписать его в буфере!
loop @b ;// крутим цикл ECX-раз..
cinvoke printf,brute,[counter] ;// покажем текущий ключ,
cinvoke printf,frmtS,[fileBuff] ;// ...и что получилось.
invoke GetAsyncKeyState,0x20 ;// проверить на клавишу "Space"
or eax,eax ;//
jnz @stop ;// если в EAX не нуль, значит пробел.
invoke Sleep,5000 ;// пауза, чтобы осмотреться..
inc [counter] ;// следующий ключ
cmp [counter],33 ;// по всему алфавиту прошлись?
jnz @find ;// ...повторить, если нет.
@stop: ret ;// выход из процедуры.
endp
;//---------
section '.idata' import data readable writeable
library msvcrt,'msvcrt.dll',kernel32,'kernel32.dll',user32,'user32.dll'
import msvcrt, printf,'printf',scanf,'scanf',\
gets,'gets',exit,'exit',flushall,"_flushall"
include 'api\kernel32.inc'
include 'api\user32.inc'
Эпилог
Не смотря на то, что алгоритмы Цезаря и Виженера уже давно покрылись мхом, они несут в себе основы шифрования данных. Как-нибудь в следующий раз рассмотрим и Виженера, с его таблицей подстановок. Это уже двойное шифрование, когда по маске ключа выбирается символ из специальной таблицы. Здесь интерес представляют не сами алгоритмы, а реализация их в виде программ для наработки собственного скилла. Так-что несмотря ни на что, доминанта пользы от этого дела, всё-таки присутствует. В скрепке лежит демонстрационный исполняемый файл этого кода, который позволит как зашифровать, так и расшифровать шифр Цезаря. Удачи и до скорого.