在 C# 和 PHP 中使用 AES 中的盐

Using Salt in AES in C# and PHP

我正在尝试使用 AES 对字符串进行编码和解码。目前,我正在使用评分最高的答案在 Mono C# 中对字符串进行编码 here, because System.Security.Crytpography.Aes is not available in Mono. However, this implementation uses a Salt, and the PHP method 我用来解密它不需要加盐,只需要一个我生成的初始化向量。

我的问题: 加密数据被加盐,即使使用已知的加盐字符串,我也不知道如何对其进行解盐。

  1. 我应该尝试从 C# class 中删除盐吗?
    • 仅使用明文 password/key 和初始化向量的实现是否足够好?
  2. 或者我可以在 PHP 中使用另一种解密形式,它将采用密文、密钥、盐和初始化向量?
  3. 或者我应该在调用 mcrypt_decrypt 之后尝试对解密的文本进行解盐处理吗?这是正确的顺序吗?
  4. 或者我应该完全重写 C# AES class?它实际上是一个坏例子吗?
  5. [edit] 或者有人知道我可以在 PHP 中使用的 Rfc2898DeriveBytes 实现吗?我不确定自己是否有足够的信心自己编写实现,以免因某些错误而完全破坏安全点。

抱歉我的无知,这是我第一次接触加密,还有很多信息需要吸收。

答案you have posted implements the Rfc2898DeriveBytes class to get the bytes of the encrypting key. This is advised, but not mandatory。您不必使用 Rfc2898DeriveBytes 并且可以简单地修改该 AES 实现以不加盐并直接将密码的字节作为密钥。虽然我不建议在实践中这样做。

我推荐的是找到一个更合适的 PHP AES 实现,它允许对您的密码进行加盐以获取密钥字节——这应该是可用的(抱歉,我对 PHP 没有什么经验在这方面帮助您;您可能会发现 PHP 加密库中存在一种额外的方法,可以根据类似于 .NET/MONO 的 Rfc2898DeriveBytes 的密码和盐输入来形成密钥) .

#1 否

#2 是(见下文)

#3 否

#4 不,我觉得还不错

#5 请使用您的加密数据尝试此 PHP 实施。我没有测试过。

<?php

function pbkdf2( $p, $s, $c, $kl, $a = 'sha1' ) {
    $hl = strlen(hash($a, null, true)); # Hash length
    $kb = ceil($kl / $hl);              # Key blocks to compute
    $dk = '';                           # Derived key
    # Create key
    for ( $block = 1; $block <= $kb; $block ++ ) {
        # Initial hash for this block
        $ib = $b = hash_hmac($a, $s . pack('N', $block), $p, true);
        # Perform block iterations
        for ( $i = 1; $i < $c; $i ++ )
            # XOR each iterate
            $ib ^= ($b = hash_hmac($a, $b, $p, true));
        $dk .= $ib; # Append iterated block
    }
    # Return derived key of correct length
    return substr($dk, 0, $kl);
}

//Usage example (Decryption by PHP)
$ciphertext_b64 = "owiCMbopBmr+NvjBEUT2Hg==";

$password = "password";
$salt = "g46dzQ80"; //Please change to the salt you are using.  Copied from the referenced answer code.

//This is the key derivation part.  I think .net uses 1000 iterations of sha1.
$key = pbkdf2($password, $salt, 1000, 32, "sha1");
$iv = "OFRna74m*aze01xY"; //Again, I copied the IV from the .NET code in the answer you referenced.

$plaintext = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, base64_decode($ciphertext_b64), MCRYPT_MODE_CBC, $iv), "[=10=]");

echo $plaintext;
// Output = hello