Erlang和PHP之间的加密

时间:2013-01-27 17:44:30

标签: php cryptography erlang openssl

更新5

将问题转交给Security StackExchange - 得到了答案。 https://security.stackexchange.com/questions/30168/aes-cfb-128-decryption-encryption-problem-between-erlang-and-php

更新4

解决问题或者我认为 - 我试着继续实施。原来这还不够。

一旦我们开始将真正的单词数据放入其中,一切都进入了地狱。一个例子是将纯文本从1234567812345678增加到12345678123456781234567812345678

在这种情况下,cypertext的第一个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'中的mycrypt模式没有使用正确的反馈模块来模拟aes cfb - 您需要使用模式nofb

更新2

尝试让AES-CFB-128兼顾两者 - 所以我发现使用mycrypt模式为RINJDAEL_128且块大小为128且类型为'cfb'的是在Erlang中等效于crypto:aes_cfb_128/3的PHP。

所以我开始用两种语言编写例程来证明这一点。

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/2crypto: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加载器如何工作?或两者兼而有之?

1 个答案:

答案 0 :(得分:0)