use*_*435 2 c# encryption cryptography aes
有人告诉我不要使用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");
我该怎么做?请显示示例代码。
编辑:凯文,我已经实现了你的算法,但问题是我想生成一次密钥并将其保存以用于其他程序进行解密,但我需要将字节 [] 传递给加密函数。所以我尝试使用 System.Text.Encoding.ASCII.GetBytes(key); 进行转换。它没有正确地做到这一点。我的密钥字节 [] 的字节数错误。
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);
        }
我在下面编写的算法使用一个随机初始化向量,它放在加密值的开头,因此您可以对相同的值进行两次加密,而不会获得相同的加密输出。这是相当正常的,并且只允许您来回传递一个“秘密”。
您将需要通过一些越界过程共享您的密钥,因为加密和解密都需要知道密钥。这是其他地方记录的密钥交换的单独主题。 如果您需要一些帮助,这里有一个 SO 链接可以帮助您入门。
此外,如果您“编造”随机值,我建议您不要这样做。使用一些东西来帮助您喜欢以下生成随机字节,然后将它们转换为 base64 字符串,这更易于人类使用或某些类型的密钥交换。请注意,这只是您如何生成随机密钥的一个示例……实际上,这可能基于某些可重新创建的用户输入,或者您使用用户哈希值来查找您生成的随机密钥。无论如何,这里是密钥的代码......
byte[] key;
string base64Key;
using (var aes = Aes.Create())
{
    // key as byte[]
    key = aes.Key;  
    // key as base64string - which one you use depends on how you store your keys
    base64Key= Convert.ToBase64String(aes.Key);
}
用法如下...
    // you get the base64 encoded key from somewhere
    var base64Key = "+CffHxKmykUvCrrCILd4rZDBcrIoe3w89jnPNXYi0rU="; 
    // convert it to byte[] or alternatively you could store your key as a byte[] 
    //   but that depends on how you set things up.
    var key = Convert.FromBase64String(base64Key);
    var plainText = "EncryptThis";
    var encryptedText = EncryptStringToBase64String(plainText, key);
    var decryptedText = DecryptStringFromBase64String(encryptedText, key);
这里是加密方法...EncryptStringToBase64String和DecryptStringFromBase64String。
编辑:关于使用 Aes.BlockSize 作为 IV 大小的好点 owlstead。 我还清理了争论检查。
    private const int KeySize = 256; // in bits
    static string EncryptStringToBase64String(string plainText, byte[] Key)
    {
        // Check arguments. 
        if (Key == null || Key.Length <= 0)
            throw new ArgumentNullException("Key");
        byte[] returnValue;
        using (var aes = Aes.Create())
        {
            aes.KeySize = KeySize;
            aes.GenerateIV();
            aes.Mode = CipherMode.CBC;
            var iv = aes.IV;
            if (string.IsNullOrEmpty(plainText))
                return Convert.ToBase64String(iv);
            var encryptor = aes.CreateEncryptor(Key, iv);
            // Create the streams used for encryption. 
            using (MemoryStream msEncrypt = new MemoryStream())
            {
                using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                {
                    using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                    {
                        //Write all data to the stream.
                        swEncrypt.Write(plainText);
                    }
                    // this is just our encrypted data
                    var encrypted = msEncrypt.ToArray();
                    returnValue = new byte[encrypted.Length + iv.Length];
                    // append our IV so our decrypt can get it
                    Array.Copy(iv, returnValue, iv.Length);
                    // append our encrypted data
                    Array.Copy(encrypted, 0, returnValue, iv.Length, encrypted.Length);
                }
            }
        }
        // return encrypted bytes converted to Base64String
        return Convert.ToBase64String(returnValue);
    }
    static string DecryptStringFromBase64String(string cipherText, byte[] Key)
    {
        // Check arguments. 
        if (string.IsNullOrEmpty(cipherText))
            return string.Empty;
        if (Key == null || Key.Length <= 0)
            throw new ArgumentNullException("Key");
        string plaintext = null;
        // this is all of the bytes
        var allBytes = Convert.FromBase64String(cipherText);
        using (var aes = Aes.Create())
        {
            aes.KeySize = KeySize;
            aes.Mode = CipherMode.CBC;
            // get our IV that we pre-pended to the data
            byte[] iv = new byte[aes.BlockSize/8];
            if (allBytes.Length < iv.Length)
                throw new ArgumentException("Message was less than IV size.");
            Array.Copy(allBytes, iv, iv.Length);
            // get the data we need to decrypt
            byte[] cipherBytes = new byte[allBytes.Length - iv.Length];
            Array.Copy(allBytes, iv.Length, cipherBytes, 0, cipherBytes.Length);
            // Create a decrytor to perform the stream transform.
            var decryptor = aes.CreateDecryptor(Key, iv);
            // Create the streams used for decryption. 
            using (MemoryStream msDecrypt = new MemoryStream(cipherBytes))
            {
                using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                {
                    using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                    {
                        // Read the decrypted bytes from the decrypting stream 
                        // and place them in a string.
                        plaintext = srDecrypt.ReadToEnd();
                    }
                }
            }
        }
        return plaintext;
    }
