Python中如何实现RSA加密,有PHP源码参考

最近对接第三方接口,有一个地方需要用 RSA 加密 ,接口方对 RSA 加密进行了修改,用 PYTHON 去写加密方法,看对方的 PHP 代码貌似把要加密的对象用\0 填充到 256 位 但是我用 pythonRSA 加密最多只能加密 245 位 这种情况应该咋处理? 附对面的 PHP 源码和我的 RSA 加密方法

对方给的 PHP 加密代码
<?php
$public_text = “123”;
$public_key_content="-----BEGIN CERTIFICATE-----
MIIEIjCCAwqgAwIBAgIFEDYSGTEwDQYJKoZIhvcNAQEFBQAwITELMAkGA1UEBhMC
Q04xEjAQBgNVBAoBCUNGQ0EgT0NBMTAeFw0xNTExMjMwOTE4NTZaFw0yMDExMjMw
OTE4NTZaMHcxCzAJBgNVBAYTAkNOMRIwEAYDVQQKEwlDRkNBIE9DQTExEDAOBgNV
BAsTB0hFTElQQVkxGTAXBgNVBAsTEE9yZ2FuaXphdGlvbmFsLTExJzAlBgNVBAMU
HjA1MUBoZWxpcGF5QDM0NDAxMDEwMDAyMzg4NTlAMTCCASIwDQYJKoZIhvcNAQEB
BQADggEPADCCAQoCggEBAKcZmf6kn/swvVeqNODJJ46alD9RCFH/KkbbJjiVzAPg
uCG7NWZqFxwpHDSPeyc+JByBs02OI6zrZ00I2c/OoW006BtZlRugcg4Yxd4s4ih6
nTg4yCv0yT8bxtDmAGkPq/rf21rtDtWjKb4/GKYhVPp/fFlia4PT1xlCFww9qcuD
MhfCbpy1Q6Kg85uX4B3hUkl/7KAxYsG2Xb7ikOOMt+YWAPhLIoCdUe70av0Mu1LZ
x4GGTi0Guibg6eMgbxkHgbC6Xr47R6zjwPKKV+aMGpGf0WsyGBKIEDrJGXKeHKIQ
6O04ipwid8TQy8y5Hw5gi2JzHaXqv9eiK1w5HoL9x2ECAwEAAaOCAQkwggEFMB8G
A1UdIwQYMBaAFNHb6YiC5d0aj0yqAIy+fPKrG/bZMB4GCSqBHIahIAQBAwQREw80
NDAxMDEwMDAyMzg4NTkwSAYDVR0gBEEwPzA9BghggRyG7yoBATAxMC8GCCsGAQUF
BwIBFiNodHRwOi8vd3d3LmNmY2EuY29tLmNuL3VzL3VzLTE0Lmh0bTA3BgNVHR8E
MDAuMCygKqAohiZodHRwOi8vY3JsLmNmY2EuY29tLmNuL1JTQS9jcmwyMzg5LmNy
bDALBgNVHQ8EBAMCA+gwHQYDVR0OBBYEFAhR4S9aru6pskVYEzggUllxjJwwMBMG
A1UdJQQMMAoGCCsGAQUFBwMCMA0GCSqGSIb3DQEBBQUAA4IBAQA0ZumHjLnhG3am
2/sT4fw/bMWrTUimNNY1tJ7bs3D0vRh4ZoHrX1fD8W2tsQqmnEOKBylmi3tIBhdb
4lI/AGigq4VUVYRYHGavNi2vVlzQaVFtfUq4bvuydR4EPe6kNkdNNvF2qxoj7KxB
dGMHdgwz4FnLPwy1VY+IRgABzJI1svjKrmWSeSEgX1vGZq/ItE1es2/P1tDJ2CiX
Z8cVqxamH1oshiYlpw1mObyQjUgCftK1kymwa7W37ohpePX0vKxfLkETBNbdqkAV
l+jBayMU7Tu6tLXj1Y/iO/AmsbfFmHAtKTivPd63r16HUxbZTmjMwFpTN8COhakJ
ocbql7dZ
-----END CERTIFICATE-----
";
$public_key= openssl_pkey_get_public($public_key_content);
openssl_public_encrypt(str_pad($public_text, 256, “\0”, STR_PAD_LEFT), $encrypted, $public_key, OPENSSL_NO_PADDING);
echo base64_encode($encrypted);
?>

我的 PYTHON 加密方法
def RSA_encrypt(message):
# message = ‘hello ghost, this is a plian text’
with open(‘ghost-public.pem’,“r”) as f:
key = f.read()
rsakey = RSA.importKey(key) # 导入读取到的公钥
cipher = Cipher_pkcs1_v1_5.new(rsakey) # 生成对象
cipher_text = base64.b64encode(cipher.encrypt(message.encode(encoding=“utf-8”))) # 通过生成的对象加密 message 明文,注意,在 python3 中加密的数据必须是 bytes 类型的数据,不能是 str 类型的数据

return cipher_text
Python中如何实现RSA加密,有PHP源码参考


6 回复

感觉你俩的明文补全方式不一样,php 是手动补的"\0",python 是 pkcs1 padding


from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
import base64

# 生成RSA密钥对
def generate_rsa_keys():
    key = RSA.generate(2048)
    private_key = key.export_key()
    public_key = key.publickey().export_key()
    return private_key, public_key

