Шифрование, конфиг, спрятать ключ

Класс с настройками сериализуется, затем шифруется симметричным ключом и записывается в файл config.bin,сам ключ сериализуется и записывается в файл config.keyConfiguration.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?
11 ответов

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


Ключ внутри сборки легко найти ildasm или .NET Reflector, если это не помеха...Но есть такой класс ProtectedData , им можно зашифровать ключ, ключом машины или ключом пользователя с помощью Data Protection API.То есть машина своим ключом шифрует твой ключ, и вроде как расшифровать может только администратор компа и то надо знать как
byte[] protectKey = ProtectData.Protect(byteKey, null, DataProtectionScope.LocalMachine); // или CurrentUserbyte[] 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());        }    }}
 


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


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


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


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


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


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


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


altarvic, я с этими очевидными фактами и не спорил. Несколько постов назад Вы заявили, что
Но в .NET, по моему опыту (ткните если ошибаюсь) можно кодировать только публичным
. На это я ответил:
Думаю, можно просто поменять местами private и public ключи. На примере RSAParameters: задаем в D public-ключ (а не private) , а в Exponent - private (а не public).
, тем самым указав, что private и public ключи взаимозаменяемы, а, следовательно, указанной Вами проблемы в .NET нет.


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