由于 mcrypt 被认为是过时的,我的任务是升级当前代码以使用 openssl。听起来很简单,但是...经过几天的尝试和失败,我觉得自己疯了。
我的问题是:有什么方法可以用以前用mcrypt加密的openssl数据解密吗?我读过很多关于这个问题的帖子,大多数帖子都说,在运行mcrypt之前,需要对数据进行手动填充。问题是,mcrypted数据已经加密(使用mcrypt提供的自动空填充),并驻留在数据库中,因此不可能和/或不希望对其进行修改。
提到:
一些代码片段:
// 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);
除了填充之外,不应该有任何主要区别。如果您直接使用更高级别的OpenSSL(EVP)结构,您应该能够调用EVP_CIPHER_CTX_set_padding
。我认为填充参数应该为零,尽管没有记录。您需要为此预配置的加密/解密上下文。
之后,您将获得与密文长度相同的明文。末尾的零到十五个字节将设置为零。您需要手动删除这些字节。如果明文碰巧以零字节结尾,那么这些字节也将被删除;然而,如果明文是可打印字符串(使用8位编码),则永远不会发生这种情况。您可能需要确保删除的字节不超过15个。
如果你得到完全随机的明文,那么你的密钥或密文是不正确的。如果您获得了可读的明文,但对于前16个字节,那么您的IV处理是不正确的。
如果您在不手动添加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很糟糕。
有点旧,但是你可以通过一些工作来解决这个问题。你可以告诉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编码? 谢谢