【问题标题】:How to get an openssl_decrypt binary output?如何获得 openssl_decrypt 二进制输出?
【发布时间】:2016-06-30 13:18:57
【问题描述】:

我正在尝试使用 openssl_encrypt/openssl_decrypt 加密/解密一些数据。目的如下:用户在GUI中输入一些数据,这些数据被加密并存储在数据库中。稍后它将仅针对某个用户配置文件进行检索和解密。

加密部分工作正常,因为我听从了同事的建议,即将输出包装到 bin2hex 函数中。
关键是我在解密数据时似乎无法获得二进制输出,即使我尝试使用 hex2bin 转换输出。我总是得到像“��Ps�1�_G�5�OUT”这样的输出。

我的想法已经不多了,实际上我现在真的不知道该怎么办。

这是我为测试此功能而编写的示例代码:

PHP

function encrypt($string) {

$cypher = 'aes-256-cbc';
$key = 's7aBkf4Ypn59bWviQziPDXyPasdaYlhQ';

$ivsize = openssl_cipher_iv_length($cypher);
$iv = openssl_random_pseudo_bytes($ivsize); 

$encripted = openssl_encrypt(
        $string, $cypher, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv
);

return $iv . $encripted;
}

function decrypt($string) {

$cypher = 'aes-256-cbc';
$key = 's7aBkf4Ypn59bWviQziPDXyPasdaYlhQ'; 

$ivsize = openssl_cipher_iv_length($cypher);
$iv = mb_substr($string, 0, $ivsize, '8bit');
$decrypted = mb_substr($string, $ivsize, null, '8bit');

$output = openssl_decrypt(
                $decrypted, $cifrado, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv
);

return $output;
}

HTML:

<!doctype html>
 <html>
    <head><title>TEST</title></head>
    <body>
        <div style='margin-left:250px;'>
            <form action="test.php" method="POST">
            Encrypt
            <input type="text" name="encrypt" value=''/>
            <input type="submit" name="send" value='Send'/>
            <br/><br/>
            <?php
            if (isset($_POST['encrypt']) && !empty($_POST['encrypt'])) {
                echo 'encrypted string: ' . bin2hex(encrypt($_POST['encrypt']));
            }
            ?>
            <br/>
            <br/>
            Decrypt
            <input type="text" name="decrypt" value=''/>
            <input type="submit" name="send" value='Send'/>
            <br/><br/>
            <?php
            if (isset($_POST['decrypt']) && !empty($_POST['decrypt'])) {
                echo 'decrypted string: ' . decrypt($_POST['decrypt']);
                var_dump(decrypt($_POST['decrypt']));
            }
            ?>
        </form>
</body>

任何想法或帮助将不胜感激。

我的 PHP 版本是 5.4.45-0+deb7u2。

提前致谢。

【问题讨论】:

  • “我在解密数据时似乎无法获得二进制输出,即使我尝试使用 hex2bin 转换输出。我总是得到像“Ps”这样的输出_G�5�OUT" - 我能说的最好的,非打印意味着你有二进制输出。
  • @jww 我在解密输出上尝试了 bin2hex,但没有任何改变。我需要一个人类可以阅读的输出,但似乎找不到解决方案。 :(
  • OpenSSL 有OPENSSL_buf2hexstr,但我不知道 pyOpenSSL 是否提供它。我最近与其中一位开发人员讨论了与BIOs 一起使用的b16hex 编码器。这对我来说很有意义,因为它是一个反复出现的请求,并且非常适合 I/O 一致性。如果库提供了 Base64 编码器和解码器,那么它也可以提供 Base32 和 Base16 编码器和解码器。
  • 加密例程中不需要“多字节”字符串处理,因为它们只是将数据视为字节块。

标签: php encryption pyopenssl


【解决方案1】:

根据@Zaph 的评论更新。

有一个小的语法错误。然而,代码的问题在于,在加密例程中,您只能使用以下之一:OPENSSL_RAW_DATA 或 OPENSSL_ZERO_PADDING。文档中有提到。

@Zaph 的评论:应该使用 PKCS#7 填充,它是一般填充。事实证明,PHP OpenSSL 的默认设置是 PKCS#7。所以,不要添加任何填充选项,你会得到正确的东西。

Openssl_encrypt() 在 CBC 或 ECB 模式下使用分组密码加密之前,将 PKCS7 填充添加到明文中。 Openssl_decrypt() 解密后去掉填充。

我使用的是 PHP 5.4.4。

因此,唯一需要的选项是:OPENSSL_RAW_DATA。

请注意,IV(初始化向量)每次都会更改并存储在输出字符串中。为什么?如果您提供相同的字符串和密码,则每次输出肯定是不同的字符串。

使加密的字符串能够安全地存储在任何地方。我有base64_encoded它。

演示地址:ideone.com

###加密: /** * 加密一个字符串 * *
* @Param 字符串 $data * @Param 字符串 $key * * @return 字符串 - base64_encoded
*/ 函数加密($data, $key) {

  $cypher = 'aes-256-cbc';  
  $ivSize  = openssl_cipher_iv_length($cypher);
  $ivData  = openssl_random_pseudo_bytes($ivSize);
  
  $encripted = openssl_encrypt($data, 
                              $cypher, 
                              $key, 
                              OPENSSL_RAW_DATA, 
                              $ivData);

                            
  return base64_encode($ivData  . $encripted);
}

###解密:

/**
 * Decrypt a string
 * 
 * @Param string $data 
 * @Param string $key
 * 
 * @return string  - original text   
 */ 
function decrypt($data, $key) {

  $cypher = 'aes-256-cbc';  
  $ivSize  = openssl_cipher_iv_length($cypher);

  $data = base64_decode($data);
  $ivData   = substr($data, 0, $ivSize);
   
  $encData = substr($data, $ivSize);

  $output = openssl_decrypt($encData, 
                            $cypher, 
                            $key, 
                            OPENSSL_RAW_DATA, 
                            $ivData);
  return $output;
}

运行它:

$srcText = "Hello World! - " . uniqid();
$key    = 's7aBkf4Ypn59bWviQziPDXyPasdaYlhQ';

$srcEncrypted  = '';
$srcDecrypted  = '';

$srcEncrypted = encrypt($srcText, $key);

$srcDecrypted = decrypt($srcEncrypted, $key);

var_dump($srcText, 
         $srcEncrypted, 
         $srcDecrypted, 
         $srcDecrypted == $srcText);

###示例输出:

string 'Hello World! - 5776adf944c52' (length=28)

string 'NOjIIMM0visDbJPmBsAMgH+OQbYiReLBSvzg5JVZTMUOCAtk3CO7FBNs/Dn/vE9s' (length=64)

string 'Hello World! - 5776adf944c52' (length=28)

boolean true

【讨论】:

  • @blinking_eyes,很高兴它有帮助。如果您觉得它有用,请接受它作为答案。 :) 任何问题,然后发表评论 :)
猜你喜欢
  • 2019-05-28
  • 2014-06-24
  • 2019-09-09
  • 1970-01-01
  • 2011-05-07
  • 2011-03-17
  • 1970-01-01
  • 2021-05-17
相关资源
最近更新 更多