Вопрос

В настоящее время я пытаюсь реализовать класс для обработки безопасной связи между экземплярами моего приложения, используя класс 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();
        }

    }
}

Второй вопрос :как мне отправлять и получать данные для передачи в класс?я новичок в этой области, буду признателен за подсказки.

Это было полезно?

Решение

Я бы сделал так, чтобы методы шифрования / подписи / дешифрования / проверки принимали параметры для данных, а не имели для них переменных-членов.Тем не менее, наличие переменных-членов для ключа и поставщика кажется нормальным.В принципе, я бы ожидал использовать один и тот же ключ несколько раз, но не одни и те же данные.

Я бы также сделал это неизменяемым - сделал все переменные доступными только для чтения, принимая все параметры, которые вам понадобятся для поставщиков в конструкторе, вместо того, чтобы использовать отдельный метод инициализации.

Помимо этого, кажется нормальным обернуть функциональность в более простой 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 в .NET страдает, когда вы пытаетесь управлять более чем 250 (более или менее, извините, я не помню) байтами данных.

Я просто вырезал и вставил только необходимые методы, я также вырезал xml-документацию, потому что она не на английском языке, если вы нашли это полезным, дайте мне знать, я могу опубликовать весь исходный код.Повторяю, я не тестировал эту версию cut & paste, но я использовал полную версию этого класса, которая не сильно отличается.

КСТАТИ:это в 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

@гоголе:на самом деле я не использую сокеты, этот код используется автономно с ключами, доставляемыми вручную.Однако, как только у вас появится свой криптомеханизм, вы пройдете более половины пути.

Здесь отсутствуют два метода создания ключей, как вы и просили, код завершен.Я надеюсь, что вы нашли это полезным

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;
    }
}
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top