У меня есть только очень рудиментарные теоретические знания о RSA.
При чтении различных источников о том, как его использовать на практике, казалось, что PKCS#1 OAEP будет хорошей вещью.
Для тестовой реализации я использую Python с PyCrypto. Например. этоявляется примером использования PKCS#1 OAEP.
Шифрование с использованием открытого ключа, а затем расшифровка с использованием закрытого ключа работает нормально. Например. общественность может отправить некоторые данные человеку X с закрытым ключом.
Исходя из моего базового понимания того, как работает RSA, я подумал, что могу просто поменять местами открытый и закрытый ключи, т. е. я могу использовать открытый ключ для шифрования и закрытый ключ для расшифровки. Например. человек X может зашифровать некоторые данные своим закрытым ключом, а публичный может расшифровать их с помощью открытого ключа. Если расшифровка работает нормально, это дает какое-то доказательство того, что данные исходят от человека X.
PyCrypto жалуется, когда я пытаюсь расшифровать с помощью открытого ключа.
Из исходного кода PyCrypto в функции _RSAKey._decrypt
( здесь) кажется, что объект ключа сам знает, является ли он закрытым или открытым ключом, и отличается между ними (к моему удивлению, опять же на основе моего очень простого понимания RSA).
Отсюда, похоже, я могу взломать функцию расшифровки, чтобы она использовала открытый ключ.Или несколько иначе: я мог бы просто поменять местами открытый показатель e
и частный показатель d
в ключевых объектах.
Но похоже, что все это не предназначено для использования/взлома таким образом. Поэтому я хотел спросить здесь о моих недоразумениях.
Кроме того, просто из любопытства я сгенерировал несколько ключей ( RSA.generate(2048)
) и посмотрел на n
, e
и д
. Во всех случаях n
и d
были очень большими, в то время как e
было во всех случаях постоянным(65537) (я бы не стал ожидал этого).
Из всего этого я догадываюсь, что мне действительно не следует просто менять местами e
и d
.
Так что я думаю, мне следует использовать какой-то другой метод для подписи, такой как PKCS1_PSS.
Код для шифрования/дешифрования, если кому интересно:
def randomString(l):
import random
return ''.join(chr(random.randint(0, 0xFF)) for i in range(l))
def genkeypair():
from Crypto.PublicKey import RSA
key = RSA.generate(2048)
pubkey = key.publickey().exportKey("DER")
privkey = key.exportKey("DER")
return (pubkey,privkey)
def encrypt(v, rsapubkey):
from Crypto.PublicKey import RSA
rsakey = RSA.importKey(rsapubkey)
from Crypto.Cipher import PKCS1_OAEP
rsa = PKCS1_OAEP.new(rsakey)
import binstruct
from array import array
aeskey = randomString(32)
iv = randomString(16)
from Crypto.Cipher import AES
aes = AES.new(aeskey, AES.MODE_CBC, iv)
data = binstruct.varEncode(v)
data += array("B", (0,) * (-len(data) % 16))
out = binstruct.strEncode(rsa.encrypt(aeskey + iv))
out += array("B", aes.encrypt(data))
return out
def decrypt(stream, rsaprivkey):
from array import array
from StringIO import StringIO
if isinstance(stream, array): stream = stream.tostring()
if isinstance(stream, str): stream = StringIO(stream)
from Crypto.PublicKey import RSA
rsakey = RSA.importKey(rsaprivkey)
from Crypto.Cipher import PKCS1_OAEP
rsa = PKCS1_OAEP.new(rsakey)
import binstruct
aesdata = binstruct.strDecode(stream)
aesdata = rsa.decrypt(aesdata)
aeskey = aesdata[0:32]
iv = aesdata[32:]
from Crypto.Cipher import AES
aes = AES.new(aeskey, AES.MODE_CBC, iv)
class Stream:
buffer = []
def read1(self):
if len(self.buffer) == 0:
nextIn = stream.read(16)
self.buffer += list(aes.decrypt(nextIn))
return self.buffer.pop(0)
def read(self, n):
return "".join([self.read1() for i in range(n)])
v = binstruct.varDecode(Stream())
return v
(binstruct
— небольшой модуль, который может кодировать/декодировать древовидные структуры данных — аналогично JSON/BSON.)
Именно здесь я подумал, что могу просто использовать шифрование
с закрытым ключом и дешифрование
с открытым ключом.
Окончательную реализацию с (надеюсь) правильной подписью/аутентификацией можно найти здесь в binstruct.