Ant*_*dge 7 php encryption utf-8 mcrypt
基本事实:
$algorithm = MCRYPT_BLOWFISH;
$mode = MCRYPT_MODE_CBC;
$randSource = MCRYPT_DEV_URANDOM;
Run Code Online (Sandbox Code Playgroud)
注意 这不是严格的编码问题.
语境:
CentOS 7,Apache 2.4.12和PHP 5.6.20.
我正在制作一封HTML电子邮件,其中包含"验证您的电子邮件地址"链接,可以完成注册过程.我的虚拟专用服务器上的所有内容都是UTF-8,所有表单和查询字符串输入都使用多字节(mb)函数进行处理.
背景
作为一个实验(我知道mcrypt库的年龄和状态),我试图解密Blowfish加密的查询字符串参数.假设在上升的过程中,加密序列工作正常,我收到带有链接的电子邮件.
在下来的过程中,hmac_hash()签名(SHA-512,仅用于此实验)正在运行,我能够将每个独立消息(32个字符)与其哈希校验和(128个字符)分开.分离的消息部分的Base64解码正在工作.对于每个参数,我留下复合密文,其中复合密文等于IV +基密码文本.假设我使用一个版本的substr(),以获得IV和基底密文独立地(这是意料之中的).
问题
PHP: Warning mcrypt_generic_init(): Iv size is incorrect; supplied length: 12, needed: 8
Run Code Online (Sandbox Code Playgroud)
假设我已经梳理了PHP手册和Stackoverflow.假设我已经看过类似的其他问题,但不完全像这个问题.假设我在互联网上搜索无济于事.假设我有足够的经验来mb_string正确设置.假设当我遇到当前问题时我会处理mcrypt填充.
多字节问题会干扰解密吗?
base64编码可以IV + base cipher text破坏IV吗?
base64填充可能是个问题吗?
我应该指定更具体的MCRYPT_BLOWFISH_*吗?
为什么河豚IV大小报告8个字节,但很少产生8字节IV?
我应该使用哪个substr(),substr()或者mb_substr(),对于倾向于使所有UTF-8并将所有其他输入作为多字节UTF-8处理的设置.我知道这是一个奇怪的问题,但所有的PHP手册mycrypt解密序列示例都使用substr(),没有使用mb_substr().我的网站上的所有内容都尽可能使用mb_functions,我不介意使用substr()它,如果它解决了我的问题,但它没有解决它.当我使用时mb_substr(),我收到以下警告.
PHP: Warning mcrypt_generic_init(): Iv size is incorrect; supplied length: 11, needed: 8
Run Code Online (Sandbox Code Playgroud)
有没有人对这个问题有任何经验?建设性的答案将得到回报!
最新
以上是我尝试从阵列重建的Blowfish哈希示例,通过SHA512 HMACed,对称Blowfish加密(CBC),url安全Base64编码,urlencoded,查询字符串(phew!)接收.
下面是查询字符串的字符串(切断上面的blowfish哈希)看起来像加密,签名和base64编码后,但在被urlencoded之前.每个长度为128个字符(每个字符串随着您执行更多操作而变长).
上面是从查询字符串派生的Base64解码和Blowfish解密数组(显然,这个结果之间有安全步骤,但我只是试图显示事物的最新状态.)有些事情是不对的.加密似乎没有任何错误.解密也不会产生任何错误.纯文本是错的.如果我加入/破坏这些元素,它们将不会像上面的Blowfish哈希.
我猜想这个问题会隐藏在 UTF-8 编码的某个地方,因为您在不正确的上下文中使用它。也可能是您的框架对所有用例都发挥了一些作用。这可能太多了,通常会导致安全漏洞或类似的错误,因为当真正需要做的时候你没有做真正需要做的事情。
\n\nPHP 中的字符串只是字节的集合。您可以以您选择的编码方式存储文本,也可以只存储二进制数据,例如图像。PHP 既不知道什么类型的数据在什么字符串中,也不知道那里使用什么编码。这取决于开发人员跟踪此信息。
\n\n使用加密时,您会在生成随机字符串或加密某些有效负载时获得二进制数据。它保存在字符串中,但它没有 UTF-8 编码,因为它只是字节。我什至不会说它的编码是 ISO-8859-1,因为这意味着字节 77 (0x4D) 代表字母“M”。但实际上,它只是数字 - 77 根本不代表任何字母。
\n\n还要添加一件事 - 对于 ASCII 符号(拉丁字母、数字等 - 0-127 字节值),需要一个字节来表示 UTF-8 编码中的该符号(与 ISO-8859 中相同)。所以只要你传递base64_encoded数据,你就不应该太担心。mb_substr也将以与 相同的方式工作substr。但!对于二进制数据,您不能使用mb_*函数,因为它适用于字符。例如,如果加密数据是两个字节0xC5 0xA1,那么它在 UTF-8 中只是单个符号。加密使用字节(直到最终结果,可以是任何东西 - 甚至二进制文件),而不是字符。
由于您没有提供任何代码,我已经为您提供了一些代码 - 我希望它能帮助解决您的问题(如果它仍然相关的话)。
\n\n为了显示 URL 中传递的参数,有两个文件:encrypt.php和decrypt.php。保存到一个目录,php -S localhost:8000在其中运行并转到http://localhost:8000/encrypt.php
encrypt.php:
<?php\n// mcrypt_enc_get_key_size($td) gives 56, so it\'s longest that this key can be\n$key = \'LedsoilgarvEwAbDavVenpirabUfjaiktavKekjeajUmshamEsyenvoa\';\n$data = \'This is very important data, with some \xc5\xa1 UTF-8 \xc4\x98\xc4\x96 symbols\';\n\n$td = mcrypt_module_open(MCRYPT_BLOWFISH, \'\', MCRYPT_MODE_CBC, \'\');\n\n// create random IV - it\'s just random 8 bytes. You should use random_bytes() instead if available\n$ivSize = mcrypt_enc_get_iv_size($td);\n$iv = mcrypt_create_iv($ivSize, MCRYPT_DEV_URANDOM);\n\nmcrypt_generic_init($td, $key, $iv);\n\n$encrypted = mcrypt_generic($td, $data);\n\nmcrypt_generic_deinit($td);\nmcrypt_module_close($td);\n\n// payload that you want to send - binary. It\'s neither UTF-8 nor ISO-8859-1 - it\'s just bytes\n$payload = $iv . $encrypted;\n\n// base64 to pass safely\n$base64EncodedPayload = base64_encode($payload);\n// URL encode for URL. No need to do both URL-safe base64 *and* base64 + urlencode\n$link = \'http://localhost:8000/decrypt.php?encryptedBase64=\' . urlencode($base64EncodedPayload);\n\n// in fact, just for the reference, you don\'t even need base64_encode - urlencode also works at byte level\n// 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\n$link2 = \'http://localhost:8000/decrypt.php?encrypted=\' . urlencode($payload);\n\n?>\n<!doctype html>\n<html>\n <head>\n <meta charset="utf-8">\n </head>\n <body>\n <pre><?php\n var_dump(\'Data:\', $data);\n var_dump(\'Data size in bytes:\', strlen($data));\n var_dump(\'Data size in characters - smaller, as 3 of the characters take 2 bytes:\', mb_strlen($data, \'UTF-8\'));\n var_dump(\'Encrypted data size in bytes - same as original:\', strlen($encrypted));\n var_dump(\'Encrypted data size in characters - will be pseudo-random each time:\', mb_strlen($encrypted, \'UTF-8\'));\n\n var_dump(\'IV base64 encoded:\', base64_encode($iv));\n var_dump(\'Encrypted string base64 encoded:\', base64_encode($encrypted));\n ?></pre>\n <!-- Link will not contain any special characters, so htmlentities should not make any difference -->\n <!-- In any case, I would still recommend to use right encoding at the right context to avoid any issues if something changes -->\n <a href="<?php echo htmlentities($link, ENT_QUOTES, \'UTF-8\');?>">Link to decrypt</a><br/>\n <a href="<?php echo htmlentities($link2, ENT_QUOTES, \'UTF-8\');?>">Link to decrypt2</a>\n </body>\n</html>\nRun Code Online (Sandbox Code Playgroud)\n\ndecrypt.php:
<?php\n$key = \'LedsoilgarvEwAbDavVenpirabUfjaiktavKekjeajUmshamEsyenvoa\';\n\nif (isset($_GET[\'encryptedBase64\'])) {\n // just get base64_encoded symbols (will be ASCII - same in UTF-8 or other encodings)\n $base64EncodedPayload = $_GET[\'encryptedBase64\'];\n $payload = base64_decode($base64EncodedPayload);\n} else {\n // just get binary string from URL\n $payload = $_GET[\'encrypted\'];\n}\n\n$td = mcrypt_module_open(MCRYPT_BLOWFISH, \'\', MCRYPT_MODE_CBC, \'\');\n\n$ivSize = mcrypt_enc_get_iv_size($td);\n\n$iv = substr($payload, 0, $ivSize);\n$encrypted = substr($payload, $ivSize);\n\nmcrypt_generic_init($td, $key, $iv);\n\n/* Decrypt encrypted string */\n$decrypted = mdecrypt_generic($td, $encrypted);\n\n/* Terminate decryption handle and close module */\nmcrypt_generic_deinit($td);\nmcrypt_module_close($td);\n\n?>\n<!doctype html>\n<html>\n <head>\n <meta charset="utf-8">\n </head>\n <body>\n <pre><?php\n var_dump(\'IV base64 encoded:\', base64_encode($iv));\n var_dump(\'Encrypted string base64 encoded:\', base64_encode($encrypted));\n var_dump(\'Result:\', $decrypted);\n ?></pre>\n </body>\n</html>\nRun Code Online (Sandbox Code Playgroud)\n