如何使用AES在一个程序中加密,在另一个程序中解密 [英] How do you use AES to Encrypt in One Program, Decrypt in Another

查看:905
本文介绍了如何使用AES在一个程序中加密,在另一个程序中解密的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我被告知不要使用 RSA加密简单文本,但使用AES。我发现一个简单的代码实现AES:

I was told not to use RSA to encrypt simple text but to use AES. I found a simple piece of code to implement 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服务程序中解密:

However, this is based on a string coming back and then used to decrypt in the same program. I need to encrypt the following data in a WinForms program and the decrypt in a whole separate Windows Service program:

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");

我该怎么办?请显示示例代码。

How can I do it? Please show sample code.

编辑:Kevin,我已经实现了你的算法,但问题是我想生成密钥一次并保存在其他程序中使用解密,但我需要传递byte []加密功能。所以我试图转换使用System.Text.Encoding.ASCII.GetBytes(key);并且它不正确地做。我有错误的字节数字节[]为键。

Kevin, I have implemented your algorithm but the problem is I want to generate the key once and save it for use in the other program to decrypt but I need to pass the byte[] to the encrypt function. So I tried converting using System.Text.Encoding.ASCII.GetBytes(key); and it doesn't do it correctly. I have the wrong number of bytes for byte[] for the 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:这是现在的两个部分。加密端:

Here's both parts as they stand now. The encrypting side:

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服务端:

The Windows Service side that tries to decrypt:

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);
        }


推荐答案

一个随机初始化向量,它放在加密值的开头,因此您可以加密相同的值两次,而不会获得相同的加密输出。这是相当正常的,让你只能传递一个单一的秘密来回。

The algorithm I wrote below uses a random Initialization Vector that it puts at the beginning of the encrypted value so you can encrypt the same value twice and not get the same encrypted output. This is fairly normal and lets you only pass a single "secret" back and forth.

您需要通过一些超越过程共享您的密钥,因为两个加密和解密需要知道的关键。这是在其他地方记录的密钥交换的一个单独的主题。 此处是一个SO链接,如果您需要帮助,可以开始使用。

You will need to share your secret key by some out of bounds process because both encryption and decryption need to know the key. That is a seperate topic of key exchange that is documented in other places. Here is an SO link to get you started if you need some help on it.

此外,如果你是弥补随机值,我建议你不要。使用某些东西来帮助你喜欢以下生成随机字节,然后将它们转换为base64字符串,这更容易为人类使用或一些类型的密钥交换。注意,这只是一个如何生成随机密钥的示例...在实践中,这可能基于一些用户输入是可重新生成的,或者您可以使用用户哈希值来查找您生成的随机密钥。无论如何,这里是键的代码...

Also if you are "making up" random values I recommend that you don't. Use something to help you like the following which generates random bytes and then converts them into a base64 string which is easier for human usage or some types of key exchange. Note that this is just an example of how you could generate random key's... in practice this may be based on some user input that is recreatable or you use the users hash value to lookup your random key that you generate. In any event here is the code for the key...

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

Here are the encryption methods... EncryptStringToBase64String and DecryptStringFromBase64String.

编辑:伟大点owlstead关于使用Aes.BlockSize IV大小。 我也清除了争论检查。

Great point owlstead about using Aes.BlockSize for the IV size. I've also cleaned up the arguement checks.

    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的字符串。如果数据开始生命为字符串,并使用编码转换为二进制,然后和ONLY,然后可以使用正确的编码将其从二进制转换为字符串。否则,您将拥有有时的代码,这是一种折磨自己的食谱。

EDIT 2: Never convert actual binary data (like a random key) into a string using a TextEncoding. If data starts life as a string and you convert into binary using an encoding then and ONLY then can you convert it from binary into a string using the proper encoding. Otherwise you will have code that works sometimes which is a recipe for torturing yourself.

        // 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。

Why use File.WriteAllText to write the file but use File.ReadAllBytes when you read it? You can write it and read it as text and use ASCII encoding since base64 is guaranteed to be ASCII. Also Decrypt returns a decrypted string which you are not storing or using. The decrypted string is what you need to parse because it's your xml.

你可以使用它来保存文件...

You can use this for saving the file...

    var encryptedText = File.ReadAllText(fileName, new ASCIIEncoding());

在您的解密中,您应该这样做...

In your decrypt you should do this...

    var encryptedText = File.ReadAllText(fileName, new ASCIIEncoding());
    string xmlStr = DecryptStringFromBase64String(encryptedStr , keyBytes);

EDIT 4:我尝试复制您的例外,这是我的测试代码,我在控制台应用程序中运行它的工作原理。

EDIT 4: I've attempted to duplicate your exception and I can't make it happen... here is my test code that I'm running in a console app and it works.

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());
    }
}

>

Usage from the console app...

    EncryptMethod();
    DecryptMethod();

这篇关于如何使用AES在一个程序中加密,在另一个程序中解密的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