Implementing RSA in C#

前端 未结 5 1059
北海茫月
北海茫月 2020-12-10 06:39

I\'m currently trying to implement a class to handle secure communications between instances of my app using RSACrytoServiceProveider class. First question : is it a good i

相关标签:
5条回答
  • 2020-12-10 07:25

    Does not know much vb but tried to convert @Andrea Celin one of useful Code in 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;
        }
    }
    }
    
    0 讨论(0)
  • 2020-12-10 07:27

    @gogole: actually I don't use sockets, this code is used in stand alone way with keys hand-bringed. However once you have your crypt mechanism, you're at more than half of the journey.

    Here there are two missing methods to create keys, as you requested the code is complete. I hope you found this helpful

    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
    
    0 讨论(0)
  • 2020-12-10 07:28

    I would make the encrypt/sign/decrypt/verify methods take parameters for the data rather than having member variables for them. Having member variables for the key and provider seems okay though. Basically I'd expect to use the same key multiple times but not the same data.

    I'd also make it immutable - make all the variables readonly, taking all the parameters you'll need for the providers in the constructor instead of having a separate initialisation method.

    Beyond that, it seems okay to wrap the functionality in a simpler API for your needs though, yes.

    0 讨论(0)
  • 2020-12-10 07:30

    I don't know if this snip of code may help you, I've wrote this code to be able to crypt and decrypt with private/public key pairs in diverse crypting algortims and without data to encrypt length issue, infact RSA implementation in .NET suffer whe you try to manage more than 250 (more or less, sorry I don't recall) bytes of data.

    I just cut and paste only methods needed, I also cutted xml documentation cause is not in english, if you found this useful let me know, I can post all source. I repeat I do not tested this cut&paste version, but I used the full version of this class that is not that different.

    BTW: it's in VB, but if you just need to lurk at it I think it's enough ;)

    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
    
    0 讨论(0)
  • 2020-12-10 07:44

    I have made some adjustments, here is what the implementation looks like:

    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
        }
    }
    

    you guys still haven't said anything about how communication is going to be established (i'm thinking sockets). Please enlighten me.

    0 讨论(0)
提交回复
热议问题