C#加密文本输出

我创建了一些使用StreamWriter将数据导出到文本文件的小程序,然后我使用StreamReader读回它们。 这很好用,我做了我需要做的事情,但我想知道是否有一种方法可以保存这些信息,而无需用户有意或无意地访问或修改它。 我在文本文件中会有一个例子,如果勾选了一个复选框,当你勾选它时会将“Ticked”输出到一个文本文件,当程序重新打开时,我知道该表格处于什么状态时关门了。 我显然不想继续使用文本文件。 有没有人对如何在没有用户修改它的情况下轻松存储这些信息有任何想法? 非常感谢你。

最简单的方法是对此文本进行Base-64编码/解码。 这不安全,但会阻止临时用户修改数据。

static public string EncodeTo64(string toEncode) { byte[] toEncodeAsBytes = System.Text.ASCIIEncoding.ASCII.GetBytes(toEncode); string returnValue = System.Convert.ToBase64String(toEncodeAsBytes); return returnValue; } static public string DecodeFrom64(string encodedData) { byte[] encodedDataAsBytes = System.Convert.FromBase64String(encodedData); string returnValue = System.Text.ASCIIEncoding.ASCII.GetString(encodedDataAsBytes); return returnValue; } 

编辑:真正的加密

 #region Encryption string passPhrase = "Pasword"; // can be any string string saltValue = "sALtValue"; // can be any string string hashAlgorithm = "SHA1"; // can be "MD5" int passwordIterations = 7; // can be any number string initVector = "~1B2c3D4e5F6g7H8"; // must be 16 bytes int keySize = 256; // can be 192 or 128 private string Encrypt(string data) { byte[] bytes = Encoding.ASCII.GetBytes(this.initVector); byte[] rgbSalt = Encoding.ASCII.GetBytes(this.saltValue); byte[] buffer = Encoding.UTF8.GetBytes(data); byte[] rgbKey = new PasswordDeriveBytes(this.passPhrase, rgbSalt, this.hashAlgorithm, this.passwordIterations).GetBytes(this.keySize / 8); RijndaelManaged managed = new RijndaelManaged(); managed.Mode = CipherMode.CBC; ICryptoTransform transform = managed.CreateEncryptor(rgbKey, bytes); MemoryStream stream = new MemoryStream(); CryptoStream stream2 = new CryptoStream(stream, transform, CryptoStreamMode.Write); stream2.Write(buffer, 0, buffer.Length); stream2.FlushFinalBlock(); byte[] inArray = stream.ToArray(); stream.Close(); stream2.Close(); return Convert.ToBase64String(inArray); } private string Decrypt(string data) { byte[] bytes = Encoding.ASCII.GetBytes(this.initVector); byte[] rgbSalt = Encoding.ASCII.GetBytes(this.saltValue); byte[] buffer = Convert.FromBase64String(data); byte[] rgbKey = new PasswordDeriveBytes(this.passPhrase, rgbSalt, this.hashAlgorithm, this.passwordIterations).GetBytes(this.keySize / 8); RijndaelManaged managed = new RijndaelManaged(); managed.Mode = CipherMode.CBC; ICryptoTransform transform = managed.CreateDecryptor(rgbKey, bytes); MemoryStream stream = new MemoryStream(buffer); CryptoStream stream2 = new CryptoStream(stream, transform, CryptoStreamMode.Read); byte[] buffer5 = new byte[buffer.Length]; int count = stream2.Read(buffer5, 0, buffer5.Length); stream.Close(); stream2.Close(); return Encoding.UTF8.GetString(buffer5, 0, count); } #endregion 

您可以向文件添加校验和或散列 – 如果文件内容与校验和不一致,您就知道它已被篡改。

如果用户无法读取文件内容很重要,则可以对其进行加密。

我不相信你可以制作一个不能被篡改的文件(例如,一个精明的用户可以使用hex编辑器进行更改) – 你能做的最好就是检测这种篡改。

您应该使用每用户密钥调用ProtectedData.Protect来加密数据。

注意,熟练的用户解密和修改数据并不是很困难。
您的程序在用户机器上执行的任何操作也可由用户完成。

您可以使用Ionic zip库来压缩这些文本文件。 如有必要,您还可以使用Ionic zipfunction,如密码保护和加密。 而且你仍然可以使用你用来创建它的相同设置自己手动打开文件(使用压缩应用程序,例如7zip)。

