当前位置: 首页 > 知识库问答 >
问题:

用openssl解密mcrypt

马凡
2023-03-14

由于 mcrypt 被认为是过时的,我的任务是升级当前代码以使用 openssl。听起来很简单,但是...经过几天的尝试和失败,我觉得自己疯了。

我的问题是:有什么方法可以用以前用mcrypt加密的openssl数据解密吗?我读过很多关于这个问题的帖子,大多数帖子都说,在运行mcrypt之前,需要对数据进行手动填充。问题是,mcrypted数据已经加密(使用mcrypt提供的自动空填充),并驻留在数据库中,因此不可能和/或不希望对其进行修改。

提到:

  1. 使用的算法是32字节密钥的rijndael-128 cbc(所以我使用aes-256-cbc进行openssl)。
  2. 我正在为php(php-crypto)使用openssl包装器。
  3. 我已经设法使逆运算工作(用mcrypt解码openssl),方法是简单地剥离末尾解码字符,如果它们不是字母数字。
  4. 在mcrypt-ing之前手动填充数据,然后使用openssl解密它就像一个魅力,但这不是这里的问题。

一些代码片段:

// Simple mcrypt encrypt, decrypt with php-crypto example
// This doesn't work and produces a "Finalizing of cipher failed" error
        $data = "This is a text";
        $strMcryptData=mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, $iv);

        $algorithm = 'aes-256-cbc';
        $cipher = new Cipher($algorithm);
        $sim_text = $cipher->decrypt($strMcryptData, $key, $iv);

// Simple mcrypt encrypt with padding, decrypt with php-crypto
// Works and produces the correct text on decryption
        $pad =  $blocksize - (strlen($data) % $blocksize);
        $text = $data;
        $text .= str_repeat(chr($pad), $pad);
        $strPaddedData=mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_CBC, $iv);

        $sim_text = $cipher->decrypt($strPaddedData, $key, $iv);

共有3个答案

谢弘阔
2023-03-14

除了填充之外,不应该有任何主要区别。如果您直接使用更高级别的OpenSSL(EVP)结构,您应该能够调用EVP_CIPHER_CTX_set_padding。我认为填充参数应该为零,尽管没有记录。您需要为此预配置的加密/解密上下文。

之后,您将获得与密文长度相同的明文。末尾的零到十五个字节将设置为零。您需要手动删除这些字节。如果明文碰巧以零字节结尾,那么这些字节也将被删除;然而,如果明文是可打印字符串(使用8位编码),则永远不会发生这种情况。您可能需要确保删除的字节不超过15个。

如果你得到完全随机的明文,那么你的密钥或密文是不正确的。如果您获得了可读的明文,但对于前16个字节,那么您的IV处理是不正确的。

费子濯
2023-03-14

如果您在不手动添加PKCS7的情况下使用mcrypt加密,mcrypt将很高兴地用<code>NUL</code>字节填充明文。

每当使用< code>aes-X-cbc时,OpenSSL将为您进行PKCS7填充。这样做的不幸后果是,如果您有< code > AES-CBC(NULL _ PADDED(plaintext))并试图解密它,< code>openssl_decrypt将尝试删除填充并失败。

比较http://3v4l.org/bdQe9vshttp://3v4l.org/jr68f和http://3v4l.org/K6ZEU

OpenSSL扩展目前没有为您提供一种说“此字符串未填充,请不要为我剥离填充”然后自行删除NUL字节的方法。必须使用 PKCS7 填充进行加密才能成功解密。

尽管这是OpenSSL的一个限制,但值得强调的是,您遇到它的唯一原因是因为mcrypt很糟糕。

晏和风
2023-03-14

有点旧,但是你可以通过一些工作来解决这个问题。你可以告诉PHP的OpenSSL加密字符串没有填充,并告诉它给你原始输出(所以你也不必base64解码它)。然后,如果字符串的长度恰好可以完全被IV整除,你可以从结果字符串的末尾去掉空值(这是一个健全的检查,就好像结果字符串不能被IV整除,那么它根本没有被填充)。

