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


Автор: tusha 20.11.2009, 18:27
добброго времени суток all
задался задачей написать класс для хранения настроек программы - в том числе юзернейм/пароль. пароль ес-но в зашифрованом виде - чтоб пользователь при редактировании конфига просто так прочитать его не мог. при загрузке программы - считывается конфиг и осуществляется подключение к MSSql Server.
вырезка кода:
Код

byte[] RSAEncrypt(byte[] DataToEncrypt, RSAParameters RSAKeyInfo, bool DoOAEPPadding)
        {
            try
            {
                RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
                RSA.ImportParameters(RSAKeyInfo);
                return RSA.Encrypt(DataToEncrypt, DoOAEPPadding);
            }
            catch (CryptographicException e)
            {
                return null;
            }

        }

        byte[] RSADecrypt(byte[] DataToDecrypt, RSAParameters RSAKeyInfo, bool DoOAEPPadding)
        {
            try
            {
                RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
                RSA.ImportParameters(RSAKeyInfo);
                return RSA.Decrypt(DataToDecrypt, DoOAEPPadding);
            }
            catch (CryptographicException e)
            {
                return null;
            }
        }

вот собственно сами данные которые собираемся шифровать:
Код

        [XmlElement(ElementName = "SQL_Database_username")]
        public string DBUser = string.Empty;        
        [XmlIgnore]
        UnicodeEncoding ByteConverter = new UnicodeEncoding();
        [XmlIgnore]
        CspParameters csp = new CspParameters();

        [XmlElement(ElementName = "SQL_User_password")]
        public byte[] password;
        [XmlIgnore]
        public string Password 
        { 
            get 
            {                
                csp.KeyContainerName = "MyContainer";
                RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(csp);
                byte[] DecryptedData = RSADecrypt(password, RSA.ExportParameters(true), false);
                return ByteConverter.GetString(DecryptedData);
            } 
            set 
            {                
                csp.KeyContainerName = "MyContainer";
                RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(csp);
                password = RSAEncrypt(ByteConverter.GetBytes(value), RSA.ExportParameters(true), false);
            } 
        }

шифрование/дешифрование на моей машине проходят наура, однако при попытке перенести конфиг и запустить на другой машине - при дешифровке вылетает эксепшн - чтото типа DecryptedData is null  и поэтому отваливается ByteConverter.GetString(DecryptedData);
возможно надо указать какието дополнительные ключи?
прошу совета

Автор: tol05 20.11.2009, 19:01
цепочка вызовов метода - очень короткая. Дебаггали?

если DecryptedData is null  => RSADecrypt() не сработал => или passord пустой (проверить серилизацию)  или RSAParameters   и т.д. 

Автор: tusha 20.11.2009, 19:15
массив byte[] password  при десереализации заполяется нормально , проверял при дебаге. параметры ключей не меняются (хм.. ключ для шифра/дешифра это же csp.KeyContainerName - я правильно понял??). 
Код

RSADecrypt(password, RSA.ExportParameters(true), false);

 возвращает null-овый массив байт
сереализацию делаю так:
Код

[XmlIgnore]
        static LibraSettings LS;        
        public static LibraSettings CreateInstance()
        {            
            if (LS == null) // if object isn't created
            {                
                XmlSerializer xs = new XmlSerializer(typeof(LibraSettings));
                FileStream fs;
                try
                {
                    fs = new FileStream(Application.StartupPath + "\\Config.xml", FileMode.Open);
                    LS = (LibraSettings)xs.Deserialize(fs);
                    fs.Close();
                }
                catch (IOException exc) // otherwise - create simple class
                {
                    MessageBox.Show("Файл конфигурации не найден (" + exc.Message + ", " + exc.Source + ")");
                    LS = new LibraSettings();
                }
                catch (Exception exc) // otherwise - create simple class
                {
                    MessageBox.Show("Произошла ошибка при чтении настроек программы (" + exc.Message + ", " + exc.Source + ")");
                    LS = new LibraSettings();
                }
            }
            return LS;
        }


public void SaveSettings()
        {
            XmlSerializer xs = new XmlSerializer(typeof(LibraSettings));
            FileStream fs = new FileStream(Application.StartupPath + "\\Config.xml", FileMode.Create);
            xs.Serialize(fs, LS);
            fs.Close();
        }


Автор: tol05 20.11.2009, 22:34
У меня все работает. На двух машинах. С разными культурами и операционными системами.

Если, хотите, присылайте архив через личное сообщение (PM). Посмотрю.

