【发布时间】:2012-06-13 14:34:36
【问题描述】:
我对RSA只有一些非常初级的理论知识。
在阅读有关如何在实践中使用它的不同来源时,PKCS#1 OAEP 似乎是一件好事。
对于测试实现,我使用 Python 和 PyCrypto。例如。 this 是使用 PKCS#1 OAEP 的示例。
使用公钥加密然后使用私钥解密可以正常工作。例如。公众可以使用私钥向 X 人发送一些数据。
根据我对 RSA 工作原理的基本了解,我认为我可以互换公钥/私钥,即我可以使用公钥进行加密,使用私钥进行解密。例如。 X 人可以用自己的私钥加密一些数据,公众可以使用公钥对其进行解密。如果解密工作正常,这可以证明数据来自 X 人。
当我尝试使用公钥解密时,PyCrypto 报错。
通过阅读 PyCrypto 源代码,在 _RSAKey._decrypt 函数 (here) 中,似乎密钥对象本身知道它是私钥还是公钥并且它们之间存在差异(令我惊讶的是,再次基于我对 RSA 的基本理解)。
从那里看来,我可以破解解密函数,以便它使用公钥。或者有些不同:我可以在关键对象中交换公共指数 e 和私有指数 d。
但这一切似乎不打算以这种方式使用/黑客攻击。所以我想在这里问一下我的误解。
另外,出于好奇,我生成了一些密钥 (RSA.generate(2048)) 并查看了 n、e 和 d。在所有情况下,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。)
那是我认为我也可以将encrypt 与私钥一起使用,并将decrypt 与公钥一起使用。
可以在here in binstruct找到(希望)正确签名/身份验证的最终实现。
【问题讨论】:
-
“当我尝试使用公钥解密时 PyCrypto 报错”。请更具体,并请出示您的代码。
-
@GregS:它在
_RSAKey._decrypt中引发TypeError("No private key")。正如您从链接代码中看到的那样。这就是我所说的。看来解密时需要私钥。 -
如果您只有基本的密码学知识,那么以不应该使用的方式使用 API 是行不通的。我有 10 年的经验,即使我以不应该的方式使用加密库时也非常小心 - 我尽量避免这样做。
-
@Albert ImportError: 没有名为 binstruct 的模块。你发的链接失效了。有没有替代链接?请分享。
标签: encryption cryptography rsa public-key-encryption