使用 Python 从 OpenSSL PHP 库中解密

Posted

技术标签:

【中文标题】使用 Python 从 OpenSSL PHP 库中解密【英文标题】:Decrypting From OpenSSL PHP Library Using Python 【发布时间】:2022-01-13 19:20:18 【问题描述】:

我正在实现一个 RSA 加密方案,其中 mysql 数据库数据使用公钥加密,只有私钥可以用来解密它。

我已经设法使用 php openssl 库进行加密和解密,甚至添加了密码来保护私钥。

// $sRawText is the text string to encrypt.
// $sPublicKey is the public key stored on the server.
openssl_public_encrypt($sRawText, $sResult, $sPublicKey, OPENSSL_PKCS1_OAEP_PADDING);
// $sResult is the encrypted result which can then be stored in the database.

它非常适合我需要公开的所有目的,即在用户注册时添加新条目,或者在将来登录时验证详细信息。这是敏感数据,如联系信息,我只是偶尔使用。仅验证密码之类的数据仍然可以进行哈希处理,并且任何需要读取的内容都不会被加密。

这是我目前使用 PHP 解密的方式:

// $sPrivateKey is the matching private key.
// $sPassPhrase is the pass phrase (required to decrypt the result).
// $sRawBytes is the encrypted data from the database to decrypt.
$kRsaKey = openssl_pkey_get_private($sPrivateKey, $sPassPhrase);
openssl_private_decrypt($sRawBytes, $sResult, $kRsaKey, OPENSSL_PKCS1_OAEP_PADDING);
// $sResult will be the decrypted data.

这种解密方法的问题在于它都是在服务器上实时进行的。显然,将私钥存储在该服务器上会破坏大部分安全优势,因为任何对服务器有足够访问权限的人都可以轻松获取它。我能想出在服务器上使用 PHP 的最好方法是在每次解密时传递私钥和/或密码短语。但是,那里仍然存在密钥,并且还为在这些请求中拦截密钥和密码短语开辟了新的攻击途径。

我要做的是离线执行所有解密。因此,离线软件将提供文本文件中的加密数据,它会根据数据和预期操作将其转换为指令列表。私钥永远不会离开那个孤立的环境,密码永远不会在会话之间存储。

我在设置离线 PHP 环境时遇到了各种障碍,所以我认为尝试在 Python 中进行解密可能更容易。一切都应该是标准的,至少我是这么想的。

我目前正在这里尝试使用 Python RSA 库: https://stuvel.eu/python-rsa-doc/reference.html#exceptions

我不知道如何使用受密码保护的私钥进行解密。任何人都可以发布一个非常简单的示例,或者如果不对 Python RSA 库进行重大修改,它是否根本不兼容?离线解密的最简单方法是什么?

【问题讨论】:

我建议您看看另一个库,主要是 Cryptography:cryptography.io/en/latest/hazmat/primitives/asymmetric/rsa 这是一个经过良好测试且成熟的软件包,拥有强大的团队,并且没有密码保护密钥的问题。 谢谢 vaizki。目前该库运行良好,我已加载密钥。私有和公共都与 PHP 完全匹配。当我在 Python 中加密文本时,我得到一个可以在 Python 中成功解密的答案。但是,该加密值与 PHP 的加密值不同,如果我在 Python 中尝试,PHP 的加密值将无法解密。我希望查看哪些参数来解决差异问题? 想通了。它使用 SHA1 而不是 SHA256。 【参考方案1】:

好的,我现在想出答案就贴出来。

(1) 我们需要在 Python 中获取密码库。

在 Windows 上,进入命令提示符(不是 Python 解释器):

py -m pip install cryptography

如果上述方法不起作用,请尝试将 'py' 替换为 'python'。

(2) 私钥需要在文本文件“privatekey.txt”中。

(3) 使用此代码进行解密:

from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding

#privatekey.txt must contain the private key.
#passphrase_bytes must be the passphrase, and it needs to be in bytes (ie b'My Pass Phrase')

with open("privatekey.txt", "rb") as key_file:
private_key = serialization.load_pem_private_key(
    key_file.read(),
    password=passphrase_bytes,
)

#rawtext_bytes must have the bytes of the ciphertext to decrypt
plaintext = private_key.decrypt(
    rawtext_bytes,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA1()),
        algorithm=hashes.SHA1(),
        label=None
    )
)
#plaintext will now contain the result

【讨论】:

以上是关于使用 Python 从 OpenSSL PHP 库中解密的主要内容,如果未能解决你的问题,请参考以下文章

启动无法加载动态库php_openssl.dll

使用 php-jwt 库解码 firebase 自定义令牌时出现 openssl_verify() 错误

C++ OpenSSL库编译及使用(VS2017,Python)

WIN下如何在PHP扩展里打开openssl支持

PHP openssl函数库

错误:缺少 OpenSSL 库?在尝试安装python时