Конфиденциальность гарантирую ))

Кстати, username & connection strings можно заменить перед отправкой. Они все равно через декриптор не проходят.. 

Автор: tusha 20.11.2009, 23:26
видать уже поздно - не нашел как в ЛС прикрепить файл  smile 
выкладываю тут
класс+xml

Добавлено через 1 минуту и 23 секунды
блин, не прикрепилось)

Добавлено через 5 минут и 31 секунду
пароль кстати temp123

Автор: tusha 21.11.2009, 00:10
хм, только что прочитал что использование CspParameters походу делает алгоритм аппаратно/софтвенно зависимым) - что мне впринципе не надо) буду завтра ковырять

Автор: tol05 21.11.2009, 12:57
Думаю не в этом причина. Давно не занимался криптографией (да и опыта собственно большого не было))  ). Не обратил внимание на то, что алгоритм то - Ассиметричный
Т.е. - открытый и закрытый ключ. Вы - издатель. Я - клиент. Я не могу прочитать Вашу информацию без ключа.

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

Т.о. нужно как-то сохранить ключи и передать их клиенту. Наверное имеет смысл использовать sn.exe Но для нашего случая, для простоты, я просто конвертирую ключи в XML и серилизую их в тот же XML, где и данные.

В свойствах LibraSettings добавьте
Код

#region SecurityKey

public string Key;

#endregion


Для расшифровки клиенту нужны только ключи, испортированные из xml-строки.
Было сложно переключаться между свойством Password и методами RSAEncrypt\RSADecrypt поэтому я объединил их со свойством. 
Код

[XmlIgnore]
        public string Password
        {
            get
            {
                RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
                
                byte[] result = null;
                try
                {
                    RSA.FromXmlString(Key);
                    result = RSA.Decrypt(password, false);
                }
                catch (CryptographicException exc)
                {
                    MessageBox.Show("Произошла ошибка при дешифрации данных (" + exc.Message + ", " + exc.Source + ")");
                }

                return ByteConverter.GetString(result);
            }
            set
            {
                CspParameters csp = new CspParameters();
                csp.KeyContainerName = "MyKeyContainer";// в принципе - это не нужно для распределенной работы

                RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(csp);

                Key = RSA.ToXmlString(true);

                try
                {
                    password = RSA.Encrypt(ByteConverter.GetBytes(value), false);
                }
                catch (CryptographicException exc)
                {
                    MessageBox.Show("Произошла ошибка при шифрации данных (" + exc.Message + ", " + exc.Source + ")");
                    
                }
            }
        }
Попробуйте прочитать пароль из файла, который я приаттачил. 
Key = RSA.ToXmlString(true); - я экспортирую оба ключа (и открытый и закрытый). Если наш вариант сработает, поставтьте параметр false - клиенту нужно передавать только открытый ключ. Ну и, конечно, ключ не вместе с данными нужно будет передавать.. Например, отдельный файлом, в процессе инсталляции клиентского модуля.

Автор: tusha 21.11.2009, 13:57
 smile  temp321_123) спасибо за советы) 
однако мне так думается , ключ надо будет хранить постоянно - ведь я им буду пользоваться при каждой загрузке программы для расшифровки пароля.  ес-но пароль будет меняться - когда пользователь захочет его изменить. и я так понимаю этот же ключ будет использоваться при кодировании нового пароля. 
PS: против лома нет приема, данный вариант секьюрности мне впинципе подходит- когда подключится к mssql нельзя будет простым копипастом) 

Автор: tol05 21.11.2009, 15:31
Цитата(tusha @  21.11.2009,  12:57 Найти цитируемый пост)
temp321_123
exactly )))

ну и отлично. в конце концов - придумать где хранить ключ - это не big deal

кстати, может быть стоит подумать над симметричным шифрованием? Тогда проблем с ключами будет меньше


Автор: jonie 21.11.2009, 20:24
Цитата

чтоб пользователь при редактировании конфига просто так прочитать его не мог. при загрузке программы - считывается конфиг и осуществляется подключение к MSSql Server.
однако для этих целей уже ЕСТЬ готовая настройка конфига. Гуглить про DPAPI, вводную читать тут:
http://weblogs.asp.net/jgalloway/archive/2008/04/13/encrypting-passwords-in-a-net-app-config-file.aspx

Автор: tusha 21.11.2009, 22:15
я давно знал что все велосипеды уже 100 раз изобретены до меня) 
но я чтото приобрел+ возможно данная ветка комуто поможет)

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