PHP:警告mcrypt_generic_init():Iv大小不正确;供应长度:12,需要:8 [英] PHP: Warning mcrypt_generic_init(): Iv size is incorrect; supplied length: 12, needed: 8

查看:256
本文介绍了PHP:警告mcrypt_generic_init():Iv大小不正确;供应长度:12,需要:8的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

基本情况:

  $ algorithm = MCRYPT_BLOWFISH; 
$ mode = MCRYPT_MODE_CBC;
$ randSource = MCRYPT_DEV_URANDOM;

注意
这不是严格的编码问题。 / p>

上下文



CentOS 7,Apache 2.4.12,& PHP 5.6.20。



我正在通过一个验证您的电子邮件地址链接制作HTML电子邮件,允许注册过程完成。我的虚拟专用服务器上的所有内容都是UTF-8,所有的表单和查询字符串输入都是用多字节(mb)函数进行处理的。



strong>



作为一个实验(我知道mcrypt库的年龄和状态),我试图解密Blowfish加密查询字符串参数。假设在进行中,加密序列工作正常,我正在接收具有链接的电子邮件。



在下降的路上, hmac_hash()签名(SHA-512,仅供本实验使用)正在工作我可以将每个独立的消息(32个字符)与其哈希校验和(128个字符)分开。分离的消息部分的Base64解码正在工作。对于每个参数,我留下了复合密文,其中复合密码等于IV +基本密文。假设我使用 substr()的版本可以独立地获取IV和基本密文(这是课程的参数)。



问题

  PHP:警告mcrypt_generic_init():Iv大小不正确;提供的长度:12,需要:8 

假设我已经梳理了PHP手册和Stackoverflow。假设我已经看过类似的其他问题,但不完全像这样。假设我已经搜索到互联网无效。假设我有足够的经验来正确设置 mb_string 。假设当我遇到这个问题时,我会照顾mcrypt padding。



多字节问题可能会干扰解密吗?



可以base64编码 IV +基本密码文本损坏IV?



可以base64填充是一个问题?



我应该指定一个更具体的 MCRYPT_BLOWFISH _ *



为什么blowfish IV大小报告8个字节,但很少产生一个8字节的IV?



我应该使用substr(), substr() mb_substr(),对于倾向于使所有UTF-8进行所有其他输入的设置多字节UTF-8。我知道这是一个奇怪的问题,但所有的PHP手册mycrypt解密序列示例使用 substr(),而没有使用 mb_substr()。我的网站上的所有内容都可能与mb_functions一起使用,如果解决了我的问题,我不介意使用 substr(),但它并不能解决。当我使用 mb_substr()时,我收到以下警告。

  PHP:警告mcrypt_generic_init():Iv大小不正确;提供的长度:11,需要:8 

有没有人有任何关于这个确切问题的经验?



最新





以上是一个例子Blowfish哈希,我想从一个数组重建,通过SHA512 HMACed,对称Blowfish加密(CBC),URL安全Base64编码,urlencoded,查询字符串(phew!)收到。



下面是查询字符串(已经打碎了上面的blowfish哈希)看起来像加密,签名和base64编码之后,但在被urlencoded之前。每个字符长度为128个字符(每个字符串的更长时间都会更多)。







以上是从查询字符串派生的Base64解码和Blowfish解密数组显然,这个结果之间有安全措施,但我只是试图显示最新的事情状况。)有些事情是不正确的。加密似乎工作没有任何错误。解密也不会产生任何错误。纯文本是错误的。如果我加入/打破这些元素,他们不会像上面的Blowfish哈希。

解决方案

我猜这个问题会隐藏UTF-8编码的地方,因为您在不正确的上下文中使用它。也可能是您的框架对所有用例都有一些魔力。这可能太多了,一般最终会出现在安全漏洞中,或者只是这样的错误,因为你真的需要做真正需要做的事情。



PHP中的字符串只是字节集合。您可以在其中存储文本,在您选择的编码中,或者您可以只存储二进制数据,如图像。 PHP既不知道什么字符串中的数据是什么,也不知道使用什么编码。这是由开发人员跟踪此信息。



使用加密时,您可以在生成随机字符串或加密某些有效内容时获取二进制数据。它保存在字符串中,但它没有UTF-8编码,因为它只是字节。我甚至不会说它的编码是ISO-8859-1,因为这意味着字节77(0x4D)代表字母M。但是对于真实的,只是数字 - 77不代表任何信件。



