Кроссплатформенность C# Crypto: Невозможно сгенерировать правильный ключ / Выбрать правильный алгоритм - PullRequest
1 голос
/ 10 января 2020

Я создаю криптографический класс для использования в моем клиенте чата (Windows,. NET Framework) и на сервере (Linux,. NET Core).

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

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

(я очень плохо знаком с крипто, C# ... Ну, в целом программирование, я учусь 1 год)

Я действительно надеюсь, что мой код не полный беспорядок:

using Org.BouncyCastle.Asn1.Nist;
using Org.BouncyCastle.Asn1.Sec;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Security;
using System;
using System.IO;
using System.Text;

namespace ChatClient
{
    public class Crypto
    {
        private bool _ready = false;
        private X9ECParameters m_x9EC;

        private ECPublicKeyParameters m_myPubKey;
        private AsymmetricKeyParameter m_myPrivKey;

        private byte[] m_sharedSecret = null;

        public Crypto()
        {
            // Get curve
            m_x9EC = NistNamedCurves.GetByName("P-521");
            ECDomainParameters ecDomain = new ECDomainParameters(m_x9EC.Curve, m_x9EC.G, m_x9EC.N, m_x9EC.H, m_x9EC.GetSeed());

            // Create generator
            ECKeyPairGenerator g = (ECKeyPairGenerator)GeneratorUtilities.GetKeyPairGenerator("ECDH");
            g.Init(new ECKeyGenerationParameters(ecDomain, new SecureRandom()));

            // Generate keypair
            AsymmetricCipherKeyPair keyPair = g.GenerateKeyPair();

            // Set keys
            m_myPubKey = (ECPublicKeyParameters)keyPair.Public;
            m_myPrivKey = keyPair.Private;
        }

        public void GenPrivateKey(byte[] key)
        {
            // Why whould anyone even...
            if (key == null)
                throw new ArgumentNullException();

            // Split up the Base64-Encoded, comma-seperated crypto-coords of the server/client
            string str = Encoding.UTF8.GetString(key);
            string[] elements = str.Split(',');
            if (elements.Length != 2)
                throw new ArgumentException();

            // Generate a key out of the coordinates
            ECPoint point = m_x9EC.Curve.CreatePoint(
                new BigInteger(Convert.FromBase64String(elements[0])),
                new BigInteger(Convert.FromBase64String(elements[1]))
                );

            // Get public key
            ECPublicKeyParameters remotePubKey = new ECPublicKeyParameters("ECDH", point, SecObjectIdentifiers.SecP521r1);

            // Generate shared secret key
            IBasicAgreement aKeyAgree = AgreementUtilities.GetBasicAgreement("ECDH");
            aKeyAgree.Init(m_myPrivKey);
            m_sharedSecret = aKeyAgree.CalculateAgreement(remotePubKey).ToByteArray();

            // Debugging...
            Console.WriteLine("Key: {0}", Convert.ToBase64String(m_sharedSecret));

            // Authentication is done, class can now be used for encryption/decryption
            _ready = true;
        }

        public byte[] GetPublicKey()
        {
            // Assemble the Base64-Encoded, comma-seperated crypto-coords to send to the other client/server
            string str = string.Format(
                "{0},{1}",
                Convert.ToBase64String(m_myPubKey.Q.AffineXCoord.ToBigInteger().ToByteArray()),
                Convert.ToBase64String(m_myPubKey.Q.AffineYCoord.ToBigInteger().ToByteArray())
                );

            // Return it
            return Encoding.UTF8.GetBytes(str);
        }

        public byte[] Encrypt(byte[] unencryptedData)
        {
            // Keys need to be generated before we can start encrypting/decrypring, And please dont pass null into here...
            if (!_ready || unencryptedData == null)
                return null;

            using (MemoryStream ms = new MemoryStream())
            {
                using (System.Security.Cryptography.AesManaged cryptor = new System.Security.Cryptography.AesManaged())
                {
                    // Set parameters
                    cryptor.Mode = System.Security.Cryptography.CipherMode.CBC;
                    cryptor.Padding = System.Security.Cryptography.PaddingMode.PKCS7;
                    cryptor.KeySize = 128;
                    cryptor.BlockSize = 128;

                    // Get iv
                    byte[] iv = cryptor.IV;

                    // Encrypt the data
                    using (System.Security.Cryptography.CryptoStream cs = new System.Security.Cryptography.CryptoStream(ms, cryptor.CreateEncryptor(m_sharedSecret, iv), System.Security.Cryptography.CryptoStreamMode.Write))
                        cs.Write(unencryptedData, 0, unencryptedData.Length);

                    // Get stuff that was encrpyted
                    byte[] encryptedContent = ms.ToArray();

                    // Create a new array for the data + iv
                    byte[] result = new byte[iv.Length + encryptedContent.Length];

                    //copy both arrays into one
                    System.Buffer.BlockCopy(iv, 0, result, 0, iv.Length);
                    System.Buffer.BlockCopy(encryptedContent, 0, result, iv.Length, encryptedContent.Length);

                    // Aaaand return it
                    return result;
                }
            }

            return null;
        }

        public byte[] Decrypt(byte[] encryptedData)
        {
            // Keys need to be generated before we can start encrypting/decrypring, And please dont pass null into here...
            if (!_ready || encryptedData == null)
                return null;

            // New arrays for iv and data
            byte[] iv = new byte[16];
            byte[] dat = new byte[encryptedData.Length - iv.Length];

            // Get iv and data
            System.Buffer.BlockCopy(encryptedData, 0, iv, 0, iv.Length);
            System.Buffer.BlockCopy(encryptedData, iv.Length, dat, 0, dat.Length);

            using (MemoryStream ms = new MemoryStream())
            {
                using (System.Security.Cryptography.AesManaged cryptor = new System.Security.Cryptography.AesManaged())
                {
                    // Set parameters
                    cryptor.Mode = System.Security.Cryptography.CipherMode.CBC;
                    cryptor.Padding = System.Security.Cryptography.PaddingMode.PKCS7;
                    cryptor.KeySize = 128;
                    cryptor.BlockSize = 128;

                    // Decrypt the data
                    using (System.Security.Cryptography.CryptoStream cs = new System.Security.Cryptography.CryptoStream(ms, cryptor.CreateDecryptor(m_sharedSecret, iv), System.Security.Cryptography.CryptoStreamMode.Write))
                        cs.Write(encryptedData, 0, encryptedData.Length);

                    // Aaaand return it
                    return ms.ToArray();
                }
            }

            return null;
        }
    }
}

Где эта часть:

// Encrypt the data
using (System.Security.Cryptography.CryptoStream cs = new System.Security.Cryptography.CryptoStream(ms, cryptor.CreateEncryptor(m_sharedSecret, iv), System.Security.Cryptography.CryptoStreamMode.Write))

Выдает эту ошибку:

Exception thrown: 'System.ArgumentException' in System.Core.dll
An unhandled exception of type 'System.ArgumentException' occurred in System.Core.dll
The specified key is not a valid size for this algorithm.

Спасибо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...