【问题标题】:Rijndael/AES decryption C# to PHP conversionRijndael/AES 解密 C# 到 PHP 转换
【发布时间】:2011-12-07 06:17:34
【问题描述】:

我在 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);
    }
 [....]

这段代码sn-p解密某个文件并输出解密后的版本。在 RijndaelManaged 的​​ CreateDecryptor 方法中,使用密码作为 KEY 和 IV。

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

$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 中创建代码。我不需要用 PHP 输出文件,一个字符串就足够了。

更新: 默认的 C# RijndaelManaged 密码方法是 AES-128-CBC。我将我的 PHP 代码更改为那个 mcrypt 模块 (default C# cipher method)

更新 2: 我确实设法创建了一个 Java Decryptor,它把我引向了另一件事。 PHP 必须使用 PKCS7 填充。

【问题讨论】:

标签: c# php aes rijndaelmanaged rijndael


【解决方案1】:

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

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 之间),每个字节等于附加的字节数。在实际实现中,您将在解密后检查填充是否有效(即所有这些字节具有相同的值),但对于“快速和肮脏”,您可以简单地使用检查最后一个字节并删除那么多字节的东西。有关示例,请参见 comments to mcrypt_decrypt

如果您可以更改您的 C# 代码:

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

  • 此外,您通常不希望直接使用(相当短的)密码作为密钥,而是使用更长的密码,并使用盐(包含在消息中)对其进行散列以派生钥匙。如果这样做,您还可以从相同的两条数据中导出初始化向量(但在某种程度上它们会有所不同,使用密钥导出函数)。 为避免从加密文件中暴力破解您的密码,请在此处使用慢速哈希函数(PBKDF-2 或 bcrypt)。

【讨论】:

  • 非常感谢您的详细回答。我无法更改 C# 代码,但 php 代码的信息足以解决我的问题。真的很有帮助。
猜你喜欢
  • 2023-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-16
  • 2014-05-08
  • 1970-01-01
  • 1970-01-01
  • 2013-08-24
相关资源
最近更新 更多