还有一件事要添加 - 对于ASCII符号(拉丁字母,数字等) 0-127字节值),以UTF-8编码(与ISO-8859中相同)需要一个字节来表示该符号。所以就你通过 base64_encode d数据,你不应该太担心。 mb_substr 也将以与 substr 相同的方式工作。 对于二进制数据,您不能使用 mb _ * 函数,因为它与字符一起使用。例如,如果加密数据是两个字节 0xC5 0xA1 ,则UTF-8中只有单个符号。加密使用字节(直到最终结果,甚至可以是任何东西 - 甚至二进制文件),而不是字符。



由于您没有提供任何代码,为你提供一些 - 我希望它会帮助你的问题(如果它仍然是相关的)。



要显示URL中的传递参数,有两个文件: encrypt.php decrypt.php 。保存到目录中,运行 php -S localhost:8000 ,然后转到 http:// localhost:8000 / encrypt.php



encrypt.php

 <?php 
// mcrypt_enc_get_key_size($ td)给出56,所以这个键可以是最长的be
$ key ='LedsoilgarvEwAbDavVenpirabUfjaiktavKekjeajUmshamEsyenvoa';
$ data ='这是非常重要的数据,一些šUTF-8ĘĖ符号;

$ td = mcrypt_module_open(MCRYPT_BLOWFISH,'',MCRYPT_MODE_CBC,'');

//创建随机的IV - 它只是随机的8个字节。如果可用,您应该使用random_bytes()
$ ivSize = mcrypt_enc_get_iv_size($ td);
$ iv = mcrypt_create_iv($ ivSize,MCRYPT_DEV_URANDOM);

mcrypt_generic_init($ td,$ key,$ iv);

$ encrypted = mcrypt_generic($ td,$ data);

mcrypt_generic_deinit($ td);
mcrypt_module_close($ td);

//要发送的有效载荷 - 二进制。它既不是UTF-8也不是ISO-8859-1 - 它只是字节
$ payload = $ iv。 $加密;

// base64安全传递
$ base64EncodedPayload = base64_encode($ payload);
// URL的URL编码。不需要同时进行URL-safe base64 *和* base64 + urlencode
$ link ='http:// localhost:8000 / decrypt.php?encryptedBase64 ='。进行urlencode($ base64EncodedPayload);

//其实只是为了引用,你甚至不需要base64_encode - urlencode也可以在字节级别
// base64_encode占用大约1.33个空间,但是urlencode需要3次超过原始的非安全符号,所以base_64可能会更短
$ link2 ='http:// localhost:8000 / decrypt.php?encrypted ='。进行urlencode($有效载荷);

