Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > шифрование, конфиг, спрятать ключ


Автор: namespace 21.3.2009, 00:19
Класс с настройками сериализуется, затем шифруется симметричным ключом и записывается в файл config.bin,
сам ключ сериализуется и записывается в файл config.key
Configuration.dll :
Код

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.Data.SqlClient;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

namespace Configuration
{
    [Serializable]
    public class Config
    {
        public string server;
        public string database;
        public string user;
        public string password;
    }

    [Serializable]
    public class ConfigKey
    {
        public byte[] iV;
        public byte[] key;

        public ConfigKey()
        {
            AesManaged aesManaged = new AesManaged();
            this.iV = aesManaged.IV;
            this.key = aesManaged.Key;
        }
    }

    public static class ConfigWorker
    {
        private static Config config;
        private static ConfigKey configKey;

        private const string configFileName = "config.bin";
        private const string configKeyFileName = "config.key";

        public static string GetConnectionString()
        {
            SqlConnectionStringBuilder csb = new SqlConnectionStringBuilder();
            csb.DataSource = config.server;
            csb.UserID = config.user;
            csb.Password = config.password;
            csb.InitialCatalog = config.database;
            return csb.ConnectionString;
        }

        public static Config GetConfig()
        {
            return config;
        }

        public static void SaveConfig(Config config)
        {
            BinaryFormatter binaryFormatter = new BinaryFormatter();
            FileStream fileStreamConfig = new FileStream(configFileName, FileMode.Create);
            FileStream fileStreamConfigKey = new FileStream(configKeyFileName, FileMode.Create);

            configKey = new ConfigKey();

            AesManaged aesManaged = new AesManaged();
            ICryptoTransform encryptor = aesManaged.CreateEncryptor(configKey.key, configKey.iV);
            CryptoStream cryptoStream = new CryptoStream(fileStreamConfig, encryptor, CryptoStreamMode.Write);
            try
            {

                binaryFormatter.Serialize(cryptoStream, config);
                binaryFormatter.Serialize(fileStreamConfigKey, configKey);

            }
            finally
            {
                cryptoStream.Close();
                fileStreamConfig.Close();
                fileStreamConfigKey.Close();
            }
        }

        public static void LoadConfig()
        {
            BinaryFormatter binaryFormatter = new BinaryFormatter();
            FileStream fileStreamConfig = new FileStream(configFileName, FileMode.Open, FileAccess.Read);
            FileStream fileStreamConfigKey = new FileStream(configKeyFileName, FileMode.Open, FileAccess.Read);

            try
            {
                configKey = (ConfigKey)binaryFormatter.Deserialize(fileStreamConfigKey);
            }
            finally
            {
                fileStreamConfigKey.Close();
            }

            AesManaged aesManaged = new AesManaged();
            ICryptoTransform decryptor = aesManaged.CreateDecryptor(configKey.key, configKey.iV);
            CryptoStream cryptoStream = new CryptoStream(fileStreamConfig, decryptor, CryptoStreamMode.Read);

            try
            {
                config = (Config)binaryFormatter.Deserialize(cryptoStream);
            }
            finally
            {
                cryptoStream.Close();
                fileStreamConfig.Close();
            }
        }
    }
}

config.bin используется несколькими экзешниками, а вариант когда ключ шифрования config.key валяется на диске меня не устраивает,
вот я и думаю а нельзя ли его не сериализовывать в config.key как сейчас, а сделать так чтобы он находился внутри этой сборки Configuration.dll?

Автор: jonie 22.3.2009, 23:24
это не защита получится. Ассиметричное шифрование не пойдет?
для защиты строк соединения у мелкофоста есть спец хрень для config файлов, она зашифрует RSA сама, прозрачно для приложения ...

Автор: SKrivosein 23.3.2009, 00:48
Ключ внутри сборки легко найти ildasm или .NET Reflector, если это не помеха...
Но есть такой класс ProtectedData , им можно зашифровать ключ, ключом машины или ключом пользователя с помощью Data Protection API.
То есть машина своим ключом шифрует твой ключ, и вроде как расшифровать может только администратор компа и то надо знать как
Код

byte[] protectKey = ProtectData.Protect(byteKey, null, DataProtectionScope.LocalMachine); // или CurrentUser
byte[] Key = ProtectedData.Unprotect(protectKey, null, DataProtectionScope.LocalMachine);

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

using System;
using System.Security.Cryptography;
using System.IO;
using System.Text;

namespace Crypto
{
    public static class CryptoClass
    {
        private static bool _protectKey;
        private static string _algorithmName;

        public static string AlgorithmName
        {
            get { return _algorithmName; }
            set { _algorithmName = value; }
        }

