【问题标题】:Decrypting string using OpenSSL works in terminal but not in PHP script使用 OpenSSL 解密字符串在终端中有效,但在 PHP 脚本中无效
【发布时间】:2014-01-12 21:37:18
【问题描述】:

我正在尝试解密文件,我可以使用以下字符串在终端中使用 OpenSSL 对其进行解密。

openssl -enc -d -aes-192-ecb -in file.crypt -out file -K 0123456789abcdef -iv 0

但是,我想用 PHP 解密这个文件。我有以下代码:

$file = file_get_contents('file.crypt');
$key = 0123456789abcdef;
$data = mcrypt_decrypt(MCRYPT_RIJNDAEL_192, $key, $file, MCRYPT_MODE_ECB);

print_r($data);

显然我遗漏了一些东西,因为 PHP 脚本正在返回数据,而不是纯文本。

我曾尝试使用 MCRYPT_RIJNDAEL_128,但没有成功。如果您能看到我做错了什么,请告诉我。提前致谢。

更新


我已使用以下方法成功解密了我的文件:

$key = pack('H*', '0123456789abcdef'); //In >= PHP 5.4 you can use hex2bin() I think.
$data = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $file, MCRYPT_MODE_ECB);

【问题讨论】:

  • $file 是否真的包含文件的加密内容?
  • 你能说明你是如何加密文件的,以便我们重现吗?
  • 如果您尝试使用 0 作为 mcrypt_decrypt 的第 5 个参数会怎样? mcrypt_decrypt(MCRYPT_RIJNDAEL_192, $key, $file, MCRYPT_MODE_ECB, 0);
  • @Mike:file.crypt 是一个加密的 sqlite 数据库。使用 0 作为第五个参数会导致 mcrypt_decrypt 函数返回 false。
  • @Drew:我没有加密文件,它是由我没有白盒访问权限的应用程序加密的。

标签: php encryption openssl


【解决方案1】:

openssl 中的键和 IV 是十六进制的(因此太短),而 PHP 中的键和 IV 用作字符值。请在 openssl 中为 AES 密钥指定 32、48 或 64 位十六进制数字,在 PHP 中为 16、24 或 32 字节指定相同的值。 IV 应始终为 32 个十六进制数字或 16 个字节,因为这是 AES 的块大小。

您应该始终使用MCRYPT_RIJNDAEL_128,因为其中的 128 是算法的块大小(而不是密钥大小),MCRYPT_RIJNDAEL_192MCRYPT_RIJNDAEL_256 算法实现 AES。

此外,openssl 默认为 PKCS#7 填充,请查看mcrypt_encrypt cmets 部分以了解 PHP 的 PKCS 填充的实现 - 默认情况下它不提供。

【讨论】:

  • “MCRYPT_RIJNDAEL_192 和 MCRYPT_RIJNDAEL_256 算法不实现 AES”。 +1。很多人没有意识到这一点,因此将 AES 和 Rijndael 互换。
  • @owlstead 非常感谢!我使用您的答案修改了我的 PHP 代码,并且我已成功解密该文件。我已经编辑了我的原始问题以包含更改。
  • 很高兴它成功了!请注意,8 字节的密钥仍然很短。可能是密钥扩展了00 值字节 - 当然是 PHP mcrypt - 但这样的密钥对于 AES-128 密钥来说不够强大(16 个十六进制字符等于 8 个字节,或 64 位,密钥大小的一半AES-128)。
  • @noloader mcrypt_encrypt 的初始样本使用了MCRYPT_RIJNDAEL_256 以及许多其他错误。所以我提交了一个错误报告并更改了官方示例代码:) 现在关于这个的问题少了很多......
【解决方案2】:

openssl -enc -d -aes-192-ecb -in file.crypt -out file -K 0123456789abcdef -iv 0

在密钥文件中使用-kfile 指定您的密钥,而不是在命令行中使用-K


也许我读错了<openssl dir>/apps/enc.c 的来源,但在使用-K 选项时它看起来很糟糕。

首先,从命令行(第 114 行)声明十六进制编码值:

char *hkey=NULL,*hiv=NULL,*hsalt = NULL;

接下来,从命令行(第 265 行)填充hkey

else if (strcmp(*argv,"-K") == 0)
{
    if (--argc < 1) goto bad;
    hkey= *(++argv);
}

然后,执行一些测试。首先,第 422 行:

if ((str == NULL) && (cipher != NULL) && (hkey == NULL))
{
    ...
    EVP_read_pw_string(...)
    ...
}

然后是第 581 行:

if ((hkey != NULL) && !set_hex(hkey,key,sizeof key))
{
    BIO_printf(bio_err,"invalid hex key value\n");
    goto end;
}

那么hkey 就没有其他事情了。


现在,kfile 选项看起来更有趣:

else if (strcmp(*argv,"-kfile") == 0)
{
    static char buf[128];
    FILE *infile;
    char *file;
    /* lots of reading and parsing removed */
    ...
    str=buf;
}

将密钥分配给str 后,对其进行处理:

if (cipher != NULL)
{
    /* Note that str is NULL if a key was passed on the command
     * line, so we get no salt in that case. Is this a bug?
     */
    if (str != NULL)
    {
        /* Salt handling: if encrypting generate a salt and
         * write to output BIO. If decrypting read salt from
         * input BIO.
         */
        unsigned char *sptr;
        if(nosalt) sptr = NULL;
        else
        {
            if(enc) {
                if(hsalt) {
                    if(!set_hex(hsalt,salt,sizeof salt)) {
                        BIO_printf(bio_err, "invalid hex salt value\n");
                        goto end;
                    }
                } else if (RAND_pseudo_bytes(salt, sizeof salt) < 0)
                    goto end;
                ...
                EVP_BytesToKey(cipher,dgst,sptr,
                              (unsigned char *)str,
                              strlen(str),1,key,iv);

这是一个小型调试会话,write watchpointkey 上。使用-K 选项时未编写(尽管在某些EVP_* 函数中使用):

(gdb) b main
Breakpoint 1 at 0x1000071c0: file enc.c, line 106.
(gdb) watch key@16
Hardware watchpoint 3: {<data variable, no debug info>} 140735109990496 @ 16
(gdb) r -d -aes-192-ecb -in file.crypt -out file.txt -K 0123456789abcdef -iv 0
Starting program: .../openssl-1.0.1e/apps/enc.exe -d -aes-192-ecb -in file.crypt
-out apps.c -K 0123456789abcdef -iv 0

Breakpoint 1, main (argc=11, argv=0x7fff5fbff970) at enc.c:106
106         char *strbuf=NULL;
(gdb) c
Continuing.

Program exited normally.

这里只是自行车脱落:aes-192-ecbMCRYPT_MODE_ECB 只有在您不重复使用密钥并且文件为 16 字节或更少的情况下才是安全的。一旦您重复使用密钥或超过 16 个字节,您就会失去 PRP 安全性。

【讨论】:

    猜你喜欢
    • 2022-01-18
    • 1970-01-01
    • 1970-01-01
    • 2012-04-02
    • 2016-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-05
    相关资源
    最近更新 更多