?>
<!doctype html>
< html>
< head>
< meta charset =utf-8>
< / head>
< body>
< pre><?php
var_dump('Data'',$ data);
var_dump('data size in bytes:',strlen($ data));
var_dump('数据大小字符 - 较小,3个字符需要2个字节:',mb_strlen($ data,'UTF-8'));
var_dump('加密的数据大小(以字节为单位) - 与原始数据相同',strlen($ encrypted));
var_dump('加密的数据大小字符 - 每次都将伪随机:',mb_strlen($ encrypted,'UTF-8'));

var_dump('IV base64 encoded:',base64_encode($ iv));
var_dump('加密字符串base64 encoded:',base64_encode($ encrypted));
?>< / pre>
<! - 链接不会包含任何特殊字符,所以htmlentities不应该有任何区别 - >
<! - 在任何情况下,我仍然建议在正确的上下文中使用正确的编码,以避免任何问题,如果有变化 - >
< a href =<?php echo htmlentities($ link,ENT_QUOTES,'UTF-8');?>>链接到解密< / a>< br />
< a href =<?php echo htmlentities($ link2,ENT_QUOTES,'UTF-8');?>>链接到decrypt2< / a>
< / body>
< / html>

decrypt.php

 <?php 
$ key ='LedsoilgarvEwAbDavVenpirabUfjaiktavKekjeajUmshamEsyenvoa';

if(isset($ _ GET ['encryptedBase64'])){
//只是获取base64_encoded符号(将是ASCII - 在UTF-8或其他编码中相同)
$ base64EncodedPayload = $ _GET ['encryptedBase64'];
$ payload = base64_decode($ base64EncodedPayload);
} else {
//从URL获取二进制字符串
$ payload = $ _GET ['encrypted'];
}

$ td = mcrypt_module_open(MCRYPT_BLOWFISH,'',MCRYPT_MODE_CBC,'');

$ ivSize = mcrypt_enc_get_iv_size($ td);

$ iv = substr($ payload,0,$ ivSize);
$ encrypted = substr($ payload,$ ivSize);

mcrypt_generic_init($ td,$ key,$ iv);

/ *解密加密的字符串* /
$ decryptpted = mdecrypt_generic($ td,$ encrypted);

/ *终止解密句柄和关闭模块* /
mcrypt_generic_deinit($ td);
mcrypt_module_close($ td);

?>
<!doctype html>
< html>
< head>
< meta charset =utf-8>
< / head>
< body>
< pre><?php
var_dump('IV base64 encoded:',base64_encode($ iv));
var_dump('加密字符串base64 encoded:',base64_encode($ encrypted));
var_dump('Result:',$ decryptpted);
?>< / pre>
< / body>
< / html>


Basic Facts:

$algorithm  = MCRYPT_BLOWFISH;
$mode       = MCRYPT_MODE_CBC;
$randSource = MCRYPT_DEV_URANDOM;

Note This is not a strict coding question.

Context:

CentOS 7, Apache 2.4.12, & PHP 5.6.20.

I am making an HTML email with a "verify your email address" link that allows a registration process to complete. Everything on my virtual private server is UTF-8, and all form and query string input is processed with multi-byte (mb) funcions.

Background

As an experiment (I know about the age and state of the mcrypt library), I am attempting to decrypt Blowfish encrypted query string parameters. Assume that on the way up, the encryption sequence works perfectly and I am receiving email with the link.

On the way down, the hmac_hash() signing (SHA-512, just for this experiment) is working and I am able to separate each independent message (32 characters) from its hash checksum (128 characters). Base64 decoding of the separated message portion is working. For each parameter, I am left with the composite cipher text, where composite cipher text equals the IV + base cipher text. Assume I use a version of substr() to obtain the IV and the base cipher text independently (which is par for the course).

Problem

PHP: Warning  mcrypt_generic_init(): Iv size is incorrect; supplied length: 12, needed: 8

Assume I have combed the PHP manual and Stackoverflow. Assume I have looked at other questions similar, but not exactly like this one. Assume I have searched the Internet to no avail. Assume I have enough experience to setup mb_string properly. Assume that I will take care of mcrypt padding when I get past this current problem.

Could multi-byte issues be interfering with decryption?

Could base64 encoding the IV + base cipher text corrupt the IV?

Could base64 padding be an issue?

Should I be specifying a more specific MCRYPT_BLOWFISH_*?

Why does the blowfish IV size report 8 bytes, but rarely produces an 8 byte IV?

Which substr() should I use, substr() or mb_substr(), for a setup that leans towards making everything UTF-8 and processes all other input as multi-byte UTF-8. I know that is an odd question, but all of the PHP Manual mycrypt decryption sequence examples use substr(), and none use mb_substr(). Everything on my site works with mb_functions when possible, and I would not mind using substr() if it solved my problem, but it does not solve it. When I use mb_substr(), I get the following warning.

PHP: Warning  mcrypt_generic_init(): Iv size is incorrect; supplied length: 11, needed: 8

Does anyone have any experience with this exact issue? Constructive answers will be rewarded!

Latest

Above is an example Blowfish hash that I am trying to reconstruct from an array, received via a SHA512 HMACed, symmetricly Blowfish encrypted (CBC), url safe Base64 encoded, urlencoded, query string (phew!).

Below, is what the strings for the query string (having chopped up the blowfish hash above) look like after encrypting, signing, and base64 encoding, but before being urlencoded. Each one is 128 characters long (each string gets longer as you do more stuff).

Above is the Base64 decoded and Blowfish decrypted array derived from the query string (Obviously, there are security steps in between this result, but I am just trying to show the latest state of things.) Something is not right. Encryption appears to work without any errors. Decryption does not produce any errors either. The plain text is just wrong. If I join/implode these elements, they will not be like the Blowfish hash above.

解决方案

I would guess that the issue will hide somewhere with the UTF-8 encoding, as you use it in incorrect contexts. It could also be that your framework does some magic for all use-cases. This could be too much and generally end up in security hole or just bugs like that, as you don't do what really needs to be done when it really needs to be done.

Strings in PHP are just collections of bytes. You can store text there, in encoding of your choosing, or you could just store binary data there, like images. PHP knows neither what kind of data is in what string nor what encoding is used there. This is up to developer to track this information.

When working with encryption, you get binary data when generating random strings or encrypting some payloads. It's saved in strings, but it does not have UTF-8 encoding, as it's just bytes. I wouldn't even say that it's encoding is ISO-8859-1, as this would mean that byte 77 (0x4D) stands for letter "M". But for real, it's just numbers - 77 does not stand for any letter at all.

One more thing to add - for ASCII symbols (Latin letters, digits etc. - 0-127 byte values) it takes one byte to represent that symbol in UTF-8 encoding (same as in ISO-8859). So as far as you pass base64_encoded data, you shouldn't worry too much about it. mb_substr will also work in the same way as substr. But! for the binary data, you cannot use mb_* functions, as it works with characters. For example, if encrypted data is two bytes 0xC5 0xA1, it's only single symbol in UTF-8. Encryption works with bytes (up until the final result, which could be anything - even binary files), not characters.

As you've not provided any code, I've put some for you - I hope it will help with your issue (if it's still relevant at all).

To show passing parameters in URL, there are two files: encrypt.php and decrypt.php. Save to a directory, run php -S localhost:8000 in it and go to http://localhost:8000/encrypt.php

encrypt.php:

<?php
// mcrypt_enc_get_key_size($td) gives 56, so it's longest that this key can be
$key = 'LedsoilgarvEwAbDavVenpirabUfjaiktavKekjeajUmshamEsyenvoa';
$data = 'This is very important data, with some š UTF-8 ĘĖ symbols';

$td = mcrypt_module_open(MCRYPT_BLOWFISH, '', MCRYPT_MODE_CBC, '');

// create random IV - it's just random 8 bytes. You should use random_bytes() instead if available
$ivSize = mcrypt_enc_get_iv_size($td);
$iv = mcrypt_create_iv($ivSize, MCRYPT_DEV_URANDOM);

mcrypt_generic_init($td, $key, $iv);

$encrypted = mcrypt_generic($td, $data);

mcrypt_generic_deinit($td);
mcrypt_module_close($td);

// payload that you want to send - binary. It's neither UTF-8 nor ISO-8859-1 - it's just bytes
$payload = $iv . $encrypted;

// base64 to pass safely
$base64EncodedPayload = base64_encode($payload);
// URL encode for URL. No need to do both URL-safe base64 *and* base64 + urlencode
$link = 'http://localhost:8000/decrypt.php?encryptedBase64=' . urlencode($base64EncodedPayload);

// in fact, just for the reference, you don't even need base64_encode - urlencode also works at byte level
// base64_encode takes about 1.33 more space, but urlencode takes 3 times more than original for non-safe symbols, so base_64 will probably be shorter
$link2 = 'http://localhost:8000/decrypt.php?encrypted=' . urlencode($payload);

?>
<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <pre><?php
            var_dump('Data:', $data);
            var_dump('Data size in bytes:', strlen($data));
            var_dump('Data size in characters - smaller, as 3 of the characters take 2 bytes:', mb_strlen($data, 'UTF-8'));
            var_dump('Encrypted data size in bytes - same as original:', strlen($encrypted));
            var_dump('Encrypted data size in characters - will be pseudo-random each time:', mb_strlen($encrypted, 'UTF-8'));

            var_dump('IV base64 encoded:', base64_encode($iv));
            var_dump('Encrypted string base64 encoded:', base64_encode($encrypted));
        ?></pre>
        <!-- Link will not contain any special characters, so htmlentities should not make any difference -->
        <!-- In any case, I would still recommend to use right encoding at the right context to avoid any issues if something changes -->
        <a href="<?php echo htmlentities($link, ENT_QUOTES, 'UTF-8');?>">Link to decrypt</a><br/>
        <a href="<?php echo htmlentities($link2, ENT_QUOTES, 'UTF-8');?>">Link to decrypt2</a>
    </body>
</html>

decrypt.php:

<?php
$key = 'LedsoilgarvEwAbDavVenpirabUfjaiktavKekjeajUmshamEsyenvoa';

if (isset($_GET['encryptedBase64'])) {
    // just get base64_encoded symbols (will be ASCII - same in UTF-8 or other encodings)
    $base64EncodedPayload = $_GET['encryptedBase64'];
    $payload = base64_decode($base64EncodedPayload);
} else {
    // just get binary string from URL
    $payload = $_GET['encrypted'];
}

$td = mcrypt_module_open(MCRYPT_BLOWFISH, '', MCRYPT_MODE_CBC, '');

$ivSize = mcrypt_enc_get_iv_size($td);

$iv = substr($payload, 0, $ivSize);
$encrypted = substr($payload, $ivSize);

mcrypt_generic_init($td, $key, $iv);

/* Decrypt encrypted string */
$decrypted = mdecrypt_generic($td, $encrypted);

/* Terminate decryption handle and close module */
mcrypt_generic_deinit($td);
mcrypt_module_close($td);

?>
<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <pre><?php
            var_dump('IV base64 encoded:', base64_encode($iv));
            var_dump('Encrypted string base64 encoded:', base64_encode($encrypted));
            var_dump('Result:', $decrypted);
        ?></pre>
    </body>
</html>

这篇关于PHP:警告mcrypt_generic_init():Iv大小不正确;供应长度:12,需要:8的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