        public static bool ProtectKey
        {
            get { return _protectKey; }
            set { _protectKey = value; }
        }

        public static void GenerateKey(string reservedFile, string protectedFile)
        {
            SymmetricAlgorithm Algorithm = SymmetricAlgorithm.Create(AlgorithmName);
            Algorithm.GenerateKey();
            byte[] Key = Algorithm.Key;

            using (FileStream safe_fs = new FileStream(reservedFile, FileMode.Create))
            {
                safe_fs.Write(Key, 0, Key.Length);
            }

            if (ProtectKey)
            {
                Key = ProtectedData.Protect(Key, null, DataProtectionScope.LocalMachine);
            }
            using (FileStream fs = new FileStream(protectedFile, FileMode.Create))
            {
                fs.Write(Key, 0, Key.Length);
            }
        }

        public static void ReadKey(SymmetricAlgorithm algorithm, string protectedFile)
        {
            byte[] Key;

            using (FileStream fs = new FileStream(protectedFile FileMode.Open))
            {
                Key = new byte[fs.Length];
                fs.Read(Key, 0, (int)fs.Length);
            }
            if (ProtectKey)
                algorithm.Key = ProtectedData.Unprotect(Key, null, DataProtectionScope.LocalMachine);
            else
                algorithm.Key = Key;
        }

        public static byte[] EncryptData(string data, string protectedFile)
        {
            byte[] ClearData = Encoding.UTF8.GetBytes(data);
            SymmetricAlgorithm Algorithm = SymmetricAlgorithm.Create(AlgorithmName);

            ReadKey(Algorithm,protectedFile);

            MemoryStream Target = new MemoryStream();
            Algorithm.GenerateIV();
            Target.Write(Algorithm.IV, 0, Algorithm.IV.Length);

            CryptoStream cs = new CryptoStream(Target, Algorithm.CreateEncryptor(), CryptoStreamMode.Write);
            cs.Write(ClearData, 0, ClearData.Length);
            cs.FlushFinalBlock();

            return Target.ToArray();
        }

        public static string DecryptData(byte[] data, string protectedFile)
        {
            SymmetricAlgorithm Algorithm = SymmetricAlgorithm.Create(AlgorithmName);

            ReadKey(Algorithm, protectedFile);

            MemoryStream Target = new MemoryStream();
            int ReadPos = 0;
            byte[] IV = new byte[Algorithm.IV.Length];
            Array.Copy(data, IV, IV.Length);
            Algorithm.IV = IV;
            ReadPos += Algorithm.IV.Length;

            CryptoStream cs = new CryptoStream(Target, Algorithm.CreateDecryptor(), CryptoStreamMode.Write);
            cs.Write(data, ReadPos, data.Length - ReadPos);
            cs.FlushFinalBlock();

            return Encoding.UTF8.GetString(Target.ToArray());
        }
    }
}
 

Автор: namespace 23.3.2009, 17:39
да вот дело в том что предполагается что прога будет лежать в сетевой шаре, сети организации. Data Protection - тут кто зашифровал тот и расшифрует, в RSA есть возможность сделать так чтобы расшифровать могли несколько компов, но тогда на компах надо будет импортировать ключ в хранилище.
вот и думаю шифрование то, в принципе, нужно то только для того чтоб сотрудники пароль от сервака не знали, с одной стороны при текущем варианте, надо дешифровать и десереализовать, IL код полюбому смотреть придется. может так и оставить...

P.S. кстати, по поводу ассиметричных алгоритмов, хочу сделать защиту на программу, так вот бывает такое что публичным ключом можно только расшифровать, а зашифровать скрытым, т.е. грубо говоря лицензионный файл (с датой окончания, названием организации), в программе зашит ключ для расшифровки, и соответственно только я могу генерировать лицензионные файлы, смотрел примеры мсдн так там публичный ключ используется для зашифровки, а скрытый для расшифровки?

Автор: arilou 23.3.2009, 18:53
Цитата(namespace @  23.3.2009,  17:39 Найти цитируемый пост)
P.S. кстати, по поводу ассиметричных алгоритмов, хочу сделать защиту на программу, так вот бывает такое что публичным ключом можно только расшифровать, а зашифровать скрытым, т.е. грубо говоря лицензионный файл (с датой окончания, названием организации), в программе зашит ключ для расшифровки, и соответственно только я могу генерировать лицензионные файлы, смотрел примеры мсдн так там публичный ключ используется для зашифровки, а скрытый для расшифровки?


Это правильный путь. 


