C # Зашифровать вывод текста - PullRequest
2 голосов
/ 22 августа 2011

Я создал несколько небольших программ, которые экспортируют данные в текстовый файл с помощью StreamWriter, а затем я считываю их обратно с помощью StreamReader. Это прекрасно работает и делает то, что мне нужно, но мне было интересно, есть ли способ, которым я мог бы сохранить эту информацию без возможности доступа или изменения ее пользователем намеренно или непреднамеренно. Примером чего-то, что у меня было бы в текстовом файле, было бы, если бы флажок был отмечен, когда вы устанавливаете флажок, он выводит «Ticked» в текстовый файл, когда программа повторно открывается, я знаю, в каком состоянии была форма, когда она был закрыт. Я, очевидно, не хочу продолжать использовать текстовые файлы. У кого-нибудь есть идеи о том, как я могу легко хранить эту информацию без возможности ее изменения пользователем? Большое спасибо.

Ответы [ 9 ]

7 голосов
/ 22 августа 2011

Самый простой способ - кодировать / декодировать этот текст в 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
2 голосов
/ 22 августа 2011

Вы должны позвонить ProtectedData.Protect, чтобы зашифровать данные с помощью ключа для каждого пользователя.

Обратите внимание, что опытному пользователю не составит труда расшифровать и изменить данные.
Все, что ваша программа делает на компьютере пользователя, также может быть сделано пользователем.

2 голосов
/ 22 августа 2011

Вы можете добавить контрольную сумму или хэш в файл - если содержимое файла не соответствует контрольной сумме, вы знаете, что оно было подделано.

Если важно, чтобы пользователи не могли прочитать содержимое файла, вы можете зашифровать его.

Я не верю, что вы можете создать файл, который не может быть подделан (опытный пользователь можетнапример, используйте редактор hex и измените его) - лучшее, что вы можете сделать, это обнаружить такое вмешательство.

1 голос
/ 27 октября 2015

Просто добавьте еще одну реализацию ответа Леона и следуйте Документы 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;
    }
}

Кстати, вот определение "соляной стоимости", которое я нашел в Google, чтобы выяснить, что это было.

Соль

Если злоумышленник не знает пароль и пытается угадать его с помощью грубой атаки, то каждый пароль, который он пытается использовать, должен быть проверен с каждым солт-значением. Таким образом, для однобитной соли (0 или 1) это делает шифрование вдвое сложнее, чем таким образом.

1 голос
/ 24 августа 2012

Попробуйте этот код для шифрования и дешифрования вашего текста! Это довольно легко и сильно, я думаю ...

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;
        }
    }
}
1 голос
/ 22 августа 2011

Хотя вы можете кодировать base64 или даже полностью шифровать данные конфигурации (с помощью SHA1 или MD5), как уже предлагалось, я думаю, что хорошей практикой будет работа с классами инфраструктуры, работающими с данными конфигурации (Configuration* 1003). * под System.Configuration пространством имен) и имеет встроенную возможность шифрования данных (с помощью метода ProtectSection класса ConfigurationSection).

Прежде всего вы должны объявить и инициализировать экземпляр:

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, указанной выше.

1 голос
/ 22 августа 2011

Если программа может получить доступ к информации, обычно это может сделать и пользователь. Однако вы можете предоставить данные, которые пользователь не сразу поймет.

Я бы начал с создания класса, который содержит всю информацию о состоянии, которую вы хотите сохранить, изолируя проблему. По совпадению, класс BinaryFormatter позволит вам легко сохранить и загрузить этот класс в / из файла. Я не знаю, являются ли его результаты «нечитаемыми» - если нет, примените кодировку Base64, как упоминал Леон.

1 голос
/ 22 августа 2011

Вы можете использовать Ionic zip library для архивирования этих текстовых файлов. При необходимости вы также можете использовать функции Ionic zip, такие как защита паролем и шифрование. И вы по-прежнему сможете открывать файл (с помощью таких приложений, как, например, 7zip) вручную, используя те же настройки, которые вы использовали для его создания.

0 голосов
/ 24 июля 2018

Предотвращение непреднамеренного изменения строки может быть выполнено с использованием контрольной суммы, как указано в этом ответе .

Однако такую ​​контрольную сумму довольно легко сгенерировать, так как их не так много, широко используемых алгоритмов .

Таким образом, это не защитит вас от преднамеренного изменения.

Чтобы предотвратить это, люди используют цифровые подписи . Это позволяет любому проверить, что ваши данные не были подделаны, но только вы (владелец личного секрета) можете сгенерировать подпись.

Здесь является примером в C #.

Однако, как отмечали другие, вам нужно встроить свой закрытый ключ в ваш двоичный файл, и (не очень) опытный программист сможет его получить, даже если вы запутываете свою .net dll или делаете это отдельный родной процесс.

Этого было бы достаточно для большинства проблем.

Если вы действительно обеспокоены безопасностью, то вам нужно перейти в облако и выполнить код на своей машине.

...