# RSA加密
def rsa_encrypt(public_key_str, plaintext):
    # 加载公钥
    public_key = RSA.import_key(public_key_str)
    
    # 使用PKCS1_OAEP填充方案(推荐)
    cipher = PKCS1_OAEP.new(public_key)
    
    # 加密数据
    encrypted_data = cipher.encrypt(plaintext.encode('utf-8'))
    
    # 转换为base64方便传输
    return base64.b64encode(encrypted_data).decode('utf-8')

# RSA解密
def rsa_decrypt(private_key_str, encrypted_b64):
    # 加载私钥
    private_key = RSA.import_key(private_key_str)
    
    # 使用PKCS1_OAEP填充方案
    cipher = PKCS1_OAEP.new(private_key)
    
    # 解码base64
    encrypted_data = base64.b64decode(encrypted_b64)
    
    # 解密数据
    decrypted_data = cipher.decrypt(encrypted_data)
    
    return decrypted_data.decode('utf-8')

# 使用示例
if __name__ == "__main__":
    # 1. 生成密钥对
    private_key, public_key = generate_rsa_keys()
    print("公钥:\n", public_key.decode())
    print("\n私钥:\n", private_key.decode())
    
    # 2. 加密数据
    message = "Hello, RSA Encryption!"
    encrypted = rsa_encrypt(public_key, message)
    print(f"\n加密后的数据 (base64): {encrypted}")
    
    # 3. 解密数据
    decrypted = rsa_decrypt(private_key, encrypted)
    print(f"解密后的数据: {decrypted}")

安装依赖:

pip install pycryptodome

核心要点:

  1. 密钥生成:使用RSA.generate()生成2048位密钥对
  2. 填充方案:必须使用PKCS1_OAEP填充(PHP对应OPENSSL_PKCS1_OAEP_PADDING
  3. 编码处理:加密后建议用base64编码便于传输

对应PHP代码参考:

// PHP端加密(对应Python的rsa_encrypt)
$publicKey = openssl_pkey_get_public($publicKeyStr);
openssl_public_encrypt($plaintext, $encrypted, $publicKey, OPENSSL_PKCS1_OAEP_PADDING);
$encryptedB64 = base64_encode($encrypted);

// PHP端解密(对应Python的rsa_decrypt)
$privateKey = openssl_pkey_get_private($privateKeyStr);
openssl_private_decrypt(base64_decode($encryptedB64), $decrypted, $privateKey, OPENSSL_PKCS1_OAEP_PADDING);

注意: Python和PHP之间互通时,确保双方使用相同的填充方案和密钥格式。

总结:用pycryptodome库,注意填充方案要和PHP保持一致。

这个是我的初始加密方式 我用\0 在加密对象左侧填充到 245 长度加密出来的结果第三方也解密不了 加密到 256 位的话 RSA 长度不行 至于 RSA 切割加密感觉更不行了, 长度估计都跟对面给出来的长度不一样,RSA 公钥加密最恶心的是每次加密出来的结果都不一样, 除了私钥根本没法验证 更恶心的是我还没有私钥

搜索: python rsa no padding

还有, no padding 每次的结果应当是一样的

求一份 Python3 的无填充代码 网上找的代码一运行就报错
NotImplementedError: Use module Crypto.Cipher.PKCS1_OAEP instead
我用的这段代码 ,引用位置和引用文件都已经改过了
author__ = ‘owen’
date = ‘2017-11-22’

import base64
from Crypto.PublicKey import RSA

ENCRYPT_SALT = b’12345678901234567890123456789012345679801234’ # 44 char
RSA_KEY_PATH = ‘./’

class MyRSACrypto:


def cryptor( cls, plain_text ):

# print("\n================ crypto ========================\n")

if( not isinstance( plain_text, bytes ) ):
plain_text = plain_text.encode()

salt = ENCRYPT_SALT
base_dir = RSA_KEY_PATH

with open(base_dir + ‘master-public.pem’) as fp:
public_key = fp.read()

if(not public_key):
return None

rsa_cryptor = RSA.importKey( public_key )

plain_text = ( plain_text + salt )

# 无填充方式公钥加密
cipher_text = rsa_cryptor.encrypt( plain_text, 0 )

pad_cnt = 64 - len(cipher_text[0])

cipher_text_rsa = pad_cnt * b’\0’ + cipher_text[0]

cipher_text_b64 = base64.b64encode( cipher_text_rsa )

return cipher_text_b64.decode()[:-2]



def decryptor( cls, cipher_text_b64 ):

# print("\n================ decrypto ========================\n")
if( not isinstance( cipher_text_b64, bytes ) ):
cipher_text_b64 = cipher_text_b64.encode()

base_dir = RSA_KEY_PATH

with open( base_dir + ‘master-private.pem’ ) as fp:
private_key = fp.read()

if(not private_key):
return None

rsa_decryptor = RSA.importKey( private_key )

cipher_text = base64.b64decode( cipher_text_b64 + b"==" )

# 无填充方式私钥解密
plain_text = rsa_decryptor.decrypt( cipher_text )

return plain_text.decode()[:20]


if name == ‘main’:

text = ‘31’ * 10

cipher_text = MyRSACrypto.cryptor( text )
print(cipher_text)

plain_text = MyRSACrypto.decryptor( cipher_text )
print( plain_text )

谢谢大神 解出来了 !!!

回到顶部