编辑 2:永远不要使用 TextEncoding 将实际的二进制数据(如随机密钥)转换为字符串。 如果数据以字符串形式开始,并且您使用编码将其转换为二进制,那么您只能使用正确的编码将其从二进制转换为字符串。否则,您的代码有时会起作用,这是一种折磨自己的方法。
        // This is base64 not UTF8, unicode, ASCII or anything else!!!
        string sKey = "LvtZELDrB394hbSOi3SurLWAvC8adNpZiJmQDJHdfJU=";
        aesKey = Convert.FromBase64String(sKey);
编辑3:
为什么File.WriteAllText用来写文件而File.ReadAllBytes读文件时使用?您可以将其作为文本写入和读取并使用 ASCII 编码,因为 base64 保证是 ASCII。Decrypt 还返回一个您没有存储或使用的解密字符串。解密后的字符串是您需要解析的,因为它是您的 xml。
您可以使用它来保存文件...
    var encryptedText = File.ReadAllText(fileName, new ASCIIEncoding());
在你的解密中,你应该这样做......
    var encryptedText = File.ReadAllText(fileName, new ASCIIEncoding());
    string xmlStr = DecryptStringFromBase64String(encryptedStr , keyBytes);
编辑 4:我试图复制您的异常,但我无法实现……这是我在控制台应用程序中运行的测试代码,并且可以正常工作。
public static void EncryptMethod()
{
    var fileName = @"c:/text.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);
    var sKey = "LvtZELDrB394hbSOi3SurLWAvC8adNpZiJmQDJHdfJU=";
    var aesKey = Convert.FromBase64String(sKey);
    string encyptedText = EncryptStringToBase64String(doc.ToString(), aesKey);
    File.WriteAllText(fileName, encyptedText);
}
public static void DecryptMethod()
{
    var fileName = @"c:/text.xml";
    string sKey = "LvtZELDrB394hbSOi3SurLWAvC8adNpZiJmQDJHdfJU=";
    Byte[] keyBytes = Convert.FromBase64String(sKey);
    var encryptedText = File.ReadAllText(fileName, new ASCIIEncoding());
    string xmlStr = DecryptStringFromBase64String(encryptedText, keyBytes);
    using (XmlReader reader = XmlReader.Create(new StringReader(xmlStr)))
    {
        reader.ReadToFollowing("DatabaseServerName");
        Console.WriteLine(reader.ReadElementContentAsString());
        reader.ReadToFollowing("DatabaseUserName");
        Console.WriteLine(reader.ReadElementContentAsString());
        reader.ReadToFollowing("DatabasePassword");
        Console.WriteLine(reader.ReadElementContentAsString());
        reader.ReadToFollowing("RegistrationCode");
        Console.WriteLine(reader.ReadElementContentAsString());
    }
}
从控制台应用程序使用...
    EncryptMethod();
    DecryptMethod();