class Crypt
{
public string keyAES;
public string keyRSA;
public Crypt()
{
keyRSA = null;
keyAES = null;
}
public void CreateRSAKey()
{
keyRSA = new RSACryptoServiceProvider().ToXmlString(true);
}
public void SetRSAKey(string keyRSA)
{
this.keyRSA = keyRSA;
}
public void CreateAESKey()
{
string filt_l = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
Random R = new Random();
string newpass = null;
for (int i = 0; i < 3; i++)
{
int n = R.Next(filt_l.Length);
newpass += filt_l[n].ToString();
}
keyAES = newpass;
}
public void SetAESKey(string keyAES)
{
this.keyAES = RSADecrypt(keyAES);
}
public byte[] Encrypt(byte[] data)
{
SymmetricAlgorithm sa = Rijndael.Create();
ICryptoTransform ct = sa.CreateEncryptor(
(new PasswordDeriveBytes(keyAES, null)).GetBytes(16),
new byte[16]);
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, ct, CryptoStreamMode.Write);
cs.Write(data, 0, data.Length);
cs.FlushFinalBlock();
return ms.ToArray();
}
public string Encrypt(string data)
{
return Convert.ToBase64String(Encrypt(Encoding.UTF8.GetBytes(data)));
}
public byte[] Decrypt(byte[] data)
{
BinaryReader br = new BinaryReader(InternalDecrypt(data, keyAES));
return br.ReadBytes((int)br.BaseStream.Length);
}
public string Decrypt(string data)
{
CryptoStream cs = InternalDecrypt(Convert.FromBase64String(data), keyAES);
StreamReader sr = new StreamReader(cs);
return sr.ReadToEnd();
}
private CryptoStream InternalDecrypt(byte[] data, string keyAES)
{
SymmetricAlgorithm sa = Rijndael.Create();
ICryptoTransform ct = sa.CreateDecryptor(
(new PasswordDeriveBytes(keyAES, null)).GetBytes(16),
new byte[16]);
MemoryStream ms = new MemoryStream(data);
return new CryptoStream(ms, ct, CryptoStreamMode.Read);
}
public string RSAEncrypt(string DataToEncrypt)
{
return Encoding.UTF8.GetString(RSAEncrypt(Encoding.UTF8.GetBytes(DataToEncrypt)));
}
public byte[] RSAEncrypt(byte[] DataToEncrypt)
{
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
RSA.FromXmlString(keyRSA);
return RSA.Encrypt(DataToEncrypt, true);
}
public string RSADecrypt(string DataToDecrypt)
{
return Encoding.UTF8.GetString(RSADecrypt(Encoding.UTF8.GetBytes(DataToDecrypt)));
}
public byte[] RSADecrypt(byte[] DataToDecrypt)
{
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
RSA.FromXmlString(keyRSA);
return RSA.Decrypt(DataToDecrypt, true);
}
}
AES & RSA, C#
Есть некое клиент-серверное приложение(opensource). В некоторых местах протокола данные шифруются. Раньше там была "защита от дурочка", состряпанная "для галочки" за несколько часов. У клиента и сервера был один постоянный AES ключ. Дошли руки разобраться с технологиями шифрования. Я пришел к выводу, что при установке соединения клиент должен отправлять серверу RSA ключ, которым сервер шифрует AES ключ и отправляет обратно. Все остальные данные шифруются AES (поправьте, пожалуйста, если я не прав).
На основе msdn и примеров в интернете был состряпан следующий класс:
Код:
Я использую следующий код для тестирования:
Код:
Crypt _Client = new Crypt(); //экземпляр в клиенте
Crypt _Server = new Crypt(); //экземпляр в сервере
_Client.CreateRSAKey(); //перед подключением клиент генерирует ключ rsa
_Server.SetRSAKey(_Client.keyRSA); //сервер принимает ключ rsa
_Server.CreateAESKey(); //сервер генерирует ключ aes
_Client.SetAESKey(_Server.RSAEncrypt(_Server.keyAES)); //и посылает его клиенту, зашифрованно в rsa
string tmp = Environment.OSVersion.ToString();
Console.WriteLine("Исходная строка:\r\n" + tmp);
Console.WriteLine(tmp.Length);
tmp = _Client.Encrypt(tmp);
Console.WriteLine("Зашифрованная строка:\r\n" + tmp);
Console.WriteLine(tmp.Length);
tmp = _Server.Decrypt(tmp);
Console.WriteLine("Расшифрованная строка:\r\n" + tmp);
Console.WriteLine(tmp.Length);
Crypt _Server = new Crypt(); //экземпляр в сервере
_Client.CreateRSAKey(); //перед подключением клиент генерирует ключ rsa
_Server.SetRSAKey(_Client.keyRSA); //сервер принимает ключ rsa
_Server.CreateAESKey(); //сервер генерирует ключ aes
_Client.SetAESKey(_Server.RSAEncrypt(_Server.keyAES)); //и посылает его клиенту, зашифрованно в rsa
string tmp = Environment.OSVersion.ToString();
Console.WriteLine("Исходная строка:\r\n" + tmp);
Console.WriteLine(tmp.Length);
tmp = _Client.Encrypt(tmp);
Console.WriteLine("Зашифрованная строка:\r\n" + tmp);
Console.WriteLine(tmp.Length);
tmp = _Server.Decrypt(tmp);
Console.WriteLine("Расшифрованная строка:\r\n" + tmp);
Console.WriteLine(tmp.Length);
Во первых, верен ли общий алгоритм?
И во вторых, вопрос более конкретный. При расшифровке ключа AES в RSADecrypt(byte[] DataToDecrypt) возникает исключение, которое говорит, что я пытаюсь расшифровать более 128 байт информации. Ну возможно...
Для тестирования RSA использую другой код, где без всякого обмена ключами RSAEncrypt(string DataToEncrypt) шифрует букву "S", а RSADecrypt(byte[] DataToDecrypt) все равно генерирует то-же самое исключение. Смутило меня UTF-8 размером представления символов, попробовал ASCII. Теперь стало ругаться на OAEP (опять-же при расшифровке). Где грабли?
Всем заранее спасибо за помощь.
Теперь имеем такой код (пока не суюсь в AES, разберусь с RSA до конца):
Код:
class Crypt
{
public string keyRSAPublic;
public string keyRSAPrivate;
public string keyRSARemote;
public Crypt()
{
keyRSAPublic = null;
keyRSAPrivate = null;
keyRSARemote = null;
}
public void CreateRSAKey()
{
keyRSAPrivate = new RSACryptoServiceProvider().ToXmlString(true);
keyRSAPublic = new RSACryptoServiceProvider().ToXmlString(false);
}
public void SetRSAKey(string keyRSA)
{
keyRSARemote = keyRSA;
}
public string RSAEncrypt(string DataToEncrypt)
{
return Encoding.GetEncoding(28591).GetString(RSAEncrypt(Encoding.GetEncoding(28591).GetBytes(DataToEncrypt)));
}
public byte[] RSAEncrypt(byte[] DataToEncrypt)
{
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
RSA.FromXmlString(keyRSRAemote);
return RSA.Encrypt(DataToEncrypt, false);
}
public string RSADecrypt(string DataToDecrypt)
{
return Encoding.GetEncoding(28591).GetString(RSADecrypt(Encoding.GetEncoding(28591).GetBytes(DataToDecrypt)));
}
public byte[] RSADecrypt(byte[] DataToDecrypt)
{
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
RSA.FromXmlString(keyRSAPrivate);
return RSA.Decrypt(DataToDecrypt, false);
}
}
{
public string keyRSAPublic;
public string keyRSAPrivate;
public string keyRSARemote;
public Crypt()
{
keyRSAPublic = null;
keyRSAPrivate = null;
keyRSARemote = null;
}
public void CreateRSAKey()
{
keyRSAPrivate = new RSACryptoServiceProvider().ToXmlString(true);
keyRSAPublic = new RSACryptoServiceProvider().ToXmlString(false);
}
public void SetRSAKey(string keyRSA)
{
keyRSARemote = keyRSA;
}
public string RSAEncrypt(string DataToEncrypt)
{
return Encoding.GetEncoding(28591).GetString(RSAEncrypt(Encoding.GetEncoding(28591).GetBytes(DataToEncrypt)));
}
public byte[] RSAEncrypt(byte[] DataToEncrypt)
{
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
RSA.FromXmlString(keyRSRAemote);
return RSA.Encrypt(DataToEncrypt, false);
}
public string RSADecrypt(string DataToDecrypt)
{
return Encoding.GetEncoding(28591).GetString(RSADecrypt(Encoding.GetEncoding(28591).GetBytes(DataToDecrypt)));
}
public byte[] RSADecrypt(byte[] DataToDecrypt)
{
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
RSA.FromXmlString(keyRSAPrivate);
return RSA.Decrypt(DataToDecrypt, false);
}
}
Для тестирования используется следующий код:
Код:
static void Main()
{
Crypt _Client = new Crypt();
Crypt _Server = new Crypt();
_Client.CreateRSAKey();
_Server.CreateRSAKey();
Console.WriteLine("Клиент и сервер создают ключи RSA");
_Client.SetRSAKey(_Server.keyRSAPublic);
_Server.SetRSAKey(_Client.keyRSAPublic);
Console.WriteLine("Клиент и сервер обмениваются публичными ключами RSA");
string tmp = Environment.OSVersion.ToString();
Console.WriteLine("Исходная строка:\r\n" + tmp);
Console.WriteLine(tmp.Length);
tmp = _Client.RSAEncrypt(tmp);
Console.WriteLine("Зашифрованная строка:\r\n" + tmp);
Console.WriteLine(tmp.Length);
tmp = _Server.RSADecrypt(tmp);
Console.WriteLine("Расшифрованная строка:\r\n" + tmp);
Console.WriteLine(tmp.Length);
Console.ReadKey();
}
{
Crypt _Client = new Crypt();
Crypt _Server = new Crypt();
_Client.CreateRSAKey();
_Server.CreateRSAKey();
Console.WriteLine("Клиент и сервер создают ключи RSA");
_Client.SetRSAKey(_Server.keyRSAPublic);
_Server.SetRSAKey(_Client.keyRSAPublic);
Console.WriteLine("Клиент и сервер обмениваются публичными ключами RSA");
string tmp = Environment.OSVersion.ToString();
Console.WriteLine("Исходная строка:\r\n" + tmp);
Console.WriteLine(tmp.Length);
tmp = _Client.RSAEncrypt(tmp);
Console.WriteLine("Зашифрованная строка:\r\n" + tmp);
Console.WriteLine(tmp.Length);
tmp = _Server.RSADecrypt(tmp);
Console.WriteLine("Расшифрованная строка:\r\n" + tmp);
Console.WriteLine(tmp.Length);
Console.ReadKey();
}
Тут мы создаем два экземпляра класса Crypt, для каждого создаем наборы ключей (публичный, приватный, и публичный удаленный). Публичный удаленный - это публичный ключ противоположного экземпляра класса Crypt. Ну и далее первый экземпляр шифрует строку публичным ключом второго экземпляра, а второй пытается расшифровать данные своим приватным ключом. И на этом возникает исключение, мол плохие данные. Если в этом же коде использовать один экземпляр класса Crypt, шифровать данные его публичным ключом, а расшифровывать приватным - все работает. Что я упустил?
Всем заранее спасибо за помощь.
В код не вникал, идея в принципе разумная..... Но. Почему бы не использовать SSL?
Цитата: hardcase
В код не вникал, идея в принципе разумная..... Но. Почему бы не использовать SSL?
А в чем плюсы у SSL перед RSA+AES? Кроме того, SSL вроде платный. Об OpenSSL вообще практически ничего не слышал. Да и msdn молчит как партизан об обоих.
Код:
public class Crypt
{
private byte[] keyRSAPublic;
private byte[] keyRSAPrivate;
private byte[] keyRSARemote;
private string keyAES;
public Crypt()
{
CreateRSAKey();
CreateAESKey();
}
private void CreateRSAKey()
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(2048);
keyRSAPrivate = rsa.ExportCspBlob(true);
keyRSAPublic = rsa.ExportCspBlob(false);
}
public void SetRSAKey(byte[] keyRSA)
{
keyRSARemote = keyRSA;
}
public byte[] GetRSAKey()
{
return keyRSAPublic;
}
public string RSAEncrypt(string DataToEncrypt)
{
return Encoding.GetEncoding(28591).GetString(RSAEncrypt(Encoding.GetEncoding(28591).GetBytes(DataToEncrypt)));
}
public byte[] RSAEncrypt(byte[] DataToEncrypt)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(2048);
rsa.ImportCspBlob(keyRSARemote);
return rsa.Encrypt(DataToEncrypt, false);
}
public string RSADecrypt(string DataToDecrypt)
{
return Encoding.GetEncoding(28591).GetString(RSADecrypt(Encoding.GetEncoding(28591).GetBytes(DataToDecrypt)));
}
public byte[] RSADecrypt(byte[] DataToDecrypt)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(2048);
rsa.ImportCspBlob(keyRSAPrivate);
return rsa.Decrypt(DataToDecrypt, false);
}
private void CreateAESKey()
{
string filt_l = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
Random R = new Random();
string newpass = null;
for (int i = 0; i < 128; i++)
{
int n = R.Next(filt_l.Length);
newpass += filt_l[n].ToString();
}
keyAES = newpass;
}
public string GetAESKey()
{
return RSAEncrypt(keyAES);
}
public void SetAESKey(string keyAES)
{
this.keyAES = RSADecrypt(keyAES);
}
public byte[] AESEncrypt(byte[] data)
{
SymmetricAlgorithm sa = Rijndael.Create();
ICryptoTransform ct = sa.CreateEncryptor(
(new PasswordDeriveBytes(keyAES, null)).GetBytes(16),
new byte[16]);
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, ct, CryptoStreamMode.Write);
cs.Write(data, 0, data.Length);
cs.FlushFinalBlock();
return ms.ToArray();
}
public string AESEncrypt(string data)
{
return Convert.ToBase64String(AESEncrypt(Encoding.UTF8.GetBytes(data)));
}
public byte[] AESDecrypt(byte[] data)
{
BinaryReader br = new BinaryReader(InternalDecrypt(data, keyAES));
return br.ReadBytes((int)br.BaseStream.Length);
}
public string AESDecrypt(string data)
{
CryptoStream cs = InternalDecrypt(Convert.FromBase64String(data), keyAES);
StreamReader sr = new StreamReader(cs);
return sr.ReadToEnd();
}
private CryptoStream InternalDecrypt(byte[] data, string keyAES)
{
SymmetricAlgorithm sa = Rijndael.Create();
ICryptoTransform ct = sa.CreateDecryptor(
(new PasswordDeriveBytes(keyAES, null)).GetBytes(16),
new byte[16]);
MemoryStream ms = new MemoryStream(data);
return new CryptoStream(ms, ct, CryptoStreamMode.Read);
}
}
{
private byte[] keyRSAPublic;
private byte[] keyRSAPrivate;
private byte[] keyRSARemote;
private string keyAES;
public Crypt()
{
CreateRSAKey();
CreateAESKey();
}
private void CreateRSAKey()
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(2048);
keyRSAPrivate = rsa.ExportCspBlob(true);
keyRSAPublic = rsa.ExportCspBlob(false);
}
public void SetRSAKey(byte[] keyRSA)
{
keyRSARemote = keyRSA;
}
public byte[] GetRSAKey()
{
return keyRSAPublic;
}
public string RSAEncrypt(string DataToEncrypt)
{
return Encoding.GetEncoding(28591).GetString(RSAEncrypt(Encoding.GetEncoding(28591).GetBytes(DataToEncrypt)));
}
public byte[] RSAEncrypt(byte[] DataToEncrypt)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(2048);
rsa.ImportCspBlob(keyRSARemote);
return rsa.Encrypt(DataToEncrypt, false);
}
public string RSADecrypt(string DataToDecrypt)
{
return Encoding.GetEncoding(28591).GetString(RSADecrypt(Encoding.GetEncoding(28591).GetBytes(DataToDecrypt)));
}
public byte[] RSADecrypt(byte[] DataToDecrypt)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(2048);
rsa.ImportCspBlob(keyRSAPrivate);
return rsa.Decrypt(DataToDecrypt, false);
}
private void CreateAESKey()
{
string filt_l = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
Random R = new Random();
string newpass = null;
for (int i = 0; i < 128; i++)
{
int n = R.Next(filt_l.Length);
newpass += filt_l[n].ToString();
}
keyAES = newpass;
}
public string GetAESKey()
{
return RSAEncrypt(keyAES);
}
public void SetAESKey(string keyAES)
{
this.keyAES = RSADecrypt(keyAES);
}
public byte[] AESEncrypt(byte[] data)
{
SymmetricAlgorithm sa = Rijndael.Create();
ICryptoTransform ct = sa.CreateEncryptor(
(new PasswordDeriveBytes(keyAES, null)).GetBytes(16),
new byte[16]);
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, ct, CryptoStreamMode.Write);
cs.Write(data, 0, data.Length);
cs.FlushFinalBlock();
return ms.ToArray();
}
public string AESEncrypt(string data)
{
return Convert.ToBase64String(AESEncrypt(Encoding.UTF8.GetBytes(data)));
}
public byte[] AESDecrypt(byte[] data)
{
BinaryReader br = new BinaryReader(InternalDecrypt(data, keyAES));
return br.ReadBytes((int)br.BaseStream.Length);
}
public string AESDecrypt(string data)
{
CryptoStream cs = InternalDecrypt(Convert.FromBase64String(data), keyAES);
StreamReader sr = new StreamReader(cs);
return sr.ReadToEnd();
}
private CryptoStream InternalDecrypt(byte[] data, string keyAES)
{
SymmetricAlgorithm sa = Rijndael.Create();
ICryptoTransform ct = sa.CreateDecryptor(
(new PasswordDeriveBytes(keyAES, null)).GetBytes(16),
new byte[16]);
MemoryStream ms = new MemoryStream(data);
return new CryptoStream(ms, ct, CryptoStreamMode.Read);
}
}
Цитата: LLIbIcpEP
А в чем плюсы у SSL перед RSA+AES? Кроме того, SSL вроде платный.
Плюс в том, что SSL (secure sockets layer) уже реализован на уровне сетевых драйверов ОС, и использование RSA + AES в некотором смысле является изобретением велосипеда. С чего вы взяли, что SSL платный? Он настолько же платный как использование платформы .NET. :)