Реализация алгоритма шифрования ГОСТ 28147-89 на VHDL
Добавлено: Пн июн 18, 2012 12:13:25
Изначально меня послали на этот сайт "здесь много материала". угу. в разделе обучалки целых две статьи по плисам. и обе немного не по тому что мне надо.
ладно. залез на форум. там много-много тем, которые практически мгновенно тонут. по этому углубился (углупился) в книги. на русском языке - там всё совсем грустно. по организации форума - не думаю что место совсем новичку писать, и тем более не в этой теме.
ГОСТ 28147-89, как и любой другой симметричный алгоритм шифрования, состоит из простых операций.
Это – сдвиг, замена, суммирование по модулю 2, суммирование по модулю 2^32, объявление и присваивание переменных.
Рассмотрим создание проекта, осуществляющего шифрование блоков сообщения согласно алгоритму ГОСТ 28147-89:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;
Это понадобится для реализации функции сдвига, а также других функций.
Объявление переменных:
entity gost is
port
(
N1 : in std_logic_vector(31 downto 0)
N2 : in std_logic_vector(31 downto 0) ;
N1_out : out std_logic_vector(31 downto 0);
N2_out : out std_logic_vector(31 downto 0)
);
end gost;
std_logic_vector – это массив переменных.
(31 downto 0) – это размер массива.
Мы только что объявили, что у нас 2 входных порта N1 и N2 и два выходных порта N1_out и N2_out.
Согласно ГОСТ 28147-89 – с внешним миром сообщаются 2 порта, которые работают и на вход и на выход одновременно. Но при этом индикации о том, что в конкретный момент данных в этом буфере нет. Поэтому возможны ситуации, когда на одном и том же порту в разные моменты времени будут исходные данные, промежуточный результат или уже зашифрованные данные. Программа постоянно читает данные с этого порта, передает их дальше и происходит зацикливание. Чтобы избежать ситуации бесконечного цикла в программе были введены раздельные порты для входных и выходных данных
внутри - используется unsigned вместо std_logic_vector - так как для некоторых операций типа сдвига и сложения - требуют именно этого типа переменных. наружу отдается std_logic_vector
Переменные:
ключи шифрования
Signal X0 : unsigned(31 downto 0) := "01001111010010100001110010101010";
Signal X1 : unsigned(31 downto 0) := "01001111010010100001110010101010";
Signal X2 : unsigned(31 downto 0) := "01001111010010100001110010101010";
Signal X3 : unsigned(31 downto 0) := "01001111010010100001110010101010";
Signal X4 : unsigned(31 downto 0) := "01001111010010100001110010101010";
Signal X5 : unsigned(31 downto 0) := "01001111010010100001110010101010";
Signal X6 : unsigned(31 downto 0) := "01001111010010100001110010101010";
Signal X7 : unsigned(31 downto 0) := "01001111010010100001110010101010";
ключи шифрования пока задаются явно, и одинаковые, но их можно менять, не суть в них.
Согласно ГОСТ 28147-89– 256 бит ключа разбивается на 8 частей по 32 бита, которые храниться в X0-X7.
Signal SM1 : unsigned(31 downto 0);
Signal SM2 : unsigned(31 downto 0);
Это два сумматора. Один работает по модулю 2, другой по модулю 2^32
Signal K : unsigned(31 downto 0);
Signal R : unsigned(31 downto 0);
K – Это модуль, где происходит операция замены текста по заранее определенным таблицам.
R – узел смещения.
Текст цикла шифрования.
sm1 <= n1 and x0;
Сложение по модулю 2^32. В этой операции мы складываем половину зашифрованных данных с первым ключом.
Затем данные подаются на таблицу замен.
process
begin
case sm1(31 downto 28) is
when "0000" => k(31 downto 28) <= "0100"; -- 0 > 4
when "0001" => k(31 downto 28) <= "1010"; -- 1 > A
when "0010" => k(31 downto 28) <= "1001"; -- 2 > 9
when "0011" => k(31 downto 28) <= "0011"; -- 3 > 2
when "0100" => k(31 downto 28) <= "1101"; -- 4 > D
when "0101" => k(31 downto 28) <= "1000"; -- 5 > 8
when "0110" => k(31 downto 28) <= "0000"; -- 6 > 0
when "0111" => k(31 downto 28) <= "1110"; -- 7 > E
when "1000" => k(31 downto 28) <= "0110"; -- 8 > 6
when "1001" => k(31 downto 28) <= "1011"; -- 9 > B
when "1010" => k(31 downto 28) <= "0001"; -- A > 1
when "1011" => k(31 downto 28) <= "1100"; -- B > C
when "1100" => k(31 downto 28) <= "0110"; -- C > 7
when "1101" => k(31 downto 28) <= "1111"; -- D > F
when "1110" => k(31 downto 28) <= "0101"; -- E > 5
when "1111" => k(31 downto 28) <= "1001"; -- F > 9
when others => sm1(31 downto 28) <= "1001";
end case;
end process;
Данные разбиваются на 8 кусков по 4 бита. Каждый кусок заменяется согласно таблице, использующейся в криптографических приложениях ЦБ РФ. Это увеличивает стойкость шифрования к некоторым видам атак.
Цикл case должен быть в рамках цикла process begin …. end process;
Таковы особенности данного языка программирования.
когда вся реализация будет - процесс распространить на весь алгорим.
r <= k(10 downto 0) & k(31 downto 11);
Перемешивание данных. Данная операция затрудняет криптоанализ.
sm2 <= r xor n2;
Остается последний сумматор sm2 в котором складывается часть открытого текста с уже зашифрованными данными.
n2_out <= n1;
n1_out <= sm2;
end gost;
На этом текст цикла зашифрования заканчивается. Цикл расшифрования идентичен циклу шифрования.
Режим имитовставки идентичен режиму шифрования, за исключением количества циклов, и того что блоки данных суммируются по модулю 2^32.
до сюда - это текст диплома.
в ходе отладки были произведены некоторые изменения.
1. таблицы замен были вынесены в отдельную переменную. делать сиё просто, по этому не буду описывать как. хотя если надо..
2. введены задержки.
wait for 10 ns;
почему не используются отдельные функции? типа передать раздачу ключей наружу и таблицу замен тоже наружу? это еще + сколько то то там тактов на каждый раунд. что приведет к потере скорости раза в полтора. а нам нужна очень быстрая реализация.
после каждой комманды которая требует выполнения предыдущей. на один раунд шифрования где то 6-7 тактов уходит. на 16 циклов шифрования одного блока данных (имитовставка) - 99. в принципе можно оптимизировать на один так, но лень, а так же не совсем верно идеологически.
т.е. скорость получалась до 64 мегабит в секунду в режиме имитовставки на частоте в 100 мегагерц (плата позволяет до 324 мегагерц работать) и 32 мегабита в режиме простого шифрования/расшифрования.
т.е. разогнав плату до 300 мегагерц мы получаем 96 мегабит в режиме шифрования/расшифрования простой замены - что вполне достаточно для большинства сетей. в принципе для режима простой замены можно провести распарралеливание обработки данных. но это скорее тема отдельного исследования.
проблема с задержками - 1. они не везде документированы. т.е. до задержек я дошел изучая англоязычную литературу на тему. русскоязычной с удобными программами - нет.
англоязычной для совсем нубов - есть.
т.е. у меня было две книги на английском языке - задача + пример кода для решения этой задачи. к сожалению в какой то момент там тоже начались косяки с работоспособностью программ. т.е. там еще требуется какие то телодвижения которых прямо не указано в тексте.
2. с задержками невозможно проверять синтаксис. таковы особенности реализации среды программирования. т.е. карту реализации, занятость кристалла и прочее не проверить. оно не работает в таком виде в режиме отладки синтаксиса. просто закомментировать задержки тоже не вариант - он будет ругаться на использование одних и тех же переменных в разных местах. что не есть хорошо.
я фактически полдня убил на то что бы поискать альтернативную их реализацию. знай я сразу что их так реализовывать - недели две-три точно бы сэкономил.
то что требуется к практической реализации.
зациклить программу так что бы к ней непрерывным потоком шли данные на вход и данные на выход забирались. в дипломе это не требовалось, да и вообще были проблемы с отладкой.
тест программы не прикладывается -по этому позже выложу её.
ладно. залез на форум. там много-много тем, которые практически мгновенно тонут. по этому углубился (углупился) в книги. на русском языке - там всё совсем грустно. по организации форума - не думаю что место совсем новичку писать, и тем более не в этой теме.
ГОСТ 28147-89, как и любой другой симметричный алгоритм шифрования, состоит из простых операций.
Это – сдвиг, замена, суммирование по модулю 2, суммирование по модулю 2^32, объявление и присваивание переменных.
Рассмотрим создание проекта, осуществляющего шифрование блоков сообщения согласно алгоритму ГОСТ 28147-89:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;
Это понадобится для реализации функции сдвига, а также других функций.
Объявление переменных:
entity gost is
port
(
N1 : in std_logic_vector(31 downto 0)
N2 : in std_logic_vector(31 downto 0) ;
N1_out : out std_logic_vector(31 downto 0);
N2_out : out std_logic_vector(31 downto 0)
);
end gost;
std_logic_vector – это массив переменных.
(31 downto 0) – это размер массива.
Мы только что объявили, что у нас 2 входных порта N1 и N2 и два выходных порта N1_out и N2_out.
Согласно ГОСТ 28147-89 – с внешним миром сообщаются 2 порта, которые работают и на вход и на выход одновременно. Но при этом индикации о том, что в конкретный момент данных в этом буфере нет. Поэтому возможны ситуации, когда на одном и том же порту в разные моменты времени будут исходные данные, промежуточный результат или уже зашифрованные данные. Программа постоянно читает данные с этого порта, передает их дальше и происходит зацикливание. Чтобы избежать ситуации бесконечного цикла в программе были введены раздельные порты для входных и выходных данных
внутри - используется unsigned вместо std_logic_vector - так как для некоторых операций типа сдвига и сложения - требуют именно этого типа переменных. наружу отдается std_logic_vector
Переменные:
ключи шифрования
Signal X0 : unsigned(31 downto 0) := "01001111010010100001110010101010";
Signal X1 : unsigned(31 downto 0) := "01001111010010100001110010101010";
Signal X2 : unsigned(31 downto 0) := "01001111010010100001110010101010";
Signal X3 : unsigned(31 downto 0) := "01001111010010100001110010101010";
Signal X4 : unsigned(31 downto 0) := "01001111010010100001110010101010";
Signal X5 : unsigned(31 downto 0) := "01001111010010100001110010101010";
Signal X6 : unsigned(31 downto 0) := "01001111010010100001110010101010";
Signal X7 : unsigned(31 downto 0) := "01001111010010100001110010101010";
ключи шифрования пока задаются явно, и одинаковые, но их можно менять, не суть в них.
Согласно ГОСТ 28147-89– 256 бит ключа разбивается на 8 частей по 32 бита, которые храниться в X0-X7.
Signal SM1 : unsigned(31 downto 0);
Signal SM2 : unsigned(31 downto 0);
Это два сумматора. Один работает по модулю 2, другой по модулю 2^32
Signal K : unsigned(31 downto 0);
Signal R : unsigned(31 downto 0);
K – Это модуль, где происходит операция замены текста по заранее определенным таблицам.
R – узел смещения.
Текст цикла шифрования.
sm1 <= n1 and x0;
Сложение по модулю 2^32. В этой операции мы складываем половину зашифрованных данных с первым ключом.
Затем данные подаются на таблицу замен.
process
begin
case sm1(31 downto 28) is
when "0000" => k(31 downto 28) <= "0100"; -- 0 > 4
when "0001" => k(31 downto 28) <= "1010"; -- 1 > A
when "0010" => k(31 downto 28) <= "1001"; -- 2 > 9
when "0011" => k(31 downto 28) <= "0011"; -- 3 > 2
when "0100" => k(31 downto 28) <= "1101"; -- 4 > D
when "0101" => k(31 downto 28) <= "1000"; -- 5 > 8
when "0110" => k(31 downto 28) <= "0000"; -- 6 > 0
when "0111" => k(31 downto 28) <= "1110"; -- 7 > E
when "1000" => k(31 downto 28) <= "0110"; -- 8 > 6
when "1001" => k(31 downto 28) <= "1011"; -- 9 > B
when "1010" => k(31 downto 28) <= "0001"; -- A > 1
when "1011" => k(31 downto 28) <= "1100"; -- B > C
when "1100" => k(31 downto 28) <= "0110"; -- C > 7
when "1101" => k(31 downto 28) <= "1111"; -- D > F
when "1110" => k(31 downto 28) <= "0101"; -- E > 5
when "1111" => k(31 downto 28) <= "1001"; -- F > 9
when others => sm1(31 downto 28) <= "1001";
end case;
end process;
Данные разбиваются на 8 кусков по 4 бита. Каждый кусок заменяется согласно таблице, использующейся в криптографических приложениях ЦБ РФ. Это увеличивает стойкость шифрования к некоторым видам атак.
Цикл case должен быть в рамках цикла process begin …. end process;
Таковы особенности данного языка программирования.
когда вся реализация будет - процесс распространить на весь алгорим.
r <= k(10 downto 0) & k(31 downto 11);
Перемешивание данных. Данная операция затрудняет криптоанализ.
sm2 <= r xor n2;
Остается последний сумматор sm2 в котором складывается часть открытого текста с уже зашифрованными данными.
n2_out <= n1;
n1_out <= sm2;
end gost;
На этом текст цикла зашифрования заканчивается. Цикл расшифрования идентичен циклу шифрования.
Режим имитовставки идентичен режиму шифрования, за исключением количества циклов, и того что блоки данных суммируются по модулю 2^32.
до сюда - это текст диплома.
в ходе отладки были произведены некоторые изменения.
1. таблицы замен были вынесены в отдельную переменную. делать сиё просто, по этому не буду описывать как. хотя если надо..
2. введены задержки.
wait for 10 ns;
почему не используются отдельные функции? типа передать раздачу ключей наружу и таблицу замен тоже наружу? это еще + сколько то то там тактов на каждый раунд. что приведет к потере скорости раза в полтора. а нам нужна очень быстрая реализация.
после каждой комманды которая требует выполнения предыдущей. на один раунд шифрования где то 6-7 тактов уходит. на 16 циклов шифрования одного блока данных (имитовставка) - 99. в принципе можно оптимизировать на один так, но лень, а так же не совсем верно идеологически.
т.е. скорость получалась до 64 мегабит в секунду в режиме имитовставки на частоте в 100 мегагерц (плата позволяет до 324 мегагерц работать) и 32 мегабита в режиме простого шифрования/расшифрования.
т.е. разогнав плату до 300 мегагерц мы получаем 96 мегабит в режиме шифрования/расшифрования простой замены - что вполне достаточно для большинства сетей. в принципе для режима простой замены можно провести распарралеливание обработки данных. но это скорее тема отдельного исследования.
проблема с задержками - 1. они не везде документированы. т.е. до задержек я дошел изучая англоязычную литературу на тему. русскоязычной с удобными программами - нет.
англоязычной для совсем нубов - есть.
т.е. у меня было две книги на английском языке - задача + пример кода для решения этой задачи. к сожалению в какой то момент там тоже начались косяки с работоспособностью программ. т.е. там еще требуется какие то телодвижения которых прямо не указано в тексте.
2. с задержками невозможно проверять синтаксис. таковы особенности реализации среды программирования. т.е. карту реализации, занятость кристалла и прочее не проверить. оно не работает в таком виде в режиме отладки синтаксиса. просто закомментировать задержки тоже не вариант - он будет ругаться на использование одних и тех же переменных в разных местах. что не есть хорошо.
я фактически полдня убил на то что бы поискать альтернативную их реализацию. знай я сразу что их так реализовывать - недели две-три точно бы сэкономил.
то что требуется к практической реализации.
зациклить программу так что бы к ней непрерывным потоком шли данные на вход и данные на выход забирались. в дипломе это не требовалось, да и вообще были проблемы с отладкой.
тест программы не прикладывается -по этому позже выложу её.