php - Erlang 和 PHP 之间的加密

标签 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

在这种情况下,密文的第一个 128 位 block 是相同的,但第二个不同:

PHP: ojit_代码

二郎: ojit_代码

更新 3 -(我虽然是)已解决(但我错了)

这个答案提供了最后的线索: Incorrect key size when porting Crypto++ AES encryption to PHP's mcrypt

问题是 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>> 模式没有使用正确的反馈 block 大小来模拟 'cfb' - 您需要使用 mycrypt 模式。

更新2

试图让 AES-CFB-128 在两者之间工作 - 所以我确定使用 aes cfbnofb 模式, block 大小为 128,mycrypt 类型是 Erlang 中 RINJDAEL_128 的 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

我发现可以用 php 函数复制 'cfb' 函数:

function encrypt_term_hex($Key, $Msg) {
    return hash_hmac("md5", $Msg, $Key);
}

原始问题

我想在两个系统之间共享信息,一个用 Erlang 编写,一个用 PHP 编写。

计划是使用一个已经在多个 Erlang 系统之间运行的系统,该系统涉及使用在 Erlang 系统之间共享的私钥签署 Erlang 术语。

Erlang 端使用函数 crypto:aes_cfb_128/3crypto:md5_mac/2,后者又使用底层 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 和固定(共享)盐生成 key ,最后进行加密 - 使用另一个盐向量对其进行初始化。

到目前为止一切顺利。然后我的任务是在 PHP 中复制这个 fn(当然还有它的解密双胞胎)。

Erlang 文档很好:

http://erlang.org/doc/man/crypto.html

试图弄清楚 Erlang 究竟如何调用底层加密库有点困难 - 因为源代码显示了模糊的 NIF 宏。

看来 PHP 围绕 OpenSSL 实现了一个库包装器,因此它应该是直截了当的。不幸的是,我无法弄清楚它。例如,我查看了 openssl-encrypt 并指出它没有记录:

http://php.net/manual/en/function.openssl-encrypt.php

有什么地方可以获得关于如何在 PHP 中实现 OpenSSL 的良好示例/文档?或者 Erlang NIF 加载器是如何工作的?还是两者兼而有之?

最佳答案

关于php - Erlang 和 PHP 之间的加密,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14550195/

相关文章:

php - 更新或检索数据库中行的最佳方法是什么?

encryption - 如果服务器受到攻击,如何防止中间人攻击?

python - erlang 到 python 的接口(interface)

ruby - 如果我非常喜欢 Ruby,我现在是否应该学习另一种语言,例如 Lua 或 Erlang?

javascript - 将 javascript 时间戳转换为日期元组的可靠方法

php - 除非删除 PHP 代码,否则不会显示登录页面

javascript - onclick 功能不起作用

web-services - AesManaged 和 RijndaelManaged

php - 从 Laravel 查询构建器中获取具有 elquent 关系的数据

c# - 如何在没有 PIN 提示的情况下通过智能卡读卡器访问 PKI 证书的私钥?