【问题标题】:Decrypt in Python a string encrypted in PHP with Halite/Libsodium在 Python 中解密使用 Halite/Libsodium 在 PHP 中加密的字符串
【发布时间】:2020-01-05 17:43:47
【问题描述】:

我使用这个 PHP 代码来加密一个字符串:

use ParagonIE\Halite\KeyFactory;
use ParagonIE\Halite\Symmetric\Crypto as Symmetric;
use ParagonIE\HiddenString\HiddenString;
define("SECURE_PLACE", '/home/htdocs/secure_place/encryption.key');

/*
//already generated
$enc_key = KeyFactory::generateEncryptionKey();
KeyFactory::save($enc_key, $secure_place);
*/

$enc_key = KeyFactory::loadEncryptionKey(SECURE_PLACE);

$string = "String to be encrypted";

$cipherstring = \ParagonIE\Halite\Symmetric\Crypto::encrypt(
  new HiddenString(
   $string
  ),
    $enc_key 
);

我可以用 PHP 解密它:

$string = \ParagonIE\Halite\Symmetric\Crypto::decrypt(
    $cipherstring,
    $enc_key
);

但我需要在 Python3 中完成此操作,因为我将 POST 将加密字符串发送到 AWS lambda handler.py 函数。

我知道Halite 是一个 PHP 库,但我也知道它是 Libsodium 的包装器,它是“一个可移植、可交叉编译、可安装、可打包的 NaCl 分支,具有兼容的 API 和扩展的API 可进一步提高可用性。”

有谁知道我应该在 Python3 中使用哪个依赖项(如果可能,提供代码)来解密字符串?我想我需要将enc_key 设置为 Lambda 环境变量。

【问题讨论】:

    标签: php python encryption libsodium


    【解决方案1】:

    更简单的跨语言秘密

    虽然可以尝试弄清楚如何在 Python 中重新创建 Halite 的加密,但我建议在下面移动一层抽象并直接使用 libsodium 的 high level encryption API。

    加密数据的PHP代码就变成了:

    $nonce = \Sodium\randombytes_buf(\Sodium\CRYPTO_SECRETBOX_NONCEBYTES);
    $string = "String to be encrypted";
    
    $cipherstring = sodium_crypto_secretbox(
        $string, $nonce, $enc_key->getRawKeyMaterial());
    
    $encoder = Halite::chooseEncoder(Halite::ENCODE_BASE64URLSAFE);
    $cipherstring = $encoder($cipherstring);
    $nonce = $encoder($nonce);
    

    现在你只需要将随机数和密码字符串获取到 Python,如果你想继续使用 base64 并使用 pynacl 包,代码如下所示:

    import nacl.secret
    import nacl.encoding
    
    decoder = nacl.encoding.URLSafeBase64Encoder
    
    box = nacl.secret.SecretBox(
        # Key goes here, doesn't necessarily have to be base64-encoded
        "EtUEpKO2q2clEO5HRL0mk-DtQyHIt7Wf_6t1dSacrFI=", decoder
    )
    
    nonce = decoder.decode("Maxm2hN-0C4zqE3viwFVJO03I8eWJcm2")
    ciphertext = decoder.decode("TpXjfPonHzBQnObD9JPtPhQc-wKIIq8Y-4o_Um3UtVut-ixCDp4=")
    
    print(box.decrypt(ciphertext, nonce))
    

    基本原理

    我之所以这么说是因为如果您深入研究 Halite 的 encryption code,他们实际上已经手动重新实现了许多 secretbox 的功能。似乎 Halite 真的只设计用于 PHP。通过直接使用 libsodium,您可以避免 Halite 更改其协议并破坏您的代码的可能性。

    【讨论】:

    • 不错。我会试试的,让你知道。但似乎$nonce 和$enc_key 是由PHP 代码动态生成的,对吧?如何将它们作为我的 lambda py 部分的 envars?
    • 你说的$enc_key可以作为环境变量的一部分存储在lambda上。不需要重新生成它。但是,$nonce 需要作为 POST 的一部分发送,就像密文一样。
    • 现在试试。 PHP 生成了一个巨大的密钥,例如31400400f253bdb365f187d53bd8175e4013acf2809f5c5d0b7c86c2a3385a89dfecfeb0cd941a8cb459af59f1acd5372fb16a503c8495cd6e811185cdd3784a2de52bf48c773f9377582e74a83c5e5b9ff8f8e8afea23fc90816ec2752f36e9dc9b1563。我把钥匙放在你的python代码上,它正在抛出nacl.exceptions.ValueError: The key must be exactly 32 bytes long
    • 该密钥是十六进制编码的,将行改为box = nacl.secret.SecretBox(..., nacl.encoding.HexEncoder)
    • 啊,实际上,Halite 在将密钥保存到文件时添加了一些额外的东西。尝试使用 $encoder = Halite::chooseEncoder(Halite::ENCODE_BASE64URLSAFE); $encoder($enc_key->getRawKeyMaterial()); 将其删除
    猜你喜欢
    • 2012-01-03
    • 2010-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-23
    • 2013-06-11
    • 2015-06-18
    • 2018-01-24
    相关资源
    最近更新 更多