简体   繁体   English

openssl_decrypt() 无法解密在命令行上加密的文本

[英]openssl_decrypt() can't decrypt text encrypted on the commandline

For testing purposes, I wrote encrypt.bash and decrypt.bash , to prove that the encrypted data saved to encrypted.txt can successfully be decrypted.出于测试目的,我编写了encrypt.bashdecrypt.bash ,以证明保存到encrypted.txt中的加密数据可以成功解密。

Here are the bash files:以下是 bash 文件:

encrypt.bash加密.bash

#!/bin/bash

message="This is my message, I hope you can see it. It's very long now."
key="sup3r_s3cr3t_p455w0rd"

echo "$message" | openssl enc \
    -aes-256-ctr \
    -e \
    -k "$key" \
    -iv "504914019097319c9731fc639abaa6ec" \
    -out encrypted.txt

decrypt.bash解密.bash

#!/bin/bash

key="sup3r_s3cr3t_p455w0rd"

decrypted=$(openssl enc \
    -aes-256-ctr \
    -d \
    -k "$key" \
    -iv "504914019097319c9731fc639abaa6ec" \
    -in encrypted.txt)

echo "Decrypted message: $decrypted"

Running bash decrypt.bash outputs the following:运行bash decrypt.bash输出以下内容:

Decrypted message: This is my message, I hope you can see it.解密消息:这是我的消息,希望你能看到。 It's very long now.现在很长。

Where I'm struggling is reading the encrypted.txt file with PHP and decrypting it with openssl_decrypt .我正在努力的地方是使用 PHP 读取encrypted.txt文件并使用openssl_decrypt对其进行解密。 As far as I can tell, I'm using all the same settings, and working with binary data correctly, but obviously I'm doing something wrong.据我所知,我使用所有相同的设置,并正确处理二进制数据,但显然我做错了什么。

decrypt.php解密.php

<?php
$key = "sup3r_s3cr3t_p455w0rd";

$encrypted = file_get_contents("encrypted.txt");
$iv = hex2bin("504914019097319c9731fc639abaa6ec");
$decrypted = openssl_decrypt(
    $encrypted,
    "aes-256-ctr",
    $key,
    0,
    $iv,
);

echo "Decrypted message: $decrypted";

Running php decrypt.php outputs the following:运行php decrypt.php输出以下内容:

Decrypted message: ��c�������Pb�j�� 解密消息:��c�������Pb�j��

It seems so simple when boiled down like this, but I am struggling to see where the bug exists in my code.像这样归结起来似乎很简单,但我很难找出代码中存在的错误。

The -k option does not specify a key, but a password. -k 选项不指定密钥,而是指定密码。 From this password, together with a randomly generated 8 bytes salt, the key is derived using the derivation function EVP_BytesToKey() .从此密码和随机生成的 8 字节盐一起,使用派生函数EVP_BytesToKey()派生密钥。 The encrypted data is returned in OpenSSL format, which consists of the ASCII encoding of Salted__ , followed by the 8 bytes salt and the actual ciphertext.加密后的数据以 OpenSSL 格式返回,该格式由Salted__的 ASCII 编码,后跟 8 个字节的 salt 和实际密文组成。

A simplified PHP implementation of this key derivation function that is sufficient here is (since the IV is explicitly specified here with -iv, it is not derived along with the key):这个密钥派生函数的简化 PHP 实现在这里就足够了(因为这里用 -iv 明确指定了 IV,所以它不与密钥一起派生):

// from: https://gist.github.com/ezimuel/67fa19030c75052b0dde278a383eda1b
function EVP_BytesToKey($salt, $password) {
    $bytes = '';
    $last = '';
    
    // 32 bytes key
    while(strlen($bytes) < 32) {
        $last = hash('sha256', $last . $password . $salt, true); // md5 before v1.1.0 
        $bytes.= $last;
    }
    return $bytes;
}

Extracting the salt and actual ciphertext is:提取盐和实际密文是:

$password = "sup3r_s3cr3t_p455w0rd";
$encrypted = file_get_contents("<path to enc file>");
$salt = substr($encrypted, 8, 8);
$key = EVP_BytesToKey($salt, $password);
$ciphertext = substr($encrypted, 16);

In addition, since the raw data is passed, the corresponding OPENSSL_RAW_DATA flag must be set:此外,由于传递的是原始数据,因此必须设置相应的OPENSSL_RAW_DATA标志:

$iv = hex2bin("504914019097319c9731fc639abaa6ec");
$decrypted = openssl_decrypt($ciphertext, "aes-256-ctr", $key, OPENSSL_RAW_DATA, $iv);

Note that as of OpenSSL v1.1.0 the default digest is SHA256, before MD5.请注意,从 OpenSSL v1.1.0 开始,默认摘要是 SHA256,在 MD5 之前。 The digests used in EVP_BytesToKey() must be identical for compatibility.为了兼容性, EVP_BytesToKey()中使用的摘要必须相同。 Also be aware that EVP_BytesToKey() is considered insecure nowadays.还要注意EVP_BytesToKey()现在被认为是不安全的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM