問題描述
玩弄 C# 加密 (Playing around with C# encryption)
Been trying to venture out and learn some C# and powershell, giving myself little projects to try and learn. Recently I have been trying to convert some code from powershell to C# and I believe I got it working but am coming across some errors creating the IV for RijndaelManaged.
This is the powershell code that works fine, pulled from the internet
function Decrypt‑String($Encrypted, $Passphrase, $salt, $init="Yet another key")
{
if($Encrypted ‑is [string]){
$Encrypted = [Convert]::FromBase64String($Encrypted)
}
$r = new‑Object System.Security.Cryptography.RijndaelManaged
$pass = [System.Text.Encoding]::UTF8.GetBytes($Passphrase)
$salt = [System.Text.Encoding]::UTF8.GetBytes($salt)
$r.Key = (new‑Object Security.Cryptography.PasswordDeriveBytes $pass, $salt, "SHA1", 5).GetBytes(32) #256/8
$r.IV = (new‑Object Security.Cryptography.SHA1Managed).ComputeHash( [Text.Encoding]::UTF8.GetBytes($init) )[0..15]
$d = $r.CreateDecryptor()
$ms = new‑Object IO.MemoryStream @(,$Encrypted)
$cs = new‑Object Security.Cryptography.CryptoStream $ms,$d,"Read"
$sr = new‑Object IO.StreamReader $cs
Write‑Output $sr.ReadToEnd()
$sr.Close()
$cs.Close()
$ms.Close()
$r.Clear()
}
And this is the C# code i moved it over to
public static string Decrypt_String(string cipherText, string passPhrase, string Salt)
{
string hashAlgorithm = "SHA1";
int passwordIterations = 5;
initName = "Yet another key";
using (RijndaelManaged r = new RijndaelManaged())
{
byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
byte[] PassPhraseBytes = Encoding.UTF8.GetBytes(passPhrase);
byte[] SaltBytes = Encoding.UTF8.GetBytes(Salt);
byte[] initVectorBytes = Encoding.UTF8.GetBytes(initName);
PasswordDeriveBytes password = new PasswordDeriveBytes(PassPhraseBytes,SaltBytes,hashAlgorithm,passwordIterations);
byte[] keyBytes = password.GetBytes(32); //(256 / 32)
r.Key = keyBytes;
SHA1Managed cHash = new SHA1Managed();
r.IV = cHash.ComputeHash(Encoding.UTF8.GetBytes(initName),0,16);
ICryptoTransform decryptor = r.CreateDecryptor();
MemoryStream memoryStream = new MemoryStream(cipherTextBytes);
CryptoStream cryptoStream = new CryptoStream(memoryStream,
decryptor,
CryptoStreamMode.Read);
StreamReader streamReader = new StreamReader(cryptoStream);
string output = streamReader.ReadToEnd();
return output;
}
}
Currently the ComputeHash is spitting back an error telling me the value is invalid. here are the values I am using from the working encrypt function
cipherText = "s6ZqNpJq05jsMh2+1BxZzJQDDiJGRQPqIYzBjYQHsgw="
saltValue = "}=[BJ8%)vjJDnQfmvC))))3Q"
passphrase = "S@lt3d"
Any ideas on why the IV wont set properly?
EDIT: Sorry the exception is
Line 38: r.IV = cHash.ComputeHash(initVectorBytes, 0, 16);
Exception Details: System.ArgumentException: Value was invalid.
Kind of generic
‑‑‑‑‑
參考解法
方法 1:
<p>@Nate is correct, you are using a different overload of the ComputeHash
method, and you are not quite handling it properly:</p>
Encoding.UTF8.GetBytes(initName)
This will return a byte array the same length as your string ‑ 15. But by passing 0
and 16
, you are asking ComputeHash
to use the first 16 elements of the array.
cHash.ComputeHash(Encoding.UTF8.GetBytes(initName),0,16);
So this first fix is to either pass 0
and 15
(or maybe 0
and initName.Length
), or better yet, go back to the overload you are using in your powershell script, which figures out the array length automatically:
cHash.ComputeHash(Encoding.UTF8.GetBytes(initName));
But you will need to shorten the resulting array (it comes back length 20, but you only want 16):
using System.Linq;
...
cHash.ComputeHash(Encoding.UTF8.GetBytes(initName)).Take(16).ToArray();