在C#中实现RSA

我目前正在尝试使用RSACrytoServiceProveider类实现一个类来处理我的应用程序实例之间的安全通信。 第一个问题:实现单个类来处理发送者/接收者角色或者我应该将角色分成单个类是一个好主意吗? 这是我到目前为止所做的:

using System; using System.Text; using System.Security.Cryptography; namespace Agnus.Cipher { public class RSA { private byte[] plaintextBytes; private byte[] ciphertextBytes; private RSACryptoServiceProvider rSAProviderThis; private RSACryptoServiceProvider rSAProviderOther; public string PublicKey { get { return rSAProviderThis.ToXmlString(false); } } public RSA() { rSAProviderThis = new RSACryptoServiceProvider { PersistKeyInCsp = true }; plaintextBytes = Encoding.Unicode.GetBytes(PublicKey); } public void InitializeRSAProviderOther(string parameters) { rSAProviderOther.FromXmlString(parameters); } public byte[] Encrypt() { return rSAProviderThis.Encrypt(plaintextBytes, true); } public byte[] Decrypt() { return rSAProviderThis.Decrypt(ciphertextBytes, true); } public byte[] Sign() { using (SHA1Managed SHA1 = new SHA1Managed()) { byte[] hash = SHA1.ComputeHash(ciphertextBytes); byte[] signature = rSAProviderThis.SignHash(hash, CryptoConfig.MapNameToOID("SHA1")); return signature; } } public void Verify() { throw new NotImplementedException(); } } } 

第二个问题:我如何发送和接收要输入课程的数据? 我是这个领域的绿色角,指针将不胜感激。

我会使encrypt / sign / decrypt / verify方法获取数据的参数,而不是为它们提供成员变量。 拥有密钥和提供者的成员变量似乎没问题。 基本上我希望多次使用相同的密钥,但不是相同的数据。

我也将它变为不可变 – 使所有变量只读,在构造函数中获取提供者所需的所有参数,而不是使用单独的初始化方法。

除此之外,似乎可以将function包装在更简单的API中,以满足您的需求,是的。

