更新 5
将问题切换到 Security StackExchange - 得到了答案。 https://security.stackexchange.com/questions/30168/aes-cfb-128-decryption-encryption-problem-between-erlang-and-php
更新 4
解决了这个问题,或者我想 - 我试图继续实施。结果发现还不够。
一旦我们开始将真实的单词数据放入其中,一切都变得糟糕透顶。一个例子是将纯文本从1234567812345678
增加到12345678123456781234567812345678
在这种情况下,密文的第一个 128 位块是相同的,但第二个是不同的:
PHP:
139 182 94 68 208 173 127 90 14 236 33 230 41 29 210 121 153 57 173 191 237 169 242 222 217 104 116 144 240 175 39 33
二郎:
<<139,182,94,68,208,173,127,90,14,236,33,230,41,29,210,121,147,172,
114,74,61,11,162,5,112,104,102,63,24,78,34,179>>
更新 3 - (我虽然是)解决了(但我错了)
这个答案提供了最后的线索: Incorrect key size when porting Crypto++ AES encryption to PHP's mcrypt
问题在于'cfb'
modemycrypt
没有使用正确的反馈块大小来模拟aes cfb
- 你需要使用 mode nofb
。
更新 2
试图让 AES-CFB-128 在两者之间工作 - 所以我已经确定使用128 块大小和类型mycrypt
的模式是在 Erlang中的 PHP 等效项。RINJDAEL_128
'cfb'
crypto:aes_cfb_128/3
所以我开始用两种语言编写例程来证明这一点。
PHP版本:
<?php
// fugly because I don't know enough PHP to write it better
// big apologies to any PHP code poets out there, my bad :(
function dump($String, $Bin) {
echo $String . " is " . ord($Bin[0]) . " " . ord($Bin[1]) . " " . ord($Bin[2]) . " " . ord($Bin[3]) . " " . ord($Bin[4]) . " " . ord($Bin[5]) . " " . ord($Bin[6]) . " " . ord($Bin[7]) . " " . ord($Bin[8]) . " " . ord($Bin[9]) . " " . ord($Bin[10]) . " " . ord($Bin[11]) . " " . ord($Bin[12]) . " " . ord($Bin[13]) . " " . ord($Bin[14]) . " " . ord($Bin[15]) . "\n";
}
$Key = "abcdefghabcdefgh";
$IV = "12345678abcdefgh";
$Text = "1234567812345678";
$KeySize = strlen($Key) * 8;
$IVSize = strlen($IV) * 8;
$TextSize = strlen($Text) * 8;
$Size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CFB);
echo "Block size is " . $Size . " bytes or " . $Size * 8 . " bits\n";
$Crypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $Key, $Text, MCRYPT_MODE_CFB, $IV);
$Decrypt = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $Key, $Crypt, MCRYPT_MODE_CFB, $IV);
echo "Key is " . $Key . " with size " . $KeySize . "\n";
echo "IV is " . $IV . " with size " . $IVSize . "\n";
echo "Text is " . $Text . " with size " . $TextSize . "\n";
echo "Crypt is " . $Crypt . "\n";
dump("Crypt", $Crypt);
echo "Decrypt is " . $Decrypt . "\n";
dump("Decrypt", $Decrypt);
?>
当我运行它时,我得到以下 PHP 输出:
Block size is 16 bytes or 128 bits
Key is abcdefghabcdefgh with size 128
IV is 12345678abcdefgh with size 128
Text is 1234567812345678 with size 128
Crypt is ��*�b�ls�M��
Crypt is 139 0 188 42 175 98 18 177 108 27 115 189 77 144 127 176
Decrypt is 1234567812345678
Decrypt is 49 50 51 52 53 54 55 56 49 50 51 52 53 54 55 56
Erlang 版本是:
-module(test_crypto).
-export([
test/0
]).
test() ->
Key = <<"abcdefghabcdefgh">>,
IV = <<"12345678abcdefgh">>,
Text = <<"1234567812345678">> ,
KeySize = bit_size(Key),
IVSize = bit_size(IV),
TextSize = bit_size(Text),
io:format("Key is ~p with size ~p~n", [Key, KeySize]),
io:format("IV is ~p with size ~p~n", [IV, IVSize]),
io:format("Text is ~p with size ~p~n", [Text, TextSize]),
Crypt = crypto:aes_cfb_128_encrypt(Key, IV, Text),
io:format("Crypt is ~p~n", [Crypt]),
Decrypt = crypto:aes_cfb_128_decrypt(Key, IV, Crypt),
io:format("Decrypt is ~p~n", [Decrypt]),
ok.
当我运行它时,我得到 Erlang 输出:
Key is <<"abcdefghabcdefgh">> with size 128
IV is <<"12345678abcdefgh">> with size 128
Text is <<"1234567812345678">> with size 128
Crypt is <<139,182,94,68,208,173,127,90,14,236,33,230,41,29,210,121>>
Decrypt is <<"1234567812345678">>
所以每个人都正确地进行了加密/解密循环 - 但加密形式不同 - 我不能在 Erlang 和 PHP 之间使用它。
我确信有一些简单的解释 - 但我不明白它。
PHP 将字符串作为输入 - Erlang 采用二进制文件 - 但似乎 PHP ascii 字符串存储为二进制文件。这是对的还是我错过了什么?
更新 1
我发现crypto:md5_mac/2
可以使用 php 函数复制该函数:
function encrypt_term_hex($Key, $Msg) {
return hash_hmac("md5", $Msg, $Key);
}
原始问题
我想在两个系统之间共享信息,一个用 Erlang 编写,一个用 PHP 编写。
该计划是使用已经在多个 Erlang 系统之间运行的系统,该系统涉及使用在 Erlang 系统之间共享的私钥签署 Erlang 术语。
Erlang 端使用这些函数crypto:md5_mac/2
,而crypto:aes_cfb_128_encrypt/3
后者又使用底层的 OpenSSL 加密库。
加密方面(在 Erlang 中)是:
encrypt_bin(Key0, PlainT0) ->
PlainT = extend(PlainT0),
Key = crypto:md5_mac(get_server_salt(), Key0),
crypto:aes_cfb_128_encrypt(Key, get_salt(), PlainT).
这个函数的作用是获取一个键值对。然后它将术语的大小扩展到固定大小,使用 md5_mac 和固定(共享)盐生成密钥,最后进行加密 - 使用另一个盐向量对其进行初始化。
到现在为止还挺好。然后我的任务是在 PHP 中复制这个 fn(当然还有它的解密双胞胎)。
Erlang 文档很好:
http://erlang.org/doc/man/crypto.html
试图弄清楚 Erlang 是如何调用底层 Crypto 库的有点困难——因为源代码显示了模糊的 NIF 宏。
PHP 似乎围绕 OpenSSL 实现了一个库包装器,因此它应该是直截了当的。不幸的是,我无法理解它。例如,我查看 openssl-encrypt 并指出它没有记录:
http://php.net/manual/en/function.openssl-encrypt.php
有没有什么地方可以得到关于如何在 PHP 中实现 OpenSSL 的好例子/文档?或者 Erlang NIF 加载器是如何工作的?或两者?