Rijndael / AES解密C#到PHP的转换 [英] Rijndael/AES decryption C# to PHP conversion

查看:443
本文介绍了Rijndael / AES解密C#到PHP的转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在C#中有以下代码

string s = "hellowld";
byte[] bytes = new UnicodeEncoding().GetBytes(s);
FileStream stream = new FileStream(inputFile, FileMode.Open);
RijndaelManaged managed = new RijndaelManaged();
CryptoStream stream2 = new CryptoStream(stream, managed.CreateDecryptor(bytes, bytes), CryptoStreamMode.Read);
FileStream stream3 = new FileStream(outputFile, FileMode.Create);
try
{
    int num;
    while ((num = stream2.ReadByte()) != -1)
    {
        stream3.WriteByte((byte) num);
    }
 [....]

此代码段可解密特定内容文件并输出解密的版本。在RijndaelManaged im的CreateDecryptor方法中,我使用密码作为KEY以及IV。

This code snippet decrypts a certain file and outputs a decrypted version. In the CreateDecryptor method from RijndaelManaged im using the password as KEY and also as IV.

我在PHP的stackoverflow上找到了一些代码,但是如果我尝试给出密钥和iv与C#中相同的字节数组什么也没发生。

I found some code here on stackoverflow for PHP but if I try to give the key and iv the same Array of Bytes like in C# nothing happens.

$Pass = "hellowld";
$Clear = file_get_contents('./file.dat', FILE_USE_INCLUDE_PATH);

$bytePass=array();
$i = 0;
foreach (str_split($Pass) as $value) {
    $bytePass[$i]=ord($value);
    $i++;
}

echo decryptAES($Clear,$bytePass,$bytePass);

function decryptAES($content,$iv, $key,$aes) {

// Setzt den Algorithmus
switch ($aes) {
    case 128:
       $rijndael = 'rijndael-128';
       break;
    case 192:
       $rijndael = 'rijndael-192';
       break;
    default:
       $rijndael = 'rijndael-256';
}

// Setzt den Verschlüsselungsalgorithmus
// und setzt den Output Feedback (OFB) Modus
$cp = mcrypt_module_open($rijndael, '', 'ofb', '');

 // Ermittelt die Anzahl der Bits, welche die Schlüssellänge des Keys festlegen
$ks = mcrypt_enc_get_key_size($cp);

// Erstellt den Schlüssel, der für die Verschlüsselung genutzt wird
$key = substr(md5($key), 0, $ks);

// Initialisiert die Verschlüsselung
mcrypt_generic_init($cp, $key, $iv);

// Entschlüsselt die Daten
$decrypted = mdecrypt_generic($cp, $content);

// Beendet die Verschlüsselung
mcrypt_generic_deinit($cp);

// Schließt das Modul
mcrypt_module_close($cp);

return trim($decrypted);

}

我真的需要一些帮助,以正确地在其中创建代码PHP。

I really need some help how to properly create the code in PHP. Its not necessary that I output a file in PHP, a string would be sufficient.

UPDATE
默认的C#RijndaelManaged密码方法是AES-128-CBC。我将PHP代码更改为该mcrypt模块(默认C#密码方法

更新2:
我确实创建了Java Decryptor,这使我想到了另一件事。 PHP必须使用PKCS7填充。

UPDATE 2: I did manage to create a Java Decryptor which lead me to another thing. PHP has to use the PKCS7 Padding.

推荐答案

您的C#代码看起来并不安全,因此,如果可以更改它,请参阅下面的一些提示。
这是对给定的PHP代码进行修改,使其看起来等同于给定的C#代码。

Your C# code doesn't really look secure, so if you can change it, see below for some tips. Here is your given PHP code modified to look like it could be equivalent to the C# code given.

function decryptAES128CBC($content,$iv, $key) {

    // AES is Rijndael-128
    $rijndael = 'rijndael-128';

    // key size is 128 bit = 16 bytes
    $ks = 16;

    // CBC mode, not OFB
    $cp = mcrypt_module_open($rijndael, '', 'cbc', '');

    // pad key and IV by zeros (this is not a good idea)
    $key = str_pad($key, $ks, "\0");
    $iv = str_pad($key, $iv, "\0");

    // initialize the decryptor with key and IV
    mcrypt_generic_init($cp, $key, $iv);

    // the actual work
    $decrypted = mdecrypt_generic($cp, $content);

    // clean up
    mcrypt_generic_deinit($cp);
    mcrypt_module_close($cp);

    // remove padding, see below
    return unpad($decrypted);
}

最后一个 unpad 在那里删除了可能由加密功能附加的填充,以将消息大小扩展到整个块数。 RijndaelManaged使用的默认填充为PKCS7-padding,它会附加一个字节数(介于1到16之间),每个字节等于所附加的字节数。在实际的实现中,您将在解密后检查填充是否有效(即所有这些字节都具有相同的值),但是对于快速且肮脏的,您可以简单地使用检查最后一个字节并删除那么多个字节的内容。有关示例,请参见对mcrypt_decrypt的评论

The last unpad is there to remove the padding which was likely appended by the encryption function to enlarge the message size to a full number of blocks. The default padding used by RijndaelManaged is PKCS7-padding, which appends a number of bytes (between 1 to 16), each of which being equal to the number of bytes appended. In a real implementation, you would check after decryption that the padding is valid (i.e. that all these bytes have the same value), but for "quick and dirty" you can simply use something which checks the last byte and removes that many bytes. See the comments to mcrypt_decrypt for an example.

如果可以更改C#代码:


  • 请注意,使用固定值(每个键)作为初始化向量通常不是一个好主意,而将键本身用作初始化向量也不是一个好主意。使用随机初始化矢量(与消息一起发送),或查看下一点。

  • Note that it is usually not a good idea to use a fixed value (per key) as an initialization vector, and using the key itself as initialization vector is not good, either. Use a random initialization vector (sent together with the message), or see the next point.

此外,您通常不希望使用(简称)密码直接作为密钥,但使用更长的密码短语,并用盐(消息中包含的盐)对其进行散列以得出密钥。如果这样做,您还可以从相同的两个数据派生初始化向量(但使用键派生函数可以使它们有所不同)。
为避免从加密文件中强行使用密码,请在此处使用慢速哈希函数(PBKDF-2或bcrypt)。

Also, you normally don't want to use a (rather short) password directly as a key, but instead use a longer passphrase, and hash it with a salt (included with in the message) to derive the key. If you do this, you can also derive the initialization vector from the same two pieces of data (but in a way that they'll be different, using a key derivation function). To avoid brute-forcing your password from the encrypted file, use a slow hash function here (PBKDF-2 or bcrypt).

这篇关于Rijndael / AES解密C#到PHP的转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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