我做了一些调整,这是实现的样子:

 using System; using System.Security.Cryptography; namespace Agnus.Cipher { public class RSA : IDisposable { private RSACryptoServiceProvider rSAProviderThis; private RSACryptoServiceProvider rSAProviderOther = null; public string PublicKey { get { return rSAProviderThis.ToXmlString(false); } } public RSA() { rSAProviderThis = new RSACryptoServiceProvider { PersistKeyInCsp = true }; } public void InitializeRSAProviderOther(string parameters) { rSAProviderOther.FromXmlString(parameters); } public byte[] Encrypt(byte[] plaintextBytes) { return rSAProviderThis.Encrypt(plaintextBytes, true); } public string Decrypt(byte[] ciphertextBytes) { try { return Convert.ToBase64String( rSAProviderThis.Decrypt(ciphertextBytes, true)); } catch (CryptographicException ex) { Console.WriteLine("Unable to decrypt: " + ex.Message + " " + ex.StackTrace); } finally { this.Dispose(); } return string.Empty; } public string SignData(byte[] ciphertextBytes) { string signature = GenerateSignature(ciphertextBytes, rSAProviderThis); return signature; } private string GenerateSignature(byte[] ciphertextBytes, RSACryptoServiceProvider provider) { using (SHA1Managed SHA1 = new SHA1Managed()) { byte[] hash = SHA1.ComputeHash(ciphertextBytes); string signature = Convert.ToBase64String(provider.SignHash(hash, CryptoConfig.MapNameToOID("SHA1"))); return signature; } } public string VerifySignature(byte[] ciphertextBytes, string parameters, string signatureToVerify) { InitializeRSAProviderOther(parameters); string actualSignature = GenerateSignature(ciphertextBytes, rSAProviderOther); if (actualSignature.Equals(signatureToVerify)) { //verification successful string decryptedData = this.Decrypt(ciphertextBytes); return decryptedData; //decryptedData is a symmetric key } else { //verification unsuccessful //end session } return string.Empty; } #region IDisposable Members public void Dispose() { if (rSAProviderOther != null) { rSAProviderOther.Clear(); } rSAProviderThis.Clear(); GC.SuppressFinalize(this); } #endregion } } 

你们还没有说过如何建立沟通(我在想套接字)。 请赐教。

我不知道这段代码是否可以帮助你,我已经编写了这段代码,能够在不同的加密算法中使用私钥/公钥对进行加密和解密,而且没有数据加密长度问题,实际上是RSA实现。当你试图管理超过250个(或多或少,抱歉我不记得)数据字节时,NET会受到影响。

我只剪切和粘贴所需的方法,我也剪切了xml文档的原因不是英文,如果你发现这个有用让我知道,我可以发布所有来源。 我再说一遍,我没有测试过这个剪切和粘贴版本,但是我使用了这个类的完整版本并没有那么不同。

顺便说一句:它在VB中,但如果你只是潜伏在它,我认为这就足够了;)

 Namespace Crypto Public Class RSACry Shared Sub New() End Sub Public Enum Algorithms DES TDES RC2 RDAEL End Enum Public Shared Function Encrypt(ByVal xmlkeystring As String, ByVal typo As Algorithms, ByVal datatoencrypt As String) As String Dim rsaer As RSA = Crypto.RSACry.ReadKeyString(xmlkeystring) Dim result() As Byte = Crypto.RSACry.EncryptIt(rsaer, typo, datatoencrypt) Return System.Convert.ToBase64String(result) End Function Public Shared Function Decrypt(ByVal xmlkeystring As String, ByVal typo As Algorithms, ByVal datatodecrypt As String) As String Dim rsaer As RSA = Crypto.RSACry.ReadKeyString(xmlkeystring) Dim result() As Byte = Crypto.RSACry.DecryptIt(rsaer, typo, datatodecrypt) Return System.Text.Encoding.UTF8.GetString(result) End Function Friend Shared Function EncryptIt(ByRef rsaer As RSA, ByVal typo As Algorithms, ByVal datatoencrypt As String) As Byte() Dim result() As Byte = Nothing Try Dim plainbytes() As Byte = System.Text.Encoding.UTF8.GetBytes(datatoencrypt) Dim sa As SymmetricAlgorithm = SymmetricAlgorithm.Create(Crypto.RSACry.GetAlgorithmName(typo)) Dim ct As ICryptoTransform = sa.CreateEncryptor() Dim encrypt() As Byte = ct.TransformFinalBlock(plainbytes, 0, plainbytes.Length) Dim fmt As RSAPKCS1KeyExchangeFormatter = New RSAPKCS1KeyExchangeFormatter(rsaer) Dim keyex() As Byte = fmt.CreateKeyExchange(sa.Key) --return the key exchange, the IV (public) and encrypted data result = New Byte(keyex.Length + sa.IV.Length + encrypt.Length) {} Buffer.BlockCopy(keyex, 0, result, 0, keyex.Length) Buffer.BlockCopy(sa.IV, 0, result, keyex.Length, sa.IV.Length) Buffer.BlockCopy(encrypt, 0, result, keyex.Length + sa.IV.Length, encrypt.Length) Catch ex As Exception Throw New CryptographicException("Unable to crypt: " + ex.Message) End Try Return result End Function Friend Shared Function DecryptIt(ByRef rsaer As RSA, ByVal typo As Algorithms, ByVal datatodecrypt As String) As Byte() Dim result() As Byte = Nothing Try Dim encrbytes() As Byte = System.Convert.FromBase64String(datatodecrypt) Dim sa As SymmetricAlgorithm = SymmetricAlgorithm.Create(Crypto.RSACry.GetAlgorithmName(typo)) Dim keyex() As Byte = New Byte((rsaer.KeySize >> 3) - 1) {} Buffer.BlockCopy(encrbytes, 0, keyex, 0, keyex.Length) Dim def As RSAPKCS1KeyExchangeDeformatter = New RSAPKCS1KeyExchangeDeformatter(rsaer) Dim key() As Byte = def.DecryptKeyExchange(keyex) Dim iv() As Byte = New Byte((sa.IV.Length - 1)) {} Buffer.BlockCopy(encrbytes, keyex.Length, iv, 0, iv.Length) Dim ct As ICryptoTransform = sa.CreateDecryptor(key, iv) result = ct.TransformFinalBlock(encrbytes, keyex.Length + iv.Length, (encrbytes.Length - 1) - (keyex.Length + iv.Length)) Catch ex As Exception Throw New CryptographicException("Unable to decrypt: " + ex.Message) End Try Return result End Function Friend Shared Function GetAlgorithmName(ByVal typo As Algorithms) As String Dim algtype As String = String.Empty Select Case typo Case Algorithms.DES Return "DES" Exit Select Case Algorithms.RC2 Return "RC2" Exit Select Case Algorithms.RDAEL Return "Rijndael" Exit Select Case Algorithms.TDES Return "TripleDES" Exit Select Case Else Return "Rijndael" Exit Select End Select Return algtype End Function Friend Shared Function ReadKeyString(ByVal xmlkeystring As String) As RSA Dim rsaer As RSA = Nothing Try If (String.IsNullOrEmpty(xmlkeystring)) Then Throw New Exception("Key is not specified") rsaer = RSA.Create() rsaer.FromXmlString(xmlkeystring) Catch ex As Exception Throw New CryptographicException("Unable to load key") End Try Return rsaer End Function End Namespace 

@gogole:实际上我不使用套接字,这个代码是单独使用的方式,带有手工镶嵌的密钥。 但是,一旦你拥有了你的密码机制,你就会有超过一半的旅程。

这里有两个缺少方法来创建密钥,因为您请求代码完成。 我希望你发现这很有帮助

 Public Shared Sub CreateKeyPair(ByVal filename As String) Dim xmlpublic As String = String.Empty Dim xmlprivate As String = String.Empty CreateKeyPair(xmlpublic, xmlprivate) Try Dim writer As New StreamWriter(filename + ".prv") writer.Write(xmlprivate) writer.Flush() writer.Close() Catch ex As Exception Throw New CryptographicException("Unable to write private key file: " + ex.Message) End Try Try Dim writer = New StreamWriter(filename + ".pub") writer.Write(xmlpublic) writer.Flush() writer.Close() Catch ex As Exception Throw New CryptographicException("Unable to write public key file: " + ex.Message) End Try End Sub Public Shared Sub CreateKeyPair(ByRef xmlpublic As String, ByRef xmlprivate As String) Dim rsa As RSA = Nothing Try rsa.Create() Catch ex As Exception Throw New CryptographicException("Unable to initialize keys: " + ex.Message) End Try Try xmlpublic = rsa.ToXmlString(True) Catch ex As Exception Throw New CryptographicException("Unable to generate public key: " + ex.Message) End Try Try xmlprivate = rsa.ToXmlString(False) Catch ex As Exception Throw New CryptographicException("Unable to generate private key: " + ex.Message) End Try End Sub 

不知道vb但是试图将@Andrea Celin转换为c#中有用的代码之一

 namespace Crypto { using System; using System.Security.Cryptography; class RSACry { public enum Algorithms { DES, TDES, RC2, RDAEL }; public string Encrypt(string xmlkeystring, Algorithms typo, string datatoencrypt) { RSA rsaer = RSACry.ReadKeyString(xmlkeystring); byte[] result = RSACry.EncryptIt(rsaer, typo, datatoencrypt); return System.Convert.ToBase64String(result); } public string Decrypt(string xmlkeystring,Algorithms typo,string datatodecrypt) { RSA rsaer = RSACry.ReadKeyString(xmlkeystring); byte[] result =RSACry.DecryptIt(rsaer, typo, datatodecrypt); return System.Text.Encoding.UTF8.GetString(result); } public static byte[] EncryptIt(RSA rsaer, Algorithms typo, string datatoencrypt) { byte[] result = null; try { byte[] plainbytes = System.Text.Encoding.UTF8.GetBytes(datatoencrypt); SymmetricAlgorithm sa = SymmetricAlgorithm.Create(RSACry.GetAlgorithmName(typo)); ICryptoTransform ct = sa.CreateEncryptor(); byte[] encrypt = ct.TransformFinalBlock(plainbytes, 0, plainbytes.Length); RSAPKCS1KeyExchangeFormatter fmt = new RSAPKCS1KeyExchangeFormatter(rsaer); byte[] keyex = fmt.CreateKeyExchange(sa.Key); //--return the key exchange, the IV (public) and encrypted data result = new byte[keyex.Length + sa.IV.Length + encrypt.Length]; Buffer.BlockCopy(keyex, 0, result, 0, keyex.Length); Buffer.BlockCopy(sa.IV, 0, result, keyex.Length, sa.IV.Length); Buffer.BlockCopy(encrypt, 0, result, keyex.Length + sa.IV.Length, encrypt.Length); } catch (Exception ex) { throw new CryptographicException("Unable to crypt: " + ex.Message); } return result; } public static byte[] DecryptIt(RSA rsaer, Algorithms typo, string datatodecrypt) { byte[] result = null; try { byte[] encrbytes = System.Convert.FromBase64String(datatodecrypt); SymmetricAlgorithm sa = SymmetricAlgorithm.Create(RSACry.GetAlgorithmName(typo)); byte[] keyex = new byte[(rsaer.KeySize >> 3) - 1]; Buffer.BlockCopy(encrbytes, 0, keyex, 0, keyex.Length); RSAPKCS1KeyExchangeDeformatter def = new RSAPKCS1KeyExchangeDeformatter(rsaer); byte[] key = def.DecryptKeyExchange(keyex); byte[] iv = new byte[sa.IV.Length - 1]; Buffer.BlockCopy(encrbytes, keyex.Length, iv, 0, iv.Length); ICryptoTransform ct = sa.CreateDecryptor(key, iv); result = ct.TransformFinalBlock(encrbytes, keyex.Length + iv.Length, (encrbytes.Length - 1) - (keyex.Length + iv.Length)); } catch (Exception ex) { throw new CryptographicException("Unable to decrypt: " + ex.Message); } return result; } public static string GetAlgorithmName(Algorithms typo) { string algtype = String.Empty; switch(typo) { case Algorithms.DES: algtype = "DES"; break; case Algorithms.RC2: algtype = "RC2"; break; case Algorithms.RDAEL: algtype = "Rijndael"; break; case Algorithms.TDES: algtype = "TripleDES"; break; default: algtype = "Rijndael"; break; } return algtype; } public static RSA ReadKeyString(string xmlkeystring) { RSA rsaer = null; try { if (String.IsNullOrEmpty(xmlkeystring)) { throw new Exception("Key is not specified"); } rsaer = RSA.Create(); rsaer.FromXmlString(xmlkeystring); } catch (Exception ex) { throw new CryptographicException("Unable to load key :"+ex.Message); } return rsaer; } } }