首页 文章

使用openssl解密mcrypt

提问于
浏览
2

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

我的问题是:你有什么方法可以用之前用mcrypt加密的openssl数据解密吗?我已经阅读了很多这方面的帖子,大多数人都说在运行mcrypt之前需要先前手动填充数据 . 问题是mcrypt-ed数据已经加密(使用mcrypt提供的自动空填充)并驻留在数据库中,因此无法和/或期望对其进行修改 .

Mentions:

  • 使用的算法是rijndael-128 cbc,带有32字节密钥(所以我使用aes-256-cbc for openssl) .

  • 我正在使用php(php-crypto)的openssl包装器 .

  • 我设法使逆操作工作(用mcrypt解码openssl),只需剥离最终解码的字符(如果它们是非字母数字) .

  • 在mcrypting之前手动填充数据然后使用openssl解密它就像魅力一样,但这不是问题所在 .

Some code snippets:

// 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 回答

  • 4

    如果您在mcrypt中加密而不手动添加PKCS7,mcrypt将很乐意用 NUL 字节填充您的明文 .

    每当使用 aes-X-cbc 时,OpenSSL都会为您执行PKCS7填充 . 这样做的不幸结果是,如果你有 AES-CBC(NULL_PADDED(plaintext)) 并尝试解密它, openssl_decrypt 将尝试删除填充并失败 .

    比较http://3v4l.org/bdQe9对比http://3v4l.org/jr68fhttp://3v4l.org/K6ZEU

    OpenSSL扩展目前没有为您提供说出"This string is not padded, please don't strip the padding for me"然后自行删除 NUL 字节的方法 . 您必须使用PKCS7填充进行加密,以便解密成功 .

    虽然这是OpenSSL的限制,但它强调的是,你遇到它的唯一原因是因为mcrypt is terrible .

  • 3

    稍微陈旧,但你可以通过一些工作来解决这个问题 . 您可以告诉PHP 's OpenSSL that the encrypted string is not padded, and tell it to give you the raw output (So you don' t必须对它进行base64解码 . 然后,如果字符串的长度碰巧可以被IV完全整除,则可以从结果字符串的末尾去除空值(这是一个完整性检查,就像结果字符串根本没有填充一样) .

    Be aware, this code has two major limitations

    • 如果您在任何时候加密了以两个或多个 NULL 字节结尾的合法字符串,那么此代码将不会为您提供相同的输出 .

    • 如果字符串的填充只需要一个空字节,则此代码不会删除它 .

    你可以解决这两个问题,如果你知道 FACT 你没有加密以空字节结尾的任何东西,你可以改变剥离空值的代码来做一个preg_replace;只需确保将正则表达式锚定到字符串的末尾,以便它只从末尾剥离 .

    http://3v4l.org/kYAXn

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

  • 2

    除了填充之外,不应该有任何重大差异 . 如果直接使用更高级别的OpenSSL(EVP)构造,则应该能够调用 EVP_CIPHER_CTX_set_padding . 我认为padding参数应为零,尽管it is not documented . 您需要一个预先配置的加密/解密上下文 .

    之后,您将获得与密文长度相同的明文 . 末尾的0到15个字节将设置为零 . 您需要手动删除这些字节 . 如果明文恰好以零字节结束,那么这些也将被删除;然而,如果明文是可打印的字符串(使用8位编码),则情况绝非如此 . 您可能希望确保不要删除超过15个字节 .

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

相关问题