Цитата(namespace @  23.3.2009,  17:39 Найти цитируемый пост)
да вот дело в том что предполагается что прога будет лежать в сетевой шаре, сети организации. Data Protection - тут кто зашифровал тот и расшифрует, в RSA есть возможность сделать так чтобы расшифровать могли несколько компов, но тогда на компах надо будет импортировать ключ в хранилище.
вот и думаю шифрование то, в принципе, нужно то только для того чтоб сотрудники пароль от сервака не знали, с одной стороны при текущем варианте, надо дешифровать и десереализовать, IL код полюбому смотреть придется. может так и оставить...

Каждая защита имеет свою цену и стоимость взлома. Взвесь все за и против и реши, насколько серьзеная защита должна быть в твоей организации, и действуй.

Автор: altarvic 24.3.2009, 10:36
Цитата(namespace @  23.3.2009,  17:39 Найти цитируемый пост)
 смотрел примеры мсдн так там публичный ключ используется для зашифровки, а скрытый для расшифровки?


Вообще в теории криптографии можно кодировать как приватным, так и публичным и расшифровывать соответственно противоположным ключом. Но в .NET, по моему опыту (ткните если ошибаюсь) можно кодировать только публичным (причем нужно это делать НЕ СВОИМ ключом, а того пользователя, кому посылается сообщение. Он его расшифровывает своим приватным ключом ). 

И это логично. Зачем шифровать приватным ключом, если расшифровать данные может любой используя публичный ключ? Ценность твоя лицензия не представляет никакой - имя, компания ... - это все не секретные данные. Имеет ценность то, что эту лицензию сгенерировал именно ты и никто другой. Для этого применяется цифровая подпись - это когда хеш от твоих данных подписывается твоим приватным ключом. Затем прога проверяет подпись: берет хеш данных и сверяет его с подписанным хешем (используя публичный ключ)

Надеюсь понятно ;)

Автор: Idsa 24.3.2009, 10:55
Цитата(altarvic @  24.3.2009,  14:36 Найти цитируемый пост)
Но в .NET, по моему опыту (ткните если ошибаюсь) можно кодировать только публичным

Думаю, можно просто поменять местами private и public ключи. На примере RSAParameters: задаем в D public-ключ (а не private) , а в Exponent - private (а не public).

Автор: altarvic 24.3.2009, 11:17
и что это нам дает? Смысл то не меняется. 
не важно как называются ключи. Если мы кодируем используя приватный ключ (т.е. не доступный другим), то расшифровать можно публичным (доступный всем) - следовательно зачем шифровать, если расшифровать может любой? при обмене секретными данными между Алисой и Бобом используют ДВА публичных ключа: Алиса шифрует данные публичным ключом Боба. Боб шифрует данные публичным ключом Алисы. Все тип топ - данные в секрете. В этом и есть смысл ассимитричного шифрования: когда для шифровки используют публичные ключи.

Автор: Idsa 24.3.2009, 12:24
altarvic, Вы сами себе противоречите.
Раз:
Цитата(altarvic @  24.3.2009,  15:17 Найти цитируемый пост)
Если мы кодируем используя приватный ключ (т.е. не доступный другим), то расшифровать можно публичным (доступный всем) - следовательно зачем шифровать, если расшифровать может любой?

Два:
Цитата(altarvic @  24.3.2009,  14:36 Найти цитируемый пост)
Зачем шифровать приватным ключом, если расшифровать данные может любой используя публичный ключ? Ценность твоя лицензия не представляет никакой - имя, компания ... - это все не секретные данные. Имеет ценность то, что эту лицензию сгенерировал именно ты и никто другой.

Автор: altarvic 24.3.2009, 14:32
не вижу противоречия.

Если вы имеете в  виду цифровую подпись, то она не обеспечивает никакой секретности - 
она гарантирует что: 
1) данные не были изменены
2) данные были созданы именно Вами

Вот и все.

Автор: Idsa 24.3.2009, 15:04
altarvic, я с этими очевидными фактами и не спорил. Несколько постов назад Вы заявили, что
Цитата(altarvic @  24.3.2009,  14:36 Найти цитируемый пост)
Но в .NET, по моему опыту (ткните если ошибаюсь) можно кодировать только публичным

. На это я ответил:
Цитата(Idsa @  24.3.2009,  14:55 Найти цитируемый пост)
Думаю, можно просто поменять местами private и public ключи. На примере RSAParameters: задаем в D public-ключ (а не private) , а в Exponent - private (а не public).

, тем самым указав, что private и public ключи взаимозаменяемы, а, следовательно, указанной Вами проблемы в .NET нет.

Автор: namespace 24.3.2009, 16:57
altarvic: да тут ценность шифрования не в том что другие не расшифруют, как раз и расшифруют, а вот создать такой же файл но с другими данными не смогут.

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

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)