Что такое rsa ?
RSA это асимметричный алгоритм шифрования. Зашифровка и расшифровка сообщение происходит двумя разными ключами, так называемый Публичны ключ за зашифровки и приватный(секретный) ключ для расшифровки сообщений . Допустим Сережа хочет отправить сообщение Алисе.
Rsa и python.
Для реализации RSA в Питоне мы будем использовать модуль который так и называется RSA. Он поддерживает шифрование и расшифровку, подписание и проверку подписей в соответствии с PKCS#1 версия 1.5.
Первым делом нам надо сгенерировать пару ключей(публичный и приватный).
import rsa
(pubkey, privkey) = rsa.newkeys(512) # 512 bits длина ключа, рекомендуется не меньше 1024
Так же модуль поддерживает сохранение и загрузку ключей в формате PEM и DER.
pubkey_pem = pubkey.save_pkcs1() # (format='PEM')
privkey_pem = privkey.save_pkcs1()
pubkey = rsa.PublicKey.load_pkcs1(pubkey_tmp, 'PEM') #(keyfile:bytes, format='PEM')
Теперь зашифруем и расшифруем сообщение :
message = 'hello Alisa!'.encode('utf8')
crypto = rsa.encrypt(message, pubkey) # Зашифровка
message = rsa.decrypt(crypto, privkey) # Расшифровка
print(message.decode('utf8'))
Проблема больших сообщений.
RSA может шифровать только сообщения, которые меньше, чем ключ. Пара байт теряются на случайном заполнении, а остальное доступно для само послание. Например, 512-битный ключ может кодировать 53-байт сообщения (512 бит = 64 байта, 11 байт используются для случайного заполнения и другая вещь.)
Но оф. руководство нам предлагает для шифрования больших сообщений воспользоваться блочным шифром, например AES. А его ключ передать зашифрованным с помощью алгоритма RSA :
import rsa.randnum
aes_key = rsa.randnum.read_random_bits(128)# Создаем случайный ключ 128 бит
encrypted_aes_key = rsa.encrypt(aes_key, public_rsa_key) # Зашифровываем ключ и передаем для расшифровки большого сообщения.
На этом все. Успехов )
Разбираем и просматриваем квалифицированные сертификаты средствами python/tkinter
Квалифицированные сертификаты быстро стали неотъемлемой частью повседневной жизни. И все больше людей хотят увидеть этого «зверя» изнутри. Это с одной стороны. А с другой стороны разрабатывается все больше приложений, в которых задействуется информация иэ этих сертификатов. И это не только атрибуты ИНН или ОГРН владельца или издателя сертификата. Это может быть и информация о том какой криптопровайдер использован владельцем сертификата (атрибут subjectSignTool) для генерации закрытого ключа или на базе каких сертифицированных средств создан удостоверяющий центр (УЦ), выпустивший тот или иной сертификат. И если написать программку, которая будет анализировать выпускаемые сертификаты, то можно будут собрать интересную статистику по тому какие СКЗИ используют владельцы сертификатов и на базе каких (правда это менее интересно) сертифицированных (или несертифицированных) средств развернуты УЦ (атрибут issuerSignTools):
На просторах Хабра уже предпринималась успешная попытка разобрать квалифицированный сертификат. К сожалению, разбор коснулся только получения атрибутов ИНН, ОГРН и СНИЛС, входящие в состав отличительного имени DN (Distinguished Name). Хотя, почему к сожалению? Перед автором стояла конкретная задача и она была решена. Мы же хотим получить доступ к атрибутам квалифицированного сертификата через Python и дать графическую утилиту для их просмотра.
Для доступа к атрибутам сертификата будем использовать пакет fsb795. Пакет доступен как для Pytho2, так и для Python3, как для Linux, так и для Windows. Для его установки достаточно выполнить традиционную команду:
# python -m pip install fsb795
Collecting fsb795
Requirement already satisfied: pyasn1-modules>=0.2.2 in /usr/lib/python2.7/site-packages (from fsb795) (0.2.2)
Collecting pyasn1>=0.4.4 (from fsb795)
Using cached https://files.pythonhosted.org/packages/d1/a1/7790cc85db38daa874f6a2e6308131b9953feb1367f2ae2d1123bb93a9f5/pyasn1-0.4.4-py2.py3-none-any.whl
Requirement already satisfied: six in /usr/lib/python2.7/site-packages (from fsb795) (1.11.0)
Installing collected packages: pyasn1, fsb795
Successfully installed fsb795-1.5.2 pyasn1-0.4.4
[root@localhost GCryptGOST]#
Пакет fsb795 в своей работе использует пакеты pyasn1 и pyasn1-modules. Поэтому если они не установлены, то будет предпринята попытка их установить.
Для python3 эта команда выглядит следующим образом:
# python -m pip install fsb795
...
#
Можно также скачать установочные пакеты
python3
и
python2
и локально их установить.
Название пакета, по аналогии с модулями из пакета pyasn1-modules, например, rfc2459 и т.д., указывает на то, что он предназначен для работы с сертификатами, соответствующими требованиям Приказа ФСБ РФ от 27 декабря 2022 г.
№ 795
«Об утверждении требований к форме квалифицированного сертификата…».
Доступ к сертификату в пакете fsb795 реализован через класс Certificate:
# -*- coding: utf-8 -*-
import os, sys
import pyasn1
import binascii
import six
from pyasn1_modules import rfc2459, pem
from pyasn1.codec.der import decoder
from datetime import datetime, timedelta
class Certificate:
#Атрибуты класса
cert_full = ''
cert = ''
pyver = ''
formatCert = ''
def __init__ (self,fileorstr):
#Проверка наличия файла с сертификатом
if not os.path.exists(fileorstr):
#Если файла нет, то предполагается, что это может быть
#строка с сертификатом в PEM-формате
strcert = fileorstr.strip('n')
if (strcert[0:27] != '-----BEGIN CERTIFICATE-----'):
return
idx, substrate = pem.readPemBlocksFromFile(six.StringIO(
strcert), ('-----BEGIN CERTIFICATE-----',
'-----END CERTIFICATE-----')
)
self.pyver = sys.version[0]
try:
self.cert_full, rest = decoder.decode(substrate, asn1Spec=rfc2459.Certificate())
self.cert = self.cert_full["tbsCertificate"]
self.formatCert = 'PEM'
except:
self.pyver = ''
self.formatCert = ''
return
#Сертификат в фвйле
#В атрибут self.pyver заносится версия python
self.pyver = sys.version[0]
filename = fileorstr
if (self.pyver == '2'):
if sys.platform != "win32":
filename = filename.encode("UTF-8")
else:
filename = filename.encode("CP1251")
#Проверяем на DER
file1 = open(filename, "rb")
substrate = file1.read()
if (self.pyver == '2'):
b0 = ord(substrate[0])
b1 = ord(substrate[1])
else:
b0 = substrate[0]
b1 = substrate[1]
#Проверка на PEM/DER, наличие последовательности 0x30, длина сертификата не может быть меньше 127 байт
if (b0 == 48 and b1 > 128) :
self.formatCert = 'DER'
else:
self.formatCert = 'PEM'
file1 = open(filename, "r")
idx, substrate = pem.readPemBlocksFromFile(
file1, ('-----BEGIN CERTIFICATE-----',
'-----END CERTIFICATE-----')
)
file1.close()
try:
self.cert_full, rest = decoder.decode(substrate, asn1Spec=rfc2459.Certificate())
self.cert = self.cert_full["tbsCertificate"]
except:
self.pyver = ''
self.formatCert = ''
#Методы класса для доступа к атрибутам сертификата
def subjectSignTool(self):
. . .
#Тест, запускаемый из командной строки
if __name__ == "__main__":
. . .
Для создании экземпляра объекта для конкретного сертификата достаточно выполнить следующий оператор:
$ python
Python 2.7.15 (default, May 23 2022, 14:20:56)
[GCC 5.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>import fsb795
>>tek_cert = fsb795.Certificate(<файл/строка с сертификатом>)
>>
В качестве параметра при создании экземпляра класса указывается сертификат, который может находится либо в файле формата PEM или DER или быть строкой в формате PEM.
После создания каждый экземпляр имеет четыре атрибута: pyver, formatCert, cert_full и cert.
По атрибуту pyver можно проверить как прошло распарсивание сертификата. Если pyver равен пустой строке, то файл или строка не содержит сертификата. В противном случае атрибут pyver содержит версию языка python:
>>> c1=fsb795.Certificate('Эта строка не может быть сертификатом')
>>> if (c1.pyver == ''):
... print ('Вы не предоставили сертификат')
...
Вы не предоставили сертификат
>>> c2 = fsb795.Certificate('/home/a513/cert_nss.der')
>>> if (c2.pyver != ""):
... print(c2.pyver)
...
2
>>> print(c2.formatCert)
DER
>>>
Атрибут formatCert при успешном создании экземпляра класса Certificate содержит тип формата файла/строки с сертификатом. Это может быть PEM или DER. Зачем этот атрибут нужен станет ясно ниже.
Пакет fsb795 создавался с использованием пакета pyasn1. Итак, осталось нерассмотренными два атрибута. В атрибуте cert хранится tbs-сертификат, готовый к использованию с пакетом pyasn1. Другой атрибут cert_full хранит весь декодированный сертификат с учетом rfc2459. Покажем, как можно получить алгоритм публичного ключа, имея атрибут cert и подключенный пакет pyasn1:
>>> pubkey = c2.cert['subjectPublicKeyInfo']
>>> ff = pubkey['algorithm']
>>> ff1 = ff['algorithm']
>>> print (ff1)
1.2.643.2.2.19
>>>
В конце можно будет оценить возможности пакета fsb795 по получению информации о публичном ключе квалифицированного сертификата.
Когда экземпляр класса Certificate успешно создан, то в нашем распоряжении оказываются методы которые позволяют легко получить необходимые данные из сертификата. Всю информацию о публичном ключе мы можем получить следующим образом:
>>> c3 = fsb795.Certificate('cert.der')
>>> key_info=c3.publicKey()
>>> for opt in key_info.keys():
... val = str(key_info[opt])
... print (opt '=' val)
...
curve=1.2.643.2.2.36.0
hash=1.2.643.2.2.30.1
valuepk=5b785f86f0dd5316ba37c8440e398e83f2ec0c34478f90da9c0c8046d341ff66f9044cd00a0e25530
acefd51e6be852dbecacbaabc55e807be8e1f861658bd58
algo=1.2.643.2.2.19
>>>
На данный момент класс Certificate содержит следующие методы:
В спойлере лежит тестовый пример, который наглядно демонстрирует работу этих методов.
Для запуска тестового примера достаточно выполнить команду:
$python test795.py
Имея в своем распоряжении пакет fsb795 было естественным написать на языке python самодостаточную платформонезависимую графическую утилиту для просмотра квалифицированных сертификатов. В качестве графической поддержки использован пакет Tkinter:
Утилита viewCertFL63 имеет три вкладки. На вкладке «О сертификате » помимо прочего отображается текущее время. Мы еще вернемся к нему ниже. Для выбора сертификата достаточно нажать кнопку «Выбрать»:
Обратите внимание на кнопку (те кто работают на Windows этой кнопки не увидят), она позволяет скрывать так называемые невидимые файлы/каталоги (hidden). Для того чтобы эта кнопка появилась достаточно выполнить следующие команды:
if sys.platform != "win32":
root.tk.call('set', '::tk::dialog::file::showHiddenBtn', '1')
root.tk.call('set', '::tk::dialog::file::showHiddenVar', '0')
Очень полезная кнопка. Итак, после выбора сертификата вкладка «О сертификате» примет вид:
Что здесь примечательного так это то, что если во время просмотра сертификата закончится срок его действия, то на иконке в левом верхнем углу печать разломается на две половинки. Каждый может убедится в этом, переставив на компьютере часы на один год вперед.
На вкладке «Детали» можно подробно просмотреть характеристики выбранного атрибута квалифицированного сертификата:
И, наконец, третья вкладка «Текст». В этой вкладке отображается содержимое всего сертификата:
Для просмотра сертификата можно использовать не только Python (кнопка «Python»), то и утилиты openssl и pp из состава Network Serurity Services (NSS). Если у кого-то не окажется этих утилит, то первую можно получить, собрав openssl с поддержкой российской криптографии. При использовании утилиты pp вывод сертификата выглядит так:
Выше мы упоминали про атрибут formatCert класса Certificate пакета fsb795. Так вот значение этого атрибута нам необходимо для указания формата файла с сертификатом при запуске той или утилиты. Например, вызов утилиты pp при формате файле PEM выглядит следующим образом:
$pp –t c –u –a –i <файл сертификата>
Параметр «-a» и указывает на формат файла PEM. Для формата DER он не указывается.
Аналогичным образом задается и параметр «–inform » для openssl.
Кнопка «Утилита» служит для указания пути к утилитам openssl или pp.
Дистрибутивы утилиты viewCertFL63 находятся
здесь
.
Сборка дистрибутивов была сделана с использованием пакета pyinstaller:
$python pyinstaller.py --noconsole -F viewCertFL63.py
Цифровая подпись.
Цифровая подпись (ЦП) позволяет подтвердить авторство электронного документа . Подпись связана как с автором, так и с самим документом с помощью криптографических методов, и не может быть подделана с помощью обычного копирования. Наш модуль RSA позволяет подписывать сообщения для подтверждения автора и целостности сообщения :
(pubkey, privkey) = rsa.newkeys(512)
message = 'Test message'
signature = rsa.sign(message, privkey, 'SHA-1') # Создание подписи rsa.sign(message, priv_key, hash_method),можно использовать ‘MD5’, ‘SHA-1’, ‘SHA-224’, 'SHA-256’, ‘SHA-384’ и ‘SHA-512’
Для проверки подписи используйте rsa.verify() функция. Эта функция возвращает значение True, если проверка прошла успешно:
>>> message = 'Test message'
>>> rsa.verify(message, signature, pubkey)
True
Если подпись не действительно выйдет исключение rsa.pkcs1.VerificationError
>>> message = 'Test message not true'
>>> rsa.verify(message, signature, pubkey)
Traceback (most recent call last):
File "", line 1, in
File "/home/sybren/workspace/python-rsa/rsa/pkcs1.py", line 289, in verify
raise VerificationError('Verification failed')
rsa.pkcs1.VerificationError: Verification failed