【发布时间】:2020-03-22 07:42:12
【问题描述】:
我找到了一个应该在 PHP 和 C# 中工作的 AES 加密/解密实现: https://odan.github.io/2017/08/10/aes-256-encryption-and-decryption-in-php-and-csharp.html
但是,在此示例中,IV 始终为 0,这是不好的。 所以,正如作者所建议的,我使用了 openssl_random_pseudo_bytes() 函数:
$ivlen = openssl_cipher_iv_length($method);
$iv = openssl_random_pseudo_bytes($ivlen);
但是,现在的问题是,我必须将 IV 存储在某个地方,以便 C# 应用程序可以使用它进行解密。我的想法是对其进行base64_encode并将其添加到加密消息中,并用“:”将两者分开,这样我就可以简单地拆分字符串,然后在C#中对其进行base64解码并可以使用IV。但是,这不起作用。这是代码:
public string DecryptString(string cipherText, byte[] key, byte[] iv)
{
// Instantiate a new Aes object to perform string symmetric encryption
Aes encryptor = Aes.Create();
encryptor.Mode = CipherMode.CBC;
// Set key and IV
byte[] aesKey = new byte[32];
Array.Copy(key, 0, aesKey, 0, 32);
encryptor.Key = aesKey;
encryptor.IV = iv;
// Instantiate a new MemoryStream object to contain the encrypted bytes
MemoryStream memoryStream = new MemoryStream();
// Instantiate a new encryptor from our Aes object
ICryptoTransform aesDecryptor = encryptor.CreateDecryptor();
// Instantiate a new CryptoStream object to process the data and write it to the
// memory stream
CryptoStream cryptoStream = new CryptoStream(memoryStream, aesDecryptor, CryptoStreamMode.Write);
// Will contain decrypted plaintext
string plainText = String.Empty;
try {
// Convert the ciphertext string into a byte array
byte[] cipherBytes = Convert.FromBase64String(cipherText);
// Decrypt the input ciphertext string
cryptoStream.Write(cipherBytes, 0, cipherBytes . Length);
// Complete the decryption process
cryptoStream.FlushFinalBlock();
// Convert the decrypted data from a MemoryStream to a byte array
byte[] plainBytes = memoryStream.ToArray();
// Convert the decrypted byte array to string
plainText = Encoding.ASCII.GetString(plainBytes, 0, plainBytes.Length);
} finally {
// Close both the MemoryStream and the CryptoStream
memoryStream.Close();
cryptoStream.Close();
}
// Return the decrypted data as a string
return plainText;
}
这就是我尝试在加密消息前加上 IV 来调用函数的方式:
private void btnDecrypt_Click(object sender, EventArgs e)
{
string encrypted = txtEncrypted.Text;
string password = txtPW.Text;
string[] temp = encrypted.Split(":".ToCharArray());
string iv_str = temp[0];
encrypted = temp[1];
SHA256 mySHA256 = SHA256Managed.Create();
byte[] key = mySHA256.ComputeHash(Encoding.ASCII.GetBytes(password));
iv_str = Encoding.Default.GetString(Convert.FromBase64String(iv_str));
byte[] iv = Encoding.ASCII.GetBytes(iv_str);
txtDecrypted.Text = this.DecryptString(encrypted, key, iv);
}
不起作用。它解密了一些东西,但这只是胡言乱语,而不是我在 PHP 中加密的消息。 我认为这与IV有关。
【问题讨论】:
-
加密你有公钥和私钥。私钥不应该随消息一起发送。将私钥与数据一起发送可以让黑客轻松解密数据。私钥应该以安全的方式单独发送,这样黑客就不会同时获得加密的消息和私钥。
-
据我所知这是一种对称加密。我没有预先添加密钥,但是解密所必需的 IV,不是吗?
-
通常在字节级别进行连接,首先是 IV,然后是密文,结果是 Base64 编码。不需要分隔符,因为 IV 的大小是已知的(密码的块大小,即 AES 为 16 个字节)。但你的方式也应该有效。一个可能的错误来源是编码:在
btnDecrypt_Click中,iv_str是 Base64 解码,然后使用默认编码解码为字符串,最后使用 ASCII 编码进行编码。最后两步是错误的。如果iv_str是Base64 编码,byte[] iv = Convert.FromBase64String(iv_str)就足够了。 -
您永远不会将密钥与数据一起发送。给强盗一把你家的钥匙也是类似的。
-
@jdweng - 据我所知,密钥不是随数据一起发送的,而是从密码中派生的(虽然 SHA256 不是 KDF 的好选择,但 PBKDF2 会更好,@ 987654322@)。如果您提到 IV,IV 是 no secret (here) 并且可能在未加密的情况下发送,例如通常与密文一起!