在PKCS#1 OAEP加密/解密中交换公钥/私钥

我对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.)

这就是我认为我也可以使用私钥加密并使用公钥解密的地方.

最终实施(希望)正确的签名/认证可以在here in binstruct找到.

您对交换公钥和私钥角色的一般理解是正确的.最后,RSA基于这样一个事实

m^(ed) congruent m (mod n)

通常标题为RSA加密的通常是操作

m^e mod n,

将消息提升到e-power,其中e是公钥.

然后解密

(m^e)^d mod n,

将加密的消息提升到d次幂,其中d是私钥.现在因为取幂的规则和乘法是可交换的(这些仍然在模运算中),我们有

m congruent (m^e)^d congruent m^(ed) congruent m^(de) congruent (m^d)^e,

因此,如果以相反的顺序应用操作,则会得到相同的结果.

你是正确的假设逆转导致数字签名,因为每个人都可以用公钥e验证(“解密”)签名,所以只有在使用相应的私钥“加密”(签名)时,该消息才是真实的. d.

事实证明,PyCrypto只是试图阻止你在另一方面误解一个,OpenSSL或Ruby OpenSSL允许你for example同时做两件事:public_encrypt / public_decrypt和private_encrypt / private_decrypt.

这个理论非常重要,现在为什么有充分的理由不让你互换使用它们.我刚才所描述的通常被称为“教科书RSA”,它仍然远非安全.需要注意额外的事情,以使结果在实践中可用.这就是为什么在PyCrypto中有一个专用的signature package – 这有效地完成了你所描述的,但另外还要照顾我提到的东西.虽然知道这些东西如何运作对我们的理解有好处,但我们应该总是在实践中使用这些包,因为他们已经制定并修复了我们在滚动自己时可能会引入的错误.

至于为什么e总是65537.它实际上不一定是固定值,但通常选择的是一个非常小的数字,其二进制表示中尽可能少的1(65537是10001).在过去,也选择了e = 3或e = 17,但在实践中被认为是不安全的,因为它们可以通过简单地取密文的第3或第17根来攻击.如果e = 3且m = 3,那么3 ^ 3是27,并且如果密文是27,则不知道m是3,而不管模数n(通常大得多).因此,危险在于密文即使在取幂之后也不会越过“模数边界”,因此允许我们简单地取第e个根来得到原始消息.典型的模数为1024 – 4096位,这不再是e = 65537的问题.

二进制表示中的少数1对于快速计算也很有用.模幂运算通常使用Multiply and Square算法实现,性能最适合少量1的小e.为什么选择这种方式而不是相反的方式,例如有少量1的小d?对初学者来说,d会更容易猜到这一点.第二个优点是,对于数字签名,您通常只签署一次文档,但经常进行验证.这意味着m ^ d经常执行一次,因此您可以使常见任务执行得最好,同时允许罕见任务执行不良.

编辑:

你问我是否可以进一步解释像RSA-PSS这样的方案,以确保安全.

当比较OAEP对加密的作用和PSS对签名的作用时,两者看起来非常相似.事实上,他们都是在这个过程中引入随机化,这允许在某些假设下OAEPPSS的可证明的安全性.我还发现这个paper很有帮助.与旧式PKCS 1.5加密和签名相比,可证明安全性是一个很大的优势,在相同的假设下可以证明这是不可证明的(关键点:没有确定性方案可以,随机化是必不可少的).提议的签名和加密方案之间的明显区别在于签名方案总是要求首先对要签名的消息进行散列.这不仅在效率方面有意义,而且还可以防止一些本来可能发生的攻击.我想这导致了为什么我们应该总是使用签名和加密方案加密签名方案的要点:提议的方案附带安全证明,我们的手工制度没有.

密码学家发明了这些方案,使我们的生活变得更加容易 – 它们为我们提供了理想的工具,可以通过将选项数量减少到最少来避免滥用或误用.例如,即使您设法使用RSA-OAEP提出了一个好的签名方案,使用它的人可能也不知道为什么他们应该在应用签名之前首先散列他们的消息. RSA-PSS甚至不存在这种误用.

你还问过一些好的阅读材料.虽然这是一个非常主观的话题,但我真的非常喜欢这些:

实用方面:

> Applied Cryptography – 仍然是经典而值得一读的.一些安全人员说它很危险,因为它让人们相信他们知道自己能够编写自己的加密.但我想我们都是成年人,不是吗?感受“那里有什么”的感觉仍然很棒
> Cryptography Engineering – 有一些很好的实用建议,并在实施加密代码时提到了警告.
> Handbook of Applied Cryptography – 它是免费的,并且仍然有很多好的建议,特别是在实现方面.

理论方面:

> Modern Cryptography – 它是理论与实践之间的混合体,并且在实践中对事情可能出错有很多了解.
> Cryptography – Theory and Practice – 这对我来说是一个改变游戏规则的人,我喜欢这本书.如果你只读过一本书,就让它成为这本书:)
> Introduction to Modern Cryptography – 在解释“现代方法”以及安全证明如何实际工作以及在何种假设下做得很好.
> Foundations of Cryptography I&II – 如果在上一本书之后你仍然无法获得足够的单向函数和朋友理论,这就是你的书.非常技术性.

安全性不仅仅是加密:

> Security engineering – 有许多例子说明声音原则在实践中如何出错
> Information Security – 与安全工程类似,说明范围内的安全性不仅仅是加密.

除此之外,我试着通过阅读有关新攻击,技术等的最新论文来了解最新情况.我发现r/netsec非常有帮助,以及关注推特上的研究人员和从业人员,他们定期发布有趣的资料.

最后,如果你有时间,请参加Coursera和Udacity的密码学课程!我想他们会在接下来的几周内重新开始,他们真的很棒,我相信你不会后悔的.他们进行了大量实践练习,这些练习非常有趣,很好地说明了各种攻击加密实现的方法.

相关文章
相关标签/搜索