Python 使用pycrypto(RSA)签名和验证数据

Python 使用pycrypto(RSA)签名和验证数据,python,pycrypto,Python,Pycrypto,我正试图熟悉pycrypto模块,但由于缺乏清晰的文档,所以很难做到这一点 首先,我想了解签名和验证数据。有人能举个例子说明这是怎么写的吗?这是 确保您使用的是pycryptome,而不是pycrypto(未维护!) pycryptodome可以与pip安装pycryptodome一起安装 import Crypto.Hash.MD5 as MD5 import Crypto.PublicKey.RSA as RSA import Crypto.PublicKey.DSA as DSA impo

我正试图熟悉pycrypto模块,但由于缺乏清晰的文档,所以很难做到这一点


首先,我想了解签名和验证数据。有人能举个例子说明这是怎么写的吗?

这是

确保您使用的是
pycryptome
,而不是
pycrypto
(未维护!)

pycryptodome可以与
pip安装pycryptodome一起安装

import Crypto.Hash.MD5 as MD5
import Crypto.PublicKey.RSA as RSA
import Crypto.PublicKey.DSA as DSA
import Crypto.PublicKey.ElGamal as ElGamal
import Crypto.Util.number as CUN
import os

plaintext = 'The rain in Spain falls mainly on the Plain'

# Here is a hash of the message
hash = MD5.new(plaintext).digest()
print(repr(hash))
# '\xb1./J\xa883\x974\xa4\xac\x1e\x1b!\xc8\x11'

for alg in (RSA, DSA, ElGamal):
    # Generates a fresh public/private key pair
    key = alg.generate(384, os.urandom)

    if alg == DSA:
        K = CUN.getRandomNumber(128, os.urandom)
    elif alg == ElGamal:
        K = CUN.getPrime(128, os.urandom)
        while CUN.GCD(K, key.p - 1) != 1:
            print('K not relatively prime with {n}'.format(n=key.p - 1))
            K = CUN.getPrime(128, os.urandom)
        # print('GCD({K},{n})=1'.format(K=K,n=key.p-1))
    else:
        K = ''

    # You sign the hash
    signature = key.sign(hash, K)
    print(len(signature), alg.__name__)
    # (1, 'Crypto.PublicKey.RSA')
    # (2, 'Crypto.PublicKey.DSA')
    # (2, 'Crypto.PublicKey.ElGamal')

    # You share pubkey with Friend
    pubkey = key.publickey()

    # You send message (plaintext) and signature to Friend.
    # Friend knows how to compute hash.
    # Friend verifies the message came from you this way:
    assert pubkey.verify(hash, signature)

    # A different hash should not pass the test.
    assert not pubkey.verify(hash[:-1], signature)

根据以下文件:

您不应在实际代码中使用PyCrypto中的Crypto.PublicKey.RSA.sign函数:

注意:此函数执行简单的原始RSA解密(教科书)。在实际应用程序中,始终需要使用适当的加密填充,并且不应使用此方法直接对数据签名。否则可能会导致安全漏洞。建议改用模块Crypto.Signature.PKCS1\u PSS或Crypto.Signature.PKCS1\u v1\u 5

我最终使用了实现PKCS1_v1_5的。这个问题相当直截了当。其他。

以下是我创建的用于执行所有必要RSA功能(加密、解密、签名、验证签名和生成新密钥)的

rsa.py

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA512, SHA384, SHA256, SHA, MD5
from Crypto import Random
from base64 import b64encode, b64decode

hash = "SHA-256"

def newkeys(keysize):
    random_generator = Random.new().read
    key = RSA.generate(keysize, random_generator)
    private, public = key, key.publickey()
    return public, private

def importKey(externKey):
    return RSA.importKey(externKey)

def getpublickey(priv_key):
    return priv_key.publickey()

def encrypt(message, pub_key):
    #RSA encryption protocol according to PKCS#1 OAEP
    cipher = PKCS1_OAEP.new(pub_key)
    return cipher.encrypt(message)

