【发布时间】:2014-04-07 18:33:12
【问题描述】:
有人告诉我not to use RSA 加密简单文本但使用 AES。我找到了一段简单的代码来实现 AES:
public static class Crypto
{
#region Settings
private static int _iterations = 2;
private static int _keySize = 256;
private static string _hash = "SHA1";
private static string _salt = "aselrias38490a32"; // Random
private static string _vector = "8947az34awl34kjq"; // Random
#endregion
public static string Encrypt(string value, string password)
{
return Encrypt<AesManaged>(value, password);
}
public static string Encrypt<T>(string value, string password)
where T : SymmetricAlgorithm, new()
{
byte[] vectorBytes = Encoding.ASCII.GetBytes(_vector);
byte[] saltBytes = Encoding.ASCII.GetBytes(_salt);
byte[] valueBytes = Encoding.UTF8.GetBytes(value);
byte[] encrypted;
using (T cipher = new T())
{
PasswordDeriveBytes _passwordBytes =
new PasswordDeriveBytes(password, saltBytes, _hash, _iterations);
byte[] keyBytes = _passwordBytes.GetBytes(_keySize/8);
cipher.Mode = CipherMode.CBC;
using (ICryptoTransform encryptor = cipher.CreateEncryptor(keyBytes, vectorBytes))
{
using (MemoryStream to = new MemoryStream())
{
using (CryptoStream writer = new CryptoStream(to, encryptor, CryptoStreamMode.Write))
{
writer.Write(valueBytes, 0, valueBytes.Length);
writer.FlushFinalBlock();
encrypted = to.ToArray();
}
}
}
cipher.Clear();
}
return Convert.ToBase64String(encrypted);
}
public static string Decrypt(string value, string password)
{
return Decrypt<AesManaged>(value, password);
}
public static string Decrypt<T>(string value, string password) where T : SymmetricAlgorithm, new()
{
byte[] vectorBytes = Encoding.ASCII.GetBytes(_vector);
byte[] saltBytes = Encoding.ASCII.GetBytes(_salt);
byte[] valueBytes = Convert.FromBase64String(value);
byte[] decrypted;
int decryptedByteCount = 0;
using (T cipher = new T())
{
PasswordDeriveBytes _passwordBytes = new PasswordDeriveBytes(password, saltBytes, _hash, _iterations);
byte[] keyBytes = _passwordBytes.GetBytes(_keySize/8);
cipher.Mode = CipherMode.CBC;
try
{
using (ICryptoTransform decryptor = cipher.CreateDecryptor(keyBytes, vectorBytes))
{
using (MemoryStream from = new MemoryStream(valueBytes))
{
using (CryptoStream reader = new CryptoStream(from, decryptor, CryptoStreamMode.Read))
{
decrypted = new byte[valueBytes.Length];
decryptedByteCount = reader.Read(decrypted, 0, decrypted.Length);
}
}
}
}
catch (Exception ex)
{
return String.Empty;
}
cipher.Clear();
}
return Encoding.UTF8.GetString(decrypted, 0, decryptedByteCount);
}
}
但是,这是基于返回的字符串,然后用于在同一程序中解密。我需要在 WinForms 程序中加密以下数据并在整个单独的 Windows 服务程序中解密:
string fileName = System.IO.Path.Combine(Application.StartupPath, "alphaService.xml");
XDocument doc = new XDocument();
XElement xml = new XElement("Info",
new XElement("DatabaseServerName", txtServerName.Text),
new XElement("DatabaseUserName", txtDatabaseUserName.Text),
new XElement("DatabasePassword", txtDatabasePassword.Text),
new XElement("ServiceAccount", txtAccount.Text),
new XElement("ServicePassword", txtServicePassword.Text),
new XElement("RegistrationCode", txtRegistrationCode.Text));
doc.Add(xml);
doc.Save(fileName);
// Convert XML doc to byte stream
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(fileName);
// byte[] fileBytes = Encoding.Default.GetBytes(xmlDoc.OuterXml);
string encrypted = Crypto.Encrypt(xmlDoc.OuterXml, "testpass");
我该怎么做?请显示示例代码。
编辑:凯文,我已经实现了你的算法,但问题是我想生成一次密钥并将其保存以用于其他程序进行解密,但我需要将 byte[] 传递给 encrypt 函数。所以我尝试使用 System.Text.Encoding.ASCII.GetBytes(key);它没有正确地做到这一点。我的 byte[] 字节数错误。
string fileName = System.IO.Path.Combine(Application.StartupPath, "alphaService.xml");
XDocument doc = new XDocument();
XElement xml = new XElement("Info",
new XElement("DatabaseServerName", txtServerName.Text),
new XElement("DatabaseUserName", txtDatabaseUserName.Text),
new XElement("DatabasePassword", txtDatabasePassword.Text),
new XElement("ServiceAccount", txtAccount.Text),
new XElement("ServicePassword", txtServicePassword.Text),
new XElement("RegistrationCode", txtRegistrationCode.Text));
doc.Add(xml);
doc.Save(fileName);
// Read file to a string
string contents = File.ReadAllText(fileName);
string key = String.Empty;
byte[] aesKey;
using (var aes = Aes.Create())
{
// aesKey = aes.Key;
key = Convert.ToBase64String(aes.Key);
}
string sKey = "LvtZELDrB394hbSOi3SurLWAvC8adNpZiJmQDJHdfJU=";
aesKey = System.Text.Encoding.UTF8.GetBytes(sKey);
string encyptedText = EncryptDecrpt.EncryptStringToBase64String(contents, aesKey);
File.WriteAllText(fileName, encyptedText);
EDIT2:这两个部分都是现在的样子。加密方面:
private void SaveForm()
{
try
{
string fileName = System.IO.Path.Combine(Application.StartupPath, "alphaService.xml");
XDocument doc = new XDocument();
XElement xml = new XElement("Info",
new XElement("DatabaseServerName", txtServerName.Text),
new XElement("DatabaseUserName", txtDatabaseUserName.Text),
new XElement("DatabasePassword", txtDatabasePassword.Text),
new XElement("ServiceAccount", txtAccount.Text),
new XElement("ServicePassword", txtServicePassword.Text),
new XElement("RegistrationCode", txtRegistrationCode.Text));
doc.Add(xml);
// doc.Save(fileName);
// Read file to a string
// string contents = File.ReadAllText(fileName);
string key = String.Empty;
byte[] aesKey;
//using (var aes = Aes.Create())
//{
// aesKey = aes.Key;
// key = Convert.ToBase64String(aes.Key);
//}
string sKey = "LvtZELDrB394hbSOi3SurLWAvC8adNpZiJmQDJHdfJU=";
aesKey = Convert.FromBase64String(sKey);
string encyptedText = EncryptDecrpt.EncryptStringToBase64String(doc.ToString(), aesKey);
File.WriteAllText(fileName, encyptedText);
//doc.Save(fileName);
尝试解密的 Windows 服务端:
try
{
string path = AppDomain.CurrentDomain.BaseDirectory;
eventLog1.WriteEntry(path);
string fileName = System.IO.Path.Combine(path, "alphaService.xml");
string sKey = "LvtZELDrB394hbSOi3SurLWAvC8adNpZiJmQDJHdfJU=";
Byte[] keyBytes = Convert.FromBase64String(sKey);
var encryptedText = File.ReadAllText(fileName, new ASCIIEncoding());
string xmlStr = DecryptStringFromBase64String(encryptedText, keyBytes);
eventLog1.WriteEntry(xmlStr);
using (XmlReader reader = XmlReader.Create(new StringReader(xmlStr)))
{
reader.ReadToFollowing("DatabaseServerName");
DatabaseServerName = reader.ReadElementContentAsString();
reader.ReadToFollowing("DatabaseUserName");
DatabaseUserName = reader.ReadElementContentAsString();
reader.ReadToFollowing("DatabasePassword");
DatabasePassword = reader.ReadElementContentAsString();
reader.ReadToFollowing("RegistrationCode");
RegistrationCode = reader.ReadElementContentAsString();
}
eventLog1.WriteEntry("Configuration data loaded successfully");
}
catch (Exception ex)
{
eventLog1.WriteEntry("Unable to load configuration data. " + ex.Message);
}
【问题讨论】:
-
您需要存储盐和初始化向量,以便您可以在两个应用程序上使用它。你如何做到这一点取决于你,例如文件,配置文件,数据库,硬编码。一个更好的主意是使用证书的密钥来加密和解密。这样您就不必担心密钥存储
-
你能用代码展示一个例子吗?我只是不明白这些东西,很困惑!
-
我的建议确实暗示使用 RSA,只是因为这解决了密钥存储问题,所以可能对你不起作用,抱歉,我错过了顶部的链接。看看 this for storage of key and iv (stackoverflow.com/questions/18324149/…) 本质上,您需要将密钥和 IV 存储在某个地方,以便 winform 应用程序和 Windows 服务都可以读取它们
-
加密类型的选择——对称或非对称(或者,实际上是混合)——更多地取决于密钥管理而不是易用性。仅仅因为它简单而选择一些功能将导致不安全的解决方案。您至少需要对您正在做什么有一个提示,然后选择一个经过严格审查的解决方案。
-
@user2471435 永远不要使用 TextEncoding 将字节转换为字符串,除非您知道它以相同的方式编码为字节。您必须使用 Convert.FromBase64String(sKey)。我将编辑我的答案。
标签: c# encryption cryptography aes