
МСЗИ_23_ИСТ_1_1_Какушкина_Ольга_Витальевна_ЛР_5
.docxМИНОБРНАУКИ РОССИИ
Ф
едеральное
государственное бюджетное образовательное
учреждение высшего образования
НИЖЕГОРОДСКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ
УНИВЕРСИТЕТ им. Р.Е.АЛЕКСЕЕВА
Институт радиоэлектроники и информационных технологий
Кафедра информатики и систем управления
ОТЧЕТ по лабораторной работе №5
АЛГОРИТМЫ ЭЛЕКТРОННОЙ ЦИФРОВОЙ ПОДПИСИ (ГОСТ Р 34.10-2018)
по дисциплине
Методы и средства защиты информации
(наименование дисциплины)
РУКОВОДИТЕЛЬ:
________________ Жуков М. С.
(подпись) (фамилия, и.,о.)
СТУДЕНТ:
________________ Какушкина О.В.
(подпись) (фамилия, и.,о.)
23-ИСТ-1-1
(шифр группы)
Работа защищена «___» ____________
С оценкой ________________________
Нижний Новгород 2025
Текст задания №5:
Реализовать процесс формирования и проверки электронной цифровой подписи по ГОСТ Р 34.10-2018.
1. ГОСТ Р 34.10-2018 - это российский стандарт электронной цифровой подписи, основанный на эллиптических кривых. Данный алгоритм является частью семейства криптографических стандартов ГОСТ и предназначен для обеспечения целостности и аутентичности цифровых данных.Описание алгоритма RSA с цифровой подписью
2. Основные понятия
Эллиптическая кривая: математический объект, заданный уравнением y² = x³ + ax + b над конечным полем
Базовые параметры: набор параметров (p, a, b, q, P), определяющих конкретную кривую
Закрытый ключ: случайное число d в диапазоне [1, q-1]
Открытый ключ: точка Q на кривой, вычисляемая как Q = d*P
Хеш-функция: используется Streebog (ГОСТ Р 34.11-2012) длиной 256 или 512 бит
3. Описание алгоритма
3.1. Генерация ключей
Выбирается случайное число d в диапазоне от 1 до q-1 (порядок базовой точки)
Вычисляется точка Q = d*P (умножение точки на скаляр)
Пара (d, Q) становится парой закрытый/открытый ключ
3.2. Формирование подписи
Вычисляется хеш сообщения h = Hash(M)
Преобразуется хеш в число e = h mod q (если e = 0, устанавливается e = 1)
Генерируется случайное число k в диапазоне от 1 до q-1
Вычисляется точка C = k*P
Вычисляется r = x_C mod q (x-координата точки C)
Если r = 0, процесс повторяется с новым k
Вычисляется s = (rd + ke) mod q
Если s = 0, процесс повторяется с новым k
Подпись - пара (r, s)
3.3. Проверка подписи
Проверяется, что 0 < r < q и 0 < s < q
Вычисляется хеш сообщения h = Hash(M)
Преобразуется хеш в число e = h mod q (если e = 0, устанавливается e = 1)
Вычисляется v = e⁻¹ mod q (обратный элемент)
Вычисляются z₁ = (sv) mod q и z₂ = (-rv) mod q
Вычисляется точка C = z₁P + z₂Q
Вычисляется R = x_C mod q (x-координата точки C)
Подпись верна, если R = r
Реализация алгоритма
import hashlib import random from typing import Tuple class Streebog: """Класс-заглушка для хеш-функции ПО ГОСТ""" @staticmethod def hash256(message: bytes) -> bytes: return hashlib.sha256(message).digest() @staticmethod def hash512(message: bytes) -> bytes: """Временная замена Streebog-512 на SHA-512 (для тестирования)""" return hashlib.sha512(message).digest() class GOST34102018: def __init__(self, p: int, a: int, b: int, q: int, P: Tuple[int, int]): """ Инициализация параметров эллиптической кривой :param p: модуль поля :param a: коэффициент a уравнения кривой :param b: коэффициент b уравнения кривой :param q: порядок подгруппы :param P: базовая точка подгруппы """ self.p = p self.a = a self.b = b self.q = q self.P = P # Определяем длину подписи в битах (256 или 512) self.l = 256 if q.bit_length() <= 256 else 512 def _hash(self, message: bytes) -> int: """Реализация хеширования """ if self.l == 256: hash_bytes = Streebog.hash256(message) else: hash_bytes = Streebog.hash512(message) return int.from_bytes(hash_bytes, 'little') def _inverse(self, a: int, n: int) -> int: """Нахождение обратного элемента по модулю (расширенный алгоритм Евклида)""" t, newt = 0, 1 r, newr = n, a while newr != 0: quotient = r // newr t, newt = newt, t - quotient * newt r, newr = newr, r - quotient * newr if r > 1: raise ValueError("Обратного элемента не существует") if t < 0: t += n return t def _add_points(self, P: Tuple[int, int], Q: Tuple[int, int]) -> Tuple[int, int]: """Сложение точек на эллиптической кривой""" if P == (0, 0): return Q if Q == (0, 0): return P if P[0] == Q[0] and (P[1] + Q[1]) % self.p == 0: return (0, 0) if P != Q: # Лямбда для сложения разных точек numerator = (Q[1] - P[1]) % self.p denominator = (Q[0] - P[0]) % self.p lambd = (numerator * self._inverse(denominator, self.p)) % self.p else: # Лямбда для удвоения точки numerator = (3 * P[0] ** 2 + self.a) % self.p denominator = (2 * P[1]) % self.p lambd = (numerator * self._inverse(denominator, self.p)) % self.p x3 = (lambd ** 2 - P[0] - Q[0]) % self.p y3 = (lambd * (P[0] - x3) - P[1]) % self.p return (x3, y3) def _multiply_point(self, k: int, point: Tuple[int, int]) -> Tuple[int, int]: """Умножение точки на скаляр """ result = (0, 0) # Нейтральный элемент addend = point while k > 0: if k & 1: result = self._add_points(result, addend) addend = self._add_points(addend, addend) k >>= 1 return result def generate_keys(self) -> Tuple[int, Tuple[int, int]]: """Генерация пары ключей (закрытый и открытый)""" d = random.randint(1, self.q - 1) # Закрытый ключ Q = self._multiply_point(d, self.P) # Открытый ключ return d, Q def sign(self, message: bytes, d: int) -> Tuple[int, int]: """Формирование подписи для сообщения""" # Шаг 1: Вычисление хеша сообщения h = self._hash(message) # Шаг 2: Преобразование хеша в число e e = h % self.q if e == 0: e = 1 while True: # Шаг 3: Генерация случайного числа k k = random.randint(1, self.q - 1) # Шаг 4: Вычисление точки C = k*P и параметра r C = self._multiply_point(k, self.P) r = C[0] % self.q if r == 0: continue # Шаг 5: Вычисление параметра s s = (r * d + k * e) % self.q if s == 0: continue # Шаг 6: Возврат подписи (r, s) return r, s def verify(self, message: bytes, signature: Tuple[int, int], Q: Tuple[int, int]) -> bool: """Проверка подписи для сообщения""" r, s = signature # Шаг 1: Проверка диапазонов r и s if not (0 < r < self.q and 0 < s < self.q): return False # Шаг 2: Вычисление хеша сообщения h = self._hash(message) # Шаг 3: Преобразование хеша в число e e = h % self.q if e == 0: e = 1 # Шаг 4: Вычисление v = e^-1 mod q v = self._inverse(e, self.q) # Шаг 5: Вычисление z1 и z2 z1 = (s * v) % self.q z2 = (-r * v) % self.q # Шаг 6: Вычисление точки C = z1*P + z2*Q z1P = self._multiply_point(z1, self.P) z2Q = self._multiply_point(z2, Q) C = self._add_points(z1P, z2Q) # Шаг 7: Проверка условия R == r mod q R = C[0] % self.q return R == r # Пример параметров для 256-битной подписи p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97 a = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94 b = 0x00000000000000000000000000000000000000000000000000000000000000A6 q = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C611070995AD10045841B09B761B893 P = (0x0000000000000000000000000000000000000000000000000000000000000001, 0x8D91E471E0989CDA27DF505A453F2B7635294F2DDF23E3B122ACC99C9E9F1E14) # Создание экземпляра класса с параметрами gost = GOST34102018(p, a, b, q, P) # Генерация ключей d, Q = gost.generate_keys() print(f"Закрытый ключ: {d}") print(f"Открытый ключ: ({Q[0]}, {Q[1]})") # Сообщение для подписи - "Кушина Ольга" (в кодировке UTF-8) message = "Какушина Ольга".encode('utf-8') # Формирование подписи signature = gost.sign(message, d) print(f"Подпись: (r={signature[0]}, s={signature[1]})") # Проверка подписи is_valid = gost.verify(message, signature, Q) print(f"Подпись верна: {is_valid}") # Проверка с измененным сообщением (должно вернуть False) fake_message = "Какушкина Ольга".encode('utf-8') is_valid_fake = gost.verify(fake_message, signature, Q) print(f"Проверка с другим сообщением: {is_valid_fake}")
Вывод программы
Вывод:
В ходе лабораторной работы я написала алгоритм ГОСТ Р 34.10-2018. Он предоставляет надежный механизм создания и проверки электронных цифровых подписей, соответствующий российским криптографическим стандартам. Использование эллиптических кривых обеспечивает высокий уровень безопасности при относительно небольших размерах ключей.