def decrypt(ciphertext, priv_key):
    #RSA encryption protocol according to PKCS#1 OAEP
    cipher = PKCS1_OAEP.new(priv_key)
    return cipher.decrypt(ciphertext)

def sign(message, priv_key, hashAlg="SHA-256"):
    global hash
    hash = hashAlg
    signer = PKCS1_v1_5.new(priv_key)
    if (hash == "SHA-512"):
        digest = SHA512.new()
    elif (hash == "SHA-384"):
        digest = SHA384.new()
    elif (hash == "SHA-256"):
        digest = SHA256.new()
    elif (hash == "SHA-1"):
        digest = SHA.new()
    else:
        digest = MD5.new()
    digest.update(message)
    return signer.sign(digest)

def verify(message, signature, pub_key):
    signer = PKCS1_v1_5.new(pub_key)
    if (hash == "SHA-512"):
        digest = SHA512.new()
    elif (hash == "SHA-384"):
        digest = SHA384.new()
    elif (hash == "SHA-256"):
        digest = SHA256.new()
    elif (hash == "SHA-1"):
        digest = SHA.new()
    else:
        digest = MD5.new()
    digest.update(message)
    return signer.verify(digest, signature)
示例用法

import rsa
from base64 import b64encode, b64decode

msg1 = "Hello Tony, I am Jarvis!"
msg2 = "Hello Toni, I am Jarvis!"
keysize = 2048
(public, private) = rsa.newkeys(keysize)
encrypted = b64encode(rsa.encrypt(msg1, public))
decrypted = rsa.decrypt(b64decode(encrypted), private)
signature = b64encode(rsa.sign(msg1, private, "SHA-512"))
verify = rsa.verify(msg1, b64decode(signature), public)

print(private.exportKey('PEM'))
print(public.exportKey('PEM'))
print("Encrypted: " + encrypted)
print("Decrypted: '%s'" % decrypted)
print("Signature: " + signature)
print("Verify: %s" % verify)
rsa.verify(msg2, b64decode(signature), public)

@Noah McIllraith:对于RSA,不使用第二个参数
K
。对于ElGamal和DSA,需要提供长字符串或随机数据
K
。详细信息可以在题为“ElGamal和DSA算法”的章节中找到。@Noah McIlraith:对于签名的便携式存储,我认为纯文本字符串是最简单的。您可以使用
json.dumps(signature)
将其保存为json字符串,然后使用
json.loads
将其加载回(作为元组)。签名元组是否包含多个项?@Noah McIlraith:对于RSA,签名元组的长度为1,而对于DSA和ElGamal,签名元组的长度为2。我编辑了我的答案,以展示如何使用DSA和ElGamal。投票被否决,因为帮助(请参见RSA密钥类型的
help(key.sign)
说明)“注意:此函数执行简单的RSA解密(教科书)。在实际应用中,您始终需要使用正确的加密填充,并且不应使用此方法直接对数据进行签名。否则可能会导致安全漏洞。建议改用模块
Crypto.Signature.PKCS1_PSS
Crypto.Signature.PKCS1_v1_5
。”使用加密技术很难做到正确,违背图书馆的建议似乎真的是个坏主意……我觉得这让人困惑。rsa.encrypt的签名是
(message,pub_key)
,但是示例用法中的调用是
rsa.encrypt(msg1,private)
,这使得它看起来想要公钥,但实际上得到了私钥。另外,rsa.newkeys()返回两个值,其中一个是从另一个值派生的(特别是,
(x,x.public_key())
),这似乎与
(public,private)
的“纯英语”解释有很大不同,感谢您指出示例用法中的错误(现已更新)。要进行加密,您需要调用
rsa.encrypt(msg1,public)
。对于RSA,加密和验证需要公钥,解密和签名需要私钥。此外,您还可以从
私钥
获取
公钥
,但不可能从另一种方式获取。警告不要使用
pycrypto
!自2013年以来,至少有两个严重漏洞至今仍未解决。使用
pycryptodome
或替代!