在Python 3.X中实施RSA / pkcs1_padding

问题描述 投票:1回答:2

我正在尝试将代码从Python 2.7移至Python 3.5

下面是Python 2.7中的当前实现,该实现使用M2Crypto

import M2Crypto
import hashlib
from binascii import hexlify

# Generates the signature of payload
def getSign(payload_xml):
    # SHA-1 digest of the payload
    dig = myDigest(payload_xml)
    # Loading the privateKey PEM file
    private_key = M2Crypto.RSA.load_key('privatekey')
    # Generating base 16 and encoding
    signature = hexlify(private_key.private_encrypt(dig, M2Crypto.RSA.pkcs1_padding))
    return signature

# To generate sha-1 digest of payload
def myDigest(payload):

    # This will give base 16 of SHA-1 digest
    digest_1 = hashlib.sha1(payload).hexdigest()
    return digest_1

sign = getSign(<mypayload_xml>)

这是Python 3.5中使用pycryptodome的新实现

from Crypto.PublicKey import RSA
import hashlib
from Crypto.Cipher import PKCS1_v1_5
from binascii import hexlify

def myDigest(payload):
    # This will give base 16 of SHA-1 digest
    digest_1 = hashlib.sha1(payload.encode('utf-8')).hexdigest()
    return digest_1

def getSign(payload_xml):
    # SHA-1 digest of the payload
    dig = myDigest(payload_xml)
    with open('privatekey', 'r') as pvt_key:
        miPvt = pvt_key.read()
    rsa_key_obj = RSA.importKey(miPvt)
    cipher = PKCS1_v1_5.new(rsa_key_obj)
    cipher_text = cipher.encrypt(dig.encode())
    base_16_new = hexlify(cipher_text)
    return base_16_new

new_sign = getSign(<mypayload_xml>)

但是,对于相同的有效负载,签名是不同的。有人可以帮忙吗适当的解决方案?

python-3.x python-2.7 ssl rsa
2个回答
0
投票

在第二个代码段中,您正在使用PKCS#1 1.5算法(Crypto.Cipher.PKCS1_v1_5模块)加密 SHA-1摘要。那不是签名。

相反,您应该使用Crypto.Signature.pkcs1_15pycryptodome模块。例如,请参见取自here的示例:

from Crypto.Signature import pkcs1_15
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA

message = 'To be signed'
key = RSA.import_key(open('private_key.der').read())
h = SHA256.new(message)
signature = pkcs1_15.new(key).sign(h)

0
投票

正如我在评论中已经提到的,PyCryptodome的encryptencrypt仅可用于通过public密钥进行加密,并通过private密钥进行解密。 PyCryptodome与M2Crypto的decryptdecrypt没有1:1对应关系,它允许使用私钥加密和使用公钥解密。取而代之的是,PyCryptodome使用private_encryptpublic_decrypt,但是详细信息的工作方式有所不同,因此signsign 不会生成相同的签名(对于相同的密钥和消息) :


verify实现verify中描述的RSASSA-PKCS1-V1_5填充。消息的哈希值private_encrypt如下填充:

sign

[sign标识摘要并且用于SHA1(其他摘要请参见RFC 8017, chapter 8.2):

H

0x00 || 0x01 || PS || 0x00 || ID || H ID个填充字节,因此填充的消息具有模数的长度。


here的填充与RSASSA-PKCS1-V1_5填充的不同之处在于,不会自动添加(0x)30 21 30 09 06 05 2b 0e 03 02 1a 05 00 04 14 。为了使PS0xFF生成相同的签名,必须在private_encrypt的上下文中manually添加ID,例如:

sign

作为站点注释,原始代码中有一个错误:private_encrypt期望数据为二进制格式,而不是十六进制字符串。


相应的PyCryptodome代码可以例如:

ID

[使用以下测试密钥(为简单起见,为512位密钥):

private_encrypt

两个代码都提供以下消息:

import M2Crypto
import hashlib
from binascii import hexlify, unhexlify

key = """-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----"""

def getSign(payload_xml):
    dig = myDigest(payload_xml)
    private_key = M2Crypto.RSA.load_key_string(key)
    signature = hexlify(private_key.private_encrypt(unhexlify('3021300906052b0e03021a05000414' + dig.hexdigest()), M2Crypto.RSA.pkcs1_padding))
    return signature

def myDigest(payload_xml):
    digest_1 = hashlib.sha1(payload_xml)
    return digest_1 

sign = getSign(b"Hello world")
print("M2Crypto: " + sign)

以下签名:

private_encrypt

结论:可以通过简单地添加from Crypto.Signature import pkcs1_15 from Crypto.Hash import SHA1 from Crypto.PublicKey import RSA key = """-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----""" def getSign(payload_xml): dig = myDigest(payload_xml) private_key = RSA.import_key(key) signature = pkcs1_15.new(private_key).sign(dig) return signature def myDigest(payload_xml): digest_1 = SHA1.new(payload_xml) return digest_1 sign = getSign(b'Hello world') print("PyCryptodome: " + sign.hex()) 来修改M2Crypto代码,使结果与PyCryptodome代码相对应。然而,相反的方法似乎是不可能的,因为PyCryptodome实现会自动添加key = """-----BEGIN PRIVATE KEY----- MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEA2gdsVIRmg5IH0rG3 u3w+gHCZq5o4OMQIeomC1NTeHgxbkrfznv7TgWVzrHpr3HHK8IpLlG04/aBo6U5W 2umHQQIDAQABAkEAu7wulGvZFat1Xv+19BMcgl3yhCdsB70Mi+7CH98XTwjACk4T +IYv4N53j16gce7U5fJxmGkdq83+xAyeyw8U0QIhAPIMhbtXlRS7XpkB66l5DvN1 XrKRWeB3RtvcUSf30RyFAiEA5ph7eWXbXWpIhdWMoe50yffF7pW+C5z07tzAIH6D Ko0CIQCyveSTr917bdIxk2V/xNHxnx7LJuMEC5DcExorNanKMQIgUxHRQU1hNgjI sXXZoKgfaHaa1jUZbmOPlNDvYYVRyS0CIB9ZZee2zubyRla4qN8PQxCJb7DiICmH 7nWP7CIvcQwB -----END PRIVATE KEY-----""" ,这显然是无法避免的。

© www.soinside.com 2019 - 2024. All rights reserved.