Python中的openssl_seal()

6 投票
3 回答
1622 浏览
提问于 2025-04-15 22:20

为了连接服务器,我发现使用PHP时需要用到 openssl_seal() 这个函数。这没问题,但我想用Python来实现。我现在还没找到一个和 openssl_seal() 功能相同的函数。

你能帮我吗?

这是 openssl_seal() 的功能:

描述 int openssl_seal ( string $data , string &$sealed_data , array &$env_keys , array $pub_key_ids )

openssl_seal() seals (encrypts) data by using RC4 with a randomly generated
secret key. The key is encrypted with each of the public keys associated
with the identifiers in pub_key_ids and each encrypted key is returned in
env_keys. This means that one can send sealed data to multiple recipients
(provided one has obtained their public keys). Each recipient must receive
both the sealed data and the envelope key that was encrypted with the
recipient's public key.

3 个回答

0

因为我还不能发评论,所以我想补充一下Gabi Nagy的回答。虽然他们的回答描述了一个正确的算法,但这和使用openssl_seal()函数是不一样的。

OpenSSL不允许未加密的密钥泄露到OpenSSL的结构之外。它会在内部生成一个密钥,并把它保存在那里,只给你一个加密后的密钥。关键的区别在于,当OpenSSL清理它的结构时,它应该以安全的方式处理未加密的密钥。

2

openssl_seal的工作流程是这样的:

  1. 从证书中提取公钥。
  2. 生成一个128位(16字节)长的随机密钥(这个密钥会用来加密消息,因为对称加密算法速度更快)。
  3. 使用PKCS #1对随机密钥进行加密。
  4. 用一个安全的加密方法和随机密钥来加密消息(注意,ARC4现在不再被认为是安全的,PHP强烈建议使用cipher_algo参数明确指定一个安全的加密方法)。
  5. 输出加密后的随机密钥和加密后的消息。

接收方可以用他们的私钥解密加密后的随机密钥,然后用这个随机密钥解密加密后的消息。

由于在Python的标准库中没有办法做到这一点,我就分享一下我尝试过的三种方法:

# pyca/cryptography (cryptography.io) version
# pip install cryptography

import os

import cryptography
from cryptography import x509


message = 'Super secret secret message'
message = message.encode('utf-8')
certificate_data = open('/path/to/certificate.cer', 'r').read()
certificate_data = certificate_data.encode('utf-8')
certificate = cryptography.x509.load_pem_x509_certificate(data=certificate_data, backend=cryptography.hazmat.backends.default_backend())
public_key = certificate.public_key()
random_key = os.urandom(16)
encrypted_random_key = public_key.encrypt(plaintext=random_key, padding=cryptography.hazmat.primitives.asymmetric.padding.PKCS1v15())
print(encrypted_random_key)
algorithm = cryptography.hazmat.primitives.ciphers.algorithms.AES(random_key)
cipher = cryptography.hazmat.primitives.ciphers.Cipher(algorithm=algorithm, mode=None, backend=cryptography.hazmat.backends.default_backend())
encryptor = cipher.encryptor()
encrypted_message = encryptor.update(message)
print(encrypted_message)

.

# M2Crypto version
# pip install pip install git+https://gitlab.com/m2crypto/m2crypto@python3

import M2Crypto


message = 'Super secret secret message'
message = message.encode('utf-8')
certificate = M2Crypto.X509.load_cert('/path/to/certificate.cer')
public_key = certificate.get_pubkey()
rsa_pub = public_key.get_rsa()
random_key = M2Crypto.Rand.rand_bytes(16)
encrypted_random_key = rsa_pub.public_encrypt(random_key, M2Crypto.RSA.pkcs1_padding)
print(encrypted_random_key)
cipher = M2Crypto.EVP.Cipher(alg='aes_128_cbc', key=random_key, iv=b'', op=M2Crypto.encrypt)
encrypted_message = cipher.update(message)
encrypted_message += cipher.final()
print(encrypted_message)

.

# PyCrypto version
# Update: PyCrypto 2.x is unmaintained, obsolete, and contains security vulnerabilities!!!
# pip install pycrypto

# Please bear in mind that PyCrypto cannot handle x509 certificates.
# You will have to extract the public_key to a pem file:
# openssl x509 -inform pem -in certificate.cer -pubkey -noout > public_key.pem

from Crypto import Random
from Crypto.Cipher import ARC4
from Crypto.Cipher import PKCS1_OAEP
from Crypto.Cipher import PKCS1_v1_5
from Crypto.PublicKey import RSA


message = 'Super secret secret message'
message = message.encode('utf-8')
public_key_data = open('/path/to/public_key.pem', 'r').read()
public_key = RSA.importKey(public_key_data)
random_key = Random.new().read(16)
cipher = PKCS1_v1_5.new(public_key)
encrypted_random_key = cipher.encrypt(random_key)
print(encrypted_random_key)
cipher = ARC4.new(random_key)
encrypted_message = cipher.encrypt(message)
print(encrypted_message)

你可以查看我的帖子,地址是 => http://helpfulsheep.com/2017-09-01-openssl-seal-in-python/

2

这篇博客详细描述了openssl_seal()内部发生的事情。里面还有一个用Java实现的例子。

从这些内容来看,我觉得用pyopenssl在Python中做一个类似的实现应该比较简单(就像“这个证明留给读者自己做”那种简单),pyopenssl支持RC4,还有一个更新的、更专注于这个目的的库tlslite

撰写回答