如果程序可以访问该信息,则用户通常也可以访问该信息。 但是,您可以生成用户无法立即理解的数据。

我首先创建一个包含您要保存的所有状态信息的类,然后隔离问题。 巧合的是, BinaryFormatter类将允许您轻松地将此类保存到文件或从文件加载此类。 我不知道它的结果是否“足够难以理解” – 如果不是,请使用像Leon所提到的Base64编码。

虽然您可以对已经建议的配置数据进行base64编码甚至完全加密(使用SHA1或MD5),但我认为良好的做法是使用处理配置数据的框架类( System.Configuration命名空间下的Configuration )并构建它能够加密数据(通过ConfigurationSection类的ProtectSection方法)。

首先,您应该声明并初始化一个实例:

 using System.Configuration; ... static void Main(string[] args) { Configuration config; config = ConfigurationManager.OpenExeConfiguration(/*path to config file*/); //Use ConfigurationManager.OpenMachineConfiguration(/*path to config file*/) when opening machine configuration ... 

之后,您需要定义一个定义配置的自定义配置部分( msdn示例 )

完成后,您只需初始化自定义配置部分的实例,并使用以下代码将其添加到配置文件中:

 isTicked = config.Sections.Add("isTicked", customSection); 

要加密刚刚添加的部分,请使用此代码( 此处包含VB.NET和C#中的更多示例):

 config.Sections["isTicked"].SectionInformation.ProtectSection("protection provider"); 

默认情况下内置“DPAPIProtectedConfigurationProvider”和“RSAProtectedConfigurationProvider”。

一旦要解密该部分,请使用以下代码:

 config.Sections["isTicked"].SectionInformation.UnprotectSection(); 

强调一点 – 加密和解密只有在保存配置文件后才会生效

要保存文件,请使用以下代码:

 config.Save(); //config.SaveAs("string") is also available 

有关相关类和方法的更多信息可以在msdn中找到,从上面链接的Configuration类页面开始。

尝试使用此代码加密和解密您的文本! 我认为它非常容易和强大……

 public static class Crypto { private static readonly byte[] IVa = new byte[] { 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x11, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 }; public static string Encrypt(this string text, string salt) { try { using (Aes aes = new AesManaged()) { Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(Encoding.UTF8.GetString(IVa, 0, IVa.Length), Encoding.UTF8.GetBytes(salt)); aes.Key = deriveBytes.GetBytes(128 / 8); aes.IV = aes.Key; using (MemoryStream encryptionStream = new MemoryStream()) { using (CryptoStream encrypt = new CryptoStream(encryptionStream, aes.CreateEncryptor(), CryptoStreamMode.Write)) { byte[] cleanText = Encoding.UTF8.GetBytes(text); System.Diagnostics.Debug.WriteLine(String.Concat("Before encryption text data size: ", text.Length.ToString())); System.Diagnostics.Debug.WriteLine(String.Concat("Before encryption byte data size: ", cleanText.Length.ToString())); encrypt.Write(cleanText, 0, cleanText.Length); encrypt.FlushFinalBlock(); } byte[] encryptedData = encryptionStream.ToArray(); string encryptedText = Convert.ToBase64String(encryptedData); System.Diagnostics.Debug.WriteLine(String.Concat("Encrypted text data size: ", encryptedText.Length.ToString())); System.Diagnostics.Debug.WriteLine(String.Concat("Encrypted byte data size: ", encryptedData.Length.ToString())); return encryptedText; } } } catch(Exception e) { return String.Empty; } } public static string Decrypt(this string text, string salt) { try { using (Aes aes = new AesManaged()) { Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(Encoding.UTF8.GetString(IVa, 0, IVa.Length), Encoding.UTF8.GetBytes(salt)); aes.Key = deriveBytes.GetBytes(128 / 8); aes.IV = aes.Key; using (MemoryStream decryptionStream = new MemoryStream()) { using (CryptoStream decrypt = new CryptoStream(decryptionStream, aes.CreateDecryptor(), CryptoStreamMode.Write)) { byte[] encryptedData = Convert.FromBase64String(text); System.Diagnostics.Debug.WriteLine(String.Concat("Encrypted text data size: ", text.Length.ToString())); System.Diagnostics.Debug.WriteLine(String.Concat("Encrypted byte data size: ", encryptedData.Length.ToString())); decrypt.Write(encryptedData, 0, encryptedData.Length); decrypt.Flush(); } byte[] decryptedData = decryptionStream.ToArray(); string decryptedText = Encoding.UTF8.GetString(decryptedData, 0, decryptedData.Length); System.Diagnostics.Debug.WriteLine(String.Concat("After decryption text data size: ", decryptedText.Length.ToString())); System.Diagnostics.Debug.WriteLine(String.Concat("After decryption byte data size: ", decryptedData.Length.ToString())); return decryptedText; } } } catch(Exception e) { return String.Empty; } } } 

只是为了添加Leon的答案的另一个实现,并遵循Microsoft文档

这是一个加密和解密字符串的类示例

  public static class EncryptionExample { #region internal consts internal const string passPhrase = "pass"; internal const string saltValue = "salt"; internal const string hashAlgorithm = "MD5"; internal const int passwordIterations = 3; // can be any number internal const string initVector = "0123456789abcdf"; // must be 16 bytes internal const int keySize = 64; // can be 192 or 256 #endregion #region public static Methods public static string Encrypt(string data) { string res = string.Empty; try { byte[] bytes = Encoding.ASCII.GetBytes(initVector); byte[] rgbSalt = Encoding.ASCII.GetBytes(saltValue); byte[] buffer = Encoding.UTF8.GetBytes(data); byte[] rgbKey = new PasswordDeriveBytes(passPhrase, rgbSalt, hashAlgorithm, passwordIterations).GetBytes(keySize / 8); RijndaelManaged managed = new RijndaelManaged(); managed.Mode = CipherMode.CBC; ICryptoTransform transform = managed.CreateEncryptor(rgbKey, bytes); byte[] inArray = null; using (MemoryStream msEncrypt = new MemoryStream()) { using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, transform, CryptoStreamMode.Write)) { csEncrypt.Write(buffer, 0, buffer.Length); csEncrypt.FlushFinalBlock(); inArray = msEncrypt.ToArray(); res = Convert.ToBase64String(inArray); } } } catch (Exception ex) { Console.WriteLine("Encrypt " + ex); } return res; } public static string Decrypt(string data) { string res = string.Empty; try { byte[] bytes = Encoding.ASCII.GetBytes(initVector); byte[] rgbSalt = Encoding.ASCII.GetBytes(saltValue); byte[] buffer = Convert.FromBase64String(data); byte[] rgbKey = new PasswordDeriveBytes(passPhrase, rgbSalt, hashAlgorithm, passwordIterations).GetBytes(keySize / 8); RijndaelManaged managed = new RijndaelManaged(); managed.Mode = CipherMode.CBC; ICryptoTransform transform = managed.CreateDecryptor(rgbKey, bytes); using (MemoryStream msEncrypt = new MemoryStream(buffer)) { using (CryptoStream csDecrypt = new CryptoStream(msEncrypt, transform, CryptoStreamMode.Read)) { using (StreamReader srDecrypt = new StreamReader(csDecrypt)) { res = srDecrypt.ReadToEnd(); } } } } catch (Exception ex) { Console.WriteLine("Decrypt " + ex); } return res; } } 

顺便说一句,这是我用谷歌搜索的“盐值”定义,以找出它是什么。

盐值

如果攻击者不知道密码,并且试图用蛮力攻击来猜测密码,那么他尝试的每个密码都必须尝试使用​​每个盐值。 因此,对于一位盐(0或1),这使得加密以这种方式难以破解两次。

如本答案中所指出的,可以使用校验和来防止无意的字符串修改。

但是,生成这样的校验和非常容易,因为它们并不是那么多广泛使用的算法 。

因此,这不会保护您免受故意修改。

为了防止这种情况,人们使用数字签名 。 这允许任何人validation您的数据没有被篡改,但只有您(私人秘密的所有者)才能生成签名。

这是C#中的一个例子。

但是,正如其他人指出的那样,你需要将私钥嵌入到二进制文件中的某个位置,并且一个(不那么)熟练的程序员将能够检索它,即使你混淆了.net dll或者你是在一个单独的本机中处理。

尽管如此,这对于大多数问题来说已足够

如果您真的担心安全性,那么您需要移动云,并在您拥有的计算机上执行代码。