请注意,该代码有两个主要限制:

> < li>

如果在任何时候,您加密了以两个或更多< code>NULL字节结尾的合法字符串,则此代码不会给出相同的输出。

如果字符串的填充只需要一个空字节,那么此代码不会剥离它。

如果您知道您没有加密任何以空字节结尾的内容,您可以解决这两个问题,您可以更改剥离空字节的代码以执行preg_replace;只要确保将正则表达式锚定到字符串的末尾,这样它就只能从末尾剥离。

<?php
$message = 'test';
$key = openssl_random_pseudo_bytes(16);
$iv = openssl_random_pseudo_bytes(16);

$cipher = mcrypt_encrypt(
    MCRYPT_RIJNDAEL_128,
    $key,
    $message,
    MCRYPT_MODE_CBC,
    $iv
);

$plain = openssl_decrypt(
    $cipher,
    'aes-128-cbc',
    $key,
    OPENSSL_RAW_DATA | OPENSSL_NO_PADDING,
    $iv
);

//try to detect null padding
if (mb_strlen($iv, '8bit') % mb_strlen($plain, '8bit') == 0) {
        preg_match_all('#([\0]+)$#', $plain, $matches);
        if (mb_strlen($matches[1][0], '8bit') > 1) {
                $plain = rtrim($plain, "\0");
                trigger_error('Detected and stripped null padding. Please double-check results!');
        }
}



var_dump(
    $message,
    bin2hex($cipher),
    $plain,
    mb_strlen($message, '8bit'),
    mb_strlen($plain, '8bit'),
    $message === $plain
);

http://3v4l.org/kYAXn

显然,这段代码没有主要的免责声明,请在您的用例中测试它,但有人可能会希望发现这很有用。

 类似资料:
  • 我正在使用以下函数通过Qt中的OpenSSL库加密我的数据: “源”在“123456789012345678901234567890123456789012ABC”中。 “密码”为“1HA!DH==SJAH48S8AK!?SKIITFI120XX”。 所以...如果我正确的话,那么EVP_BytesToKey()应该从密码中生成一个密钥,并提供数据以在后面解密字符串。 对base64编码的密钥是:

  • 在Java代码中,我应该解密一个加密的单词,如下所示: 我是加密新手,但是我发现了一些如何用Java加密/解密一些AES/CBC的示例。但是它需要盐、密钥和Iv。我发现OpenSsl正在从“密码”中导出这些值,但我没有发现如何Java解密加密值。 有人知道它是怎么工作的吗?盐、钥匙和/或Iv是否存储在加密值中?谢谢你的回答。

  • 问题内容: 我必须使用openssl命令行或C api加密xml文件。输出应为Base64。 一个Java程序将用于解密。该程序由客户提供,不能更改(他们正在将这些代码用于旧版应用程序)。正如您在下面的代码中看到的那样,客户提供了一个密码短语,因此将使用SecretKeySpec方法生成密钥。 Java代码: 我已经测试了几个命令,例如: 但是,使用Java无法成功解密给定的输出。为了进行测试,我

  • 我是密码学的新手。我的要求是对使用openssl加密/解密的文本进行解密/加密。我们在Openssl中使用的算法是aes-256-cbc。因此,我尝试在我的应用程序中实现相同的功能。到目前为止,在谷歌搜索了很多次之后,我所能做的就是。。 我的openssl命令是 我的密钥长度是32位IV是16位 Thnx...

  • 我的理解是,公钥可以用于加密,私钥可以用于解密,公钥不能解密由同一公钥加密的文件。我有没有误解,或者我做错了什么? 1) 生成密钥 openssl genrsa-out./private.pem2048 2) 生成公钥 openssl rsa-in/私有的pem-发布 3)加密一个小文本文件 openssl加密/在里面txt-输出/出来附件e-aes256-k/平民的pem公司 4) 使用公钥解密

  • 或者唯一的方法是运行一个脚本,它将用mcrypt解密我存储的所有加密数据,并用openssl编码? 谢谢