我試圖寫一個C#方法,將吐出同樣的加密字符串(Base64編碼),如OpenSSL的二進制文件沒有,但我有一個時間把事情匹配赫克向上。C#和OpenSSL:它支持AES加密不同的輸出
大量的終端輸出和C#的遵循...:P
我們要使用加密字符串「a」,密碼爲「123」的非常精彩的例子。
首先是OpenSSL的時候我提供我的靜態鹽和密碼(這是怎樣的命令將被理想的運行,而我希望我的C#輸出匹配到什麼):
[email protected] ~# echo -n a | openssl enc -aes-128-cbc -S cc77e2a591358a1c -pass pass:123 -a -p
salt=CC77E2A591358A1C
key=7B2AD689138A44AD32297BBAAA5B0EEE
iv =EC4F0416B2E9A9B2FEEF2E66FF982159
U2FsdGVkX1/Md+KlkTWKHOtnt1ftHSKyWiz6GxkBVck=
第二個是openssl,當我提供我的靜態鹽,以及從該鹽派生的密鑰和iv(從第一個命令的輸出C + p'd)但沒有密碼(因爲即使文檔說這將是一個不 - 好主意):
[email protected] ~# echo -n a | openssl enc -aes-128-cbc -S cc77e2a591358a1c -K 7b2ad689138a44ad32297bbaaa5b0eee -iv ec4f0416b2e9a9b2feef2e66ff982159 -a -p
salt=E85778B7FFFFFFFF
key=7B2AD689138A44AD32297BBAAA5B0EEE
iv =EC4F0416B2E9A9B2FEEF2E66FF982159
62e3V+0dIrJaLPobGQFVyQ==
這讓我覺得很奇怪。將第一個命令中的「調試」輸出(-p參數)中的鍵和iv值添加到相同的鹽中,我以某種方式得到不同的鹽! (CC77E2A591358A1C和E85778B7FFFFFFFF [0xff的4個字節在這裏似乎很有意思])。
第三是我的應用程序的輸出:
[email protected] ~# mono aestest.exe "a" "123"
==> INPUT : a
==> SECRET : 123
==> SALT : cc77e2a591358a1c
==> KEY : 7b2ad689138a44ad32297bbaaa5b0eee
==> IV : ec4f0416b2e9a9b2feef2e66ff982159
==> ENCRYPTED : 62e3V+0dIrJaLPobGQFVyQ==
因此,C#匹配openssl命令的輸出,當我手動指定的密鑰和IV自己(即然後以某種方式產生不同的鹽) ,但似乎有點不對。在我看來,C#應用程序的輸出應該與第一組OpenSSL輸出相匹配,不是嗎?
C#代碼:
public static string EncryptString(string plainText, string password)
{
byte[] salt = Encryption.GetStaticSalt();
byte[] key, iv;
Encryption.DeriveKeyAndIV(password, salt, out key, out iv);
var amAes = new AesManaged();
amAes.Mode = CipherMode.CBC;
amAes.KeySize = 128;
amAes.BlockSize = 128;
amAes.Key = key;
amAes.IV = iv;
var icTransformer = amAes.CreateEncryptor();
var msTemp = new MemoryStream();
var csEncrypt = new CryptoStream(msTemp, icTransformer, CryptoStreamMode.Write);
var sw = new StreamWriter(csEncrypt);
sw.Write(plainText);
sw.Close();
sw.Dispose();
csEncrypt.Clear();
csEncrypt.Dispose();
byte[] bResult = msTemp.ToArray();
string sResult = Convert.ToBase64String(bResult);
if (System.Diagnostics.Debugger.IsAttached)
{
string debugDetails = "";
debugDetails += "==> INPUT : " + plainText + Environment.NewLine;
debugDetails += "==> SECRET : " + password + Environment.NewLine;
debugDetails += "==> SALT : " + Encryption.ByteArrayToHexString(salt) + Environment.NewLine;
debugDetails += "==> KEY : " + Encryption.ByteArrayToHexString(amAes.Key) + " (" + amAes.KeySize.ToString() + ")" + Environment.NewLine;
debugDetails += "==> IV : " + Encryption.ByteArrayToHexString(amAes.IV) + Environment.NewLine;
debugDetails += "==> ENCRYPTED : " + sResult;
Console.WriteLine(debugDetails);
}
return sResult;
}
private static string ByteArrayToHexString(byte[] bytes)
{
StringBuilder sbHex = new StringBuilder();
foreach (byte b in bytes)
sbHex.AppendFormat("{0:x2}", b);
return sbHex.ToString();
}
public static byte[] GetStaticSalt()
{
// Just random bytes.
return new byte[]
{
0xcc,
0x77,
0xe2,
0xa5,
0x91,
0x35,
0x8a,
0x1c
};
}
// largely hijacked from http://stackoverflow.com/a/8011654/97423
public static void DeriveKeyAndIV(string password, byte[] bSalt, out byte[] bKey, out byte[] bIV)
{
int keyLen = 16;
int ivLen = 16;
byte[] bPassword = Encoding.UTF8.GetBytes(password);
using (var md5Gen = MD5.Create())
{
List<byte> lstHashes = new List<byte>(keyLen + ivLen);
byte[] currHash = new byte[0];
int preHashLength = bPassword.Length + bSalt.Length;
byte[] preHash = new byte[preHashLength];
Buffer.BlockCopy(bPassword, 0, preHash, 0, bPassword.Length);
Buffer.BlockCopy(bSalt, 0, preHash, bPassword.Length, bSalt.Length);
currHash = md5Gen.ComputeHash(preHash);
lstHashes.AddRange(currHash);
while (lstHashes.Count < (keyLen + ivLen))
{
preHashLength = currHash.Length + password.Length + bSalt.Length;
preHash = new byte[preHashLength];
Buffer.BlockCopy(currHash, 0, preHash, 0, currHash.Length);
Buffer.BlockCopy(bPassword, 0, preHash, currHash.Length, password.Length);
Buffer.BlockCopy(bSalt, 0, preHash, currHash.Length + password.Length, bSalt.Length);
currHash = md5Gen.ComputeHash(preHash);
lstHashes.AddRange(currHash);
}
bKey = new byte[keyLen];
bIV = new byte[ivLen];
lstHashes.CopyTo(0, bKey, 0, keyLen);
lstHashes.CopyTo(keyLen, bIV, 0, ivLen);
}
}
我缺少的東西真的很明顯這裏,或者是這個東西更加微妙?我環顧四周,已經看到很多關於C#,OpenSSL和AES的內容,但沒有涉及到這個具體問題......所以,halp? ;)
現在讓鮑勃馬利再次離開我的頭:) –