我创建了一些使用StreamWriter将数据导出到文本文件的小程序,然后我使用StreamReader读回它们。这很好用,我做了我需要它做但我想知道是否有一种方法可以保存这些信息,而无需用户有意或无意地访问或修改它。我在文本文件中会有一个例子,如果勾选了一个复选框,当你勾选它时会将“Ticked”输出到一个文本文件,当程序重新打开时,我知道该表单处于什么状态时关门了。我显然不想继续使用文本文件。有没有人对如何在没有用户修改它的情况下轻松存储这些信息有任何想法?非常感谢你。
答案 0 :(得分:7)
最简单的方法是对此文本进行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
答案 1 :(得分:2)
您可以在文件中添加checksum或hash - 如果文件内容与校验和不一致,您就知道它已被篡改。
如果用户无法读取文件内容,请加密。
我不相信你可以创建一个无法被篡改的文件(例如,一个精明的用户可以使用十六进制编辑器进行更改) - 你能做的最好就是检测这种篡改。
答案 2 :(得分:2)
您应该使用每用户密钥调用ProtectedData.Protect
来加密数据。
请注意,熟练的用户解密和修改数据并不是很困难 您的程序在用户机器上执行的任何操作也可由用户完成。
答案 3 :(得分:1)
您可以使用Ionic zip libraries压缩这些文本文件。如有必要,您还可以使用Ionic zip的功能,如密码保护和加密。而且你仍然可以使用你用来创建它的相同设置自己手动打开文件(使用压缩应用程序,例如7zip)。
答案 4 :(得分:1)
如果程序可以访问该信息,则用户通常也可以访问该信息。但是,您可以生成用户无法立即理解的数据。
我首先创建一个包含您要保存的所有状态信息的类,然后隔离问题。巧合的是,BinaryFormatter
类将允许您轻松地将此类保存到文件或从文件加载此类。我不知道它的结果是否“足够难以理解” - 如果不是,请像Leon所提到的那样应用Base64编码。
答案 5 :(得分:1)
虽然您可以像已经建议的那样使用base64编码甚至完全加密配置数据(使用SHA1或MD5),但我认为良好的做法是使用处理配置数据的框架类(Configuration
下的ConfigurationSection
{1}}命名空间)它内置了加密数据的能力(通过msdn example类的System.Configuration
方法)。
首先,您应该声明并初始化一个实例:
ProtectSection
之后,您需要定义一个定义配置的自定义配置部分(here)
完成后,您只需要初始化自定义配置部分的实例,并使用以下代码将其添加到配置文件中:
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
...
要加密刚刚添加的部分,请使用此代码(在VB.NET和C#中找到{{3}}的其他示例):
isTicked = config.Sections.Add("isTicked", customSection);
默认情况下内置“DPAPIProtectedConfigurationProvider”和“RSAProtectedConfigurationProvider”。
一旦您想解密该部分,请使用以下代码:
config.Sections["isTicked"].SectionInformation.ProtectSection("protection provider");
强调一点 - 加密和解密只有在保存配置文件后才会生效
要保存文件,请使用以下代码:
config.Sections["isTicked"].SectionInformation.UnprotectSection();
有关相关类和方法的更多信息可以在msdn中找到,从上面链接的config.Save(); //config.SaveAs("string") is also available
类页面开始。
答案 6 :(得分:1)
尝试使用此代码加密和解密您的文字! 我认为这很容易和强大......
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;
}
}
}
答案 7 :(得分:1)
只是为了添加Leon的另一个答案,然后按照 Microsoft docs
这是一个加密和解密字符串的类示例
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;
}
}
顺便说一句,这是"盐值"我用Google搜索的定义,以找出它是什么。
如果攻击者不知道密码,并且试图用蛮力攻击来猜测密码,那么他尝试的每个密码都必须尝试使用每个盐值。因此,对于一位盐(0或1),这使得加密以这种方式难以破解两次。
答案 8 :(得分:0)
可以使用this answer中指出的校验和来防止意外的字符串修改。
但是,生成这样的校验和非常容易,因为它们的使用范围并不广泛used algorithms。
因此,这不能保护您免受有意的修改。
为防止这种情况,人们使用digital signatures。这样一来,任何人都可以验证您的数据未被篡改,但是只有您(私人机密的所有者)才能生成签名。
Here是C#中的一个示例。
但是,正如其他人指出的那样,您需要将私钥嵌入二进制文件中的某个位置,即使您混淆了.net dll或在其中进行了编码,熟练的(不是这样)熟练的程序员也将能够检索它。一个单独的本地过程。
尽管如此,对于大多数关注而言这已经足够了。
如果您真的很担心安全性,那么您需要在云上移动并在您拥有的计算机上执行代码。