【问题标题】:Python Crypto, RSA Public/Private key, with large filePython Crypto,RSA 公钥/私钥,带有大文件
【发布时间】:2015-04-10 03:45:28
【问题描述】:

我现在知道 RSA 公钥/私钥一次只能加密非常短的输入,但任何人都可以提供一种方法来加密任何类型的文件(.txt、.phf、.exe 等),只使用公钥/私钥?我不想拥有额外的 AES 密钥。

这是我的代码,在使用一对公钥和私钥进行加密和解密后,我无法取回原始内容。我不关心我的加密或解密有多安全,我只希望简单的加密解密可以处理可能需要的任何输入,无论它有多长或多长。

from Crypto.PublicKey import RSA
from Crypto import Random


random_generator = Random.new().read
key = RSA.generate(1024, random_generator)
public_key = key.publickey()

f = open('C:\Users\Administrator\Desktop\jack.txt','r').read()

print 'original content: '+ f

enc_data = public_key.encrypt(f, 32)
print 'encrypted data: '
print enc_data

dec_data = key.decrypt(enc_data)
print 'decrypted data: '+ dec_data

这是输出:

original content: Python Cryptography Toolkit

A collection of cryptographic modules implementing various algorithms and protocols.

Subpackages:

Crypto.Cipher
Secret-key (AES, DES, ARC4) and public-key encryption (RSA PKCS#1) algorithms
Crypto.Hash
Hashing algorithms (MD5, SHA, HMAC)
Crypto.Protocol
Cryptographic protocols (Chaffing, all-or-nothing transform, key derivation functions). This package does not contain any network protocols.
Crypto.PublicKey
Public-key encryption and signature algorithms (RSA, DSA)
Crypto.Signature
Public-key signature algorithms (RSA PKCS#1)
Crypto.Util
Various useful modules and functions (long-to-string conversion, random number generation, number theoretic functions)
encrypted data: 
('\x08\xe3\x9d\x03\x1e\xe9(\xe2\xc7\xc6e\x0b5\x02\xc0\xd8G\x1f\xf5\xb8\x9cMC\x93Z\x982\xa5\x97\xec\xab4\x18\xc2\xc8\xd9\xd3\x99aX\xd96b\x19\x96\xdc\x1d|F\xe0\xa9\xa9\xea\x03\x10>0g\x83\xdb\xeb\xdb\x13\x91\xc6\xd8\xf6\x95\xedE@A\x0bc\xae\xbe\xbe\xf0\xde\xcc\xcexk\x10\xb3\x86\xd3\xdd\xd0\xca@T2\x9a\x8a6ut\xb1\xaf\x07\x1f\xa2M\r\xf0D\xa2`h\xc3\x89\x18\x0e\xd4\xca\xee\xf5\xfc\x01\xed\x95}X\x1f\x13 1',)
decrypted data: ���J�rPX �����ju�a,�xm�'�]��ٟ�?y;�)��tĹ�,�D4^�ba�8����9q
+�i��l �q]Kd�Y���u��S�B���Ϲ�^�A3
.7��j��m�
�6�dl� qU

【问题讨论】:

    标签: python encryption cryptography rsa pycrypto


    【解决方案1】:

    RSA 速度很慢,因此它不太适合加密/解密大块数据。它通常用于加密/解密更快对称密码的密钥,例如 AES。

    乍一看,你的加密数据看起来有点小,与你输入的数据相对应,但我对 Crypto 不是很熟悉(我前几天才自己安装的),所以我无法解释它是什么对您的数据进行了处理。

    但是这段代码对我有用:

    #!/usr/bin/env python
    
    from Crypto.PublicKey import RSA
    from Crypto import Random
    
    src_data = 'To be, or not to be - that is the question.'
    print `src_data`
    
    random_generator = Random.new().read
    key = RSA.generate(1024, random_generator)
    print 'Key generated'
    
    pub_key = key.publickey()
    print 'Public key', pub_key
    
    enc_data = pub_key.encrypt(src_data, 32)[0]
    print `enc_data`
    
    dec_data = key.decrypt(enc_data)
    print `dec_data`
    

    典型输出

    'To be, or not to be - that is the question.'
    Key generated
    Public key <_RSAobj @0xb7114dcc n(1024),e>
    ',\x17\xb1\x8a\x98\xb0-z\x8c\xb8r\x17\xa2\xfe[\x10I\x97\x93\x9d[\x93\x19&\\\x16V\xc2\xa3\x99\x80\xa5\x08\xafT\xb5iA|\x89\xeeJ\x90%\xceXv\x9f\x9f\xcb\\P"i\x00D\xd4\x16\xee\xa9\xe49\x18[\xa5\x0f\xd3\xfb\x91\xd5\x98\x1bP\xbf\xa4\xa5Dz\x8b7\x13\x9dqk+\xf7A\xd3\x12\x1c\x06\xcep\xf2\xba\xc6\xee\xf8\xa2\xb4\x04v\xfb\xb7>\xb3U\x17\xban\xf7\xc0oM+Tq\xce\xe3D\x83\xb9\xa4\x90\xe6c,\x18'
    'To be, or not to be - that is the question.'
    

    FWIW,这里是上面的稍作修改的版本,可以在 Python 2 和 Python 3 上运行,尽管两个版本的输出会有细微的差异。

    在 Python 3 中,我们不能将字符串传递给加密或解密函数,我们必须传递字节。此外,Python 3 不支持在 Python 2 中获取对象的 repr 的反引号语法。

    此代码调用字符串.encode() 和字节.decode() 方法来执行转换。我们可以指定一个编码编解码器,例如

    src_data.encode('utf-8')
    

    但这不是必需的,因为 UTF-8 是默认编解码器。

    from __future__ import print_function
    
    from Crypto.PublicKey import RSA
    from Crypto import Random
    
    src_data = 'To be, or not to be - that is the question.'
    print(repr(src_data))
    
    random_generator = Random.new().read
    key = RSA.generate(1024, random_generator)
    pub_key = key.publickey()
    print('Key generated')
    
    print(key.exportKey().decode())
    print(pub_key.exportKey().decode())
    
    enc_data = pub_key.encrypt(src_data.encode(), 32)[0]
    print('Encoded\n', repr(enc_data))
    
    dec_data = key.decrypt(enc_data).decode()
    print('Decoded\n', repr(dec_data))    
    

    典型的 Python 3 输出

    'To be, or not to be - that is the question.'
    Key generated
    -----BEGIN RSA PRIVATE KEY-----
    MIICXAIBAAKBgQDL/TzI4yHmlcC8qP3xWNieujmXR7CnEaZJrDH1Hyr/tGNa0aEE
    jDIz+RlMntBbhOuiQMkMtCSB5X28h7HetiD4XkWTXmlIiKZQLZ074cO5mxF+HhF7
    WIG30VONpX+Q4t/beqtaqbzyeIWvDdcCjUwOSQLrUKU5PX9LFzX+FnN1UwIDAQAB
    AoGASRVZib+Wjb5pZy5EjQt/0J53s7ODnte78/k1jNS12xcN4aPpRG/WLLi6T7E2
    hROCOIdtgJep3MAT5E/ZciledflaDwwmLo6+NsrhMppsNhpIHsvxWxmwxnH+bC2H
    lpyeUmxku4xzqwYW4kuF3iaR45K2eUpXQyWTE9+pgvepgoECQQDT6Waiavstvs4W
    btW2P4J+7O//NmTcvnyLTnhFTXklxTxnSun54HYOce8+TttsXWESTbzf91saN5SW
    0vPyKK25AkEA9m3gbwFppiA65464jnDCP1AnrR15n3tbsLpaadYdRm07b+4BB0R2
    M820cgber14JiGndOfv1uPl1Ooy0IH4hawJBAJKRC/uqIrAxGDlLz2SN6KQBHL1X
    0csbtOhlDaphOzl0gaKvncTGCuFSzDY8NGdu7oTKX6hIXSp05sCqhy8mE4ECQE49
    xKx5/llIkmtC3UYcdxAzGuXUHfGM8SfDg0FnQhRCSkTXhGwSSJVaEpjBpaJ4cP5m
    3l6yqOn6CkZ0thw679ECQCWNC5hVEtsAb0TcjGdTpw+xTFusiZciNyHTQ64Zq2cc
    ehQrxTRDIEBA4wIgUwrTwdVXk10OtpcVZvLIVjqdC84=
    -----END RSA PRIVATE KEY-----
    -----BEGIN PUBLIC KEY-----
    MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDL/TzI4yHmlcC8qP3xWNieujmX
    R7CnEaZJrDH1Hyr/tGNa0aEEjDIz+RlMntBbhOuiQMkMtCSB5X28h7HetiD4XkWT
    XmlIiKZQLZ074cO5mxF+HhF7WIG30VONpX+Q4t/beqtaqbzyeIWvDdcCjUwOSQLr
    UKU5PX9LFzX+FnN1UwIDAQAB
    -----END PUBLIC KEY-----
    Encoded
     b'\x843\x9aJ\xe6\x91p\xd2\x9c\xd0r{37\xa2G\x13Q\xc7~\xbd5\xce\x9f\xd4\x16\xda\x11\x02.\xb7\xf1\xf3Q\x8c|\xb0R2B\x1b)e\xeaD\x8e\x11\x1b\xb0J:\xbal\xac\x86\xdcb}_\x16IX\xccd\x0c\xb5E?Im<\x04ORT\xc9\xc6K|;\xf3\xbcK\xfd\x89\x96ZF(\x0b\x82v\x19`\xc3\xa1N\x934*\x9c\xfcT\xf4i\x02g\x1fl\xec\xc1\x19z\x9f7\xa6}\xe2\xe3}\xaa|\x1e\x13z\xd9$\xea'
    Decoded
     'To be, or not to be - that is the question.'
    

    我们真的在这里不需要使用 UTF-8 编码。由于src_data 是一个纯 7 位 ASCII 字符串,并且我们已将其作为文字嵌入到脚本中,因此我们可以将其作为文字字节字符串提供:

    src_data = b'To be, or not to be - that is the question.' 
    

    【讨论】:

    • 要在 python 3 中进行这项工作,您需要将 src_data 编码为 .encode('UTF-8')
    • @ScottMcC 感谢您的提醒。我已经更新了我的答案以包含 Python 2 / 3 兼容代码。我想这个答案并没有真正回答 OP 的问题,但我想它对于那些想要在少量文本上使用 RSA 的人来说仍然是一个有用的演示。
    • @PM 2Ring 您添加的其他内容当然很有帮助,感谢您的更新。不幸的是,当您忘记在 Python 3 中正确编码字符串时,pycrypto 的错误输出并不是很有帮助:TypeError: argument 1 must be int, not str。我花了一点时间才意识到这是一个编码问题......
    • @ScottMcC 按名称加密,按性质加密。 ;) Python 3 明确区分了文本字符串和字节字符串,这很好,虽然我理解将 bytes(或 bytearray)对象中的项目作为整数的基本原理,但许多 Python 编码人员同意它可以发生这种错误时会有点困惑。甚至一些核心开发人员也想知道他们是否在那里做出了正确的决定。
    【解决方案2】:

    RSA 只能加密有限数量的输入。这取决于 RSA 的密钥大小(在您的情况下为 1024 位)和使用的填充。大于此的所有内容(不使用填充时为 128 字节,如果使用填充则更少)并且您无法再恢复它。

    解决方案是使用混合加密。

    1. 生成一个 16、24 或 32 字节的随机字节串用作 AES 密钥,
    2. 使用之前生成的密钥和 AES 加密实际数据
    3. 使用 RSA 加密 AES 密钥。

    AES加密:

    from Crypto.Cipher import AES
    from Crypto import Random
    
    aeskey = Random.new().read(32)
    iv = Random.new().read(AES.block_size)
    cipher = AES.new(aeskey, AES.MODE_CFB, iv)
    msg = iv + cipher.encrypt(b'Attack at dawn')
    

    RSA 加密(使用像 OAEP 这样的适当填充,因为教科书 RSA 被严重破坏了):

    from Crypto.Cipher import PKCS1_OAEP
    from Crypto.PublicKey import RSA
    
    message = aeskey
    random_generator = Random.new().read
    rsakey = RSA.generate(1024, random_generator)
    cipher = PKCS1_OAEP.new(rsakey.publickey())
    ciphertext = cipher.encrypt(message)
    

    并且只发送msgciphertext。解密是类似的,但是是反向的,因为您首先必须从 RSA 密文中恢复 AES 密钥。使用 AES 解密时不要忘记切掉 IV。

    【讨论】:

    • 有没有我可以在没有额外的 AES 密钥的情况下做到这一点?因为我真的在寻找仅使用公钥/私钥加密/解密和签名/验证文件。
    • 我是说,如果文件太大,那么你不能用普通或填充的 RSA 加密/解密它。您需要混合加密或 RSA-KEM。签名和验证会起作用,因为 RSA 签名是文件内容哈希的加密(使用私钥),因此与大小无关。
    • 我的教授想要的是仅使用密钥对进行加密/签名和解密/验证,因此当您向某人发送内容时,他们所需要的只是加密文件和其中一个密钥。您所说的签名是发送 3 个东西,文件,签名,公钥。他希望在签名时将签名包含在文件中,因此您只需要公钥即可进行验证。
    • 一个仍然只需要公钥来验证,一个仍然只需要私钥来解密。这只是一个级联。您可以将加密的msg+ciphertext 视为单个密文。但是签名不包含数据,就像您的手写签名不包含您的血肉一样。
    猜你喜欢
    • 2018-01-13
    • 2013-12-26
    • 2020-04-07
    • 2023-03-17
    • 2012-01-28
    • 1970-01-01
    • 1970-01-01
    • 2018-07-03
    • 2011-07-11
    相关资源
    最近更新 更多