c#加密文本输出

本文关键字:输出 加密文本 | 更新日期: 2023-09-27 18:06:15

我创建了一些小程序,使用StreamWriter将数据导出到文本文件,然后我使用StreamReader读取它们。这工作很好,做什么我需要它做的,但我想知道是否有一种方法,我可以保存这些信息,而无需用户能够访问或修改它有意或无意。我在文本文件中的一个例子是,如果一个复选框被选中,当你勾选它时,它会输出"被选中"到文本文件,当程序重新打开时,我知道表单在关闭时的状态。我显然不想继续使用文本文件。有没有人有任何想法,我可以很容易地存储这些信息,而不需要用户修改它?非常感谢。

c#加密文本输出

最简单的方法是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;
}

EDIT: Real encryption

#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

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

请注意,对于一个熟练的用户来说,解密和修改数据并不难。
你的程序在用户机器上做的任何事情,用户也可以做。

您可以向文件添加校验和或哈希-如果文件内容与校验和不一致,您就知道它被篡改了。

如果重要的是用户不能读取文件的内容,您可以加密它。

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

您可以使用Ionic zip库来压缩这些文本文件。如果有必要,你也可以使用Ionic zip的功能,如密码保护和加密。您仍然可以使用最初创建文件时使用的相同设置手动打开文件(使用压缩应用程序,例如7zip)。

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

我将首先创建一个类来保存您想要保存的所有状态信息,从而隔离问题。巧合的是,BinaryFormatter类将允许您轻松地将该类保存并加载到文件中。我不知道它的结果是否"足够不可读"——如果不是,就像Leon提到的那样应用Base64编码。

虽然您可以base64编码甚至完全加密您的配置数据(使用SHA1或MD5),正如已经建议的那样,我认为良好的做法是使用处理配置数据的框架类(ConfigurationSystem.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和VB中都有进一步的示例)。. NET和c#):

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

"DPAPIProtectedConfigurationProvider"answers"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的答案的另一个实现,并遵循微软文档

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

    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),这使得加密以这种方式破解的难度增加了一倍。

可以使用校验和来防止无意的字符串修改,正如这个答案所指出的那样。

然而,生成这样的校验和是很容易的,因为它们不是那么多广泛使用的算法。

因此,这并不能保护您免受有意修改的影响。为了防止这种情况,人们使用数字签名。这使得任何人都可以验证您的数据没有被篡改,但只有您(私有秘密的所有者)可以生成签名。

下面是c#中的一个例子。

然而,正如其他人指出的那样,您需要将私钥嵌入到二进制文件中的某个地方,并且(不那么)熟练的程序员将能够检索它,即使您混淆了。net dll或在单独的本机进程中进行。

这对大多数人来说已经足够了。

如果您真的关心安全性,那么您需要迁移到云上,并在您自己的机器上执行代码。