Получение криптографического исключения при попытке использовать CngKey.Import с сообщением об ошибке «Параметр неверен» - PullRequest
0 голосов
/ 23 марта 2019

Я устанавливаю криптографический слой для моего TCP-сервера. До этого все сообщения осуществлялись через открытый текст. Я решил использовать ECDiffieHellmanCng для первоначального обмена ключами, а затем AES для последующих сообщений.

Ключ должным образом передается со стороны клиента через сокет TCP, и их длина совпадает.

Я получаю исключение в этой строке:

sessionKey = server.DeriveKeyMaterial(CngKey.Import(clientPublicKey, 
CngKeyBlobFormat.EccPublicBlob));

Сообщение об исключении и трассировка стека:

The parameter is incorrect.
at System.Security.Cryptography.NCryptNative.ImportKey(SafeNCryptProviderHandle 
   provider, Byte[] keyBlob, String format)
at System.Security.Cryptography.CngKey.Import(Byte[] keyBlob, String curveName,
   CngKeyBlobFormat format, CngProvider provider)
at System.Security.Cryptography.CngKey.Import(Byte[] keyBlob, CngKeyBlobFormat
   format)

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

Код на стороне клиента, который инициирует обмен ключами:

try
{
client = new ECDiffieHellmanCng();

client.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;

client.HashAlgorithm = CngAlgorithm.Sha256;

clientPublicKey = client.PublicKey.ToByteArray();

displayLine("[client public key] Length : " + clientPublicKey.Length.ToString() + " Key: " + BitConverter.ToString(clientPublicKey));

writeByteArrayToClient(clientPublicKey,clientSocket);

}

catch(Exception e)
{
}

/// <summary>
        /// Write a byte array to the client
        /// </summary>
        /// <param name="bytesToSend">user supplied byte array</param>
        /// <param name="tcpClient">socket to write on</param>
        /// <returns></returns>

public bool writeByteArrayToClient(byte[] bytesToSend, TcpClient tcpClient)

{

//Stores the success or failure status
            bool returnFlag = false;

            try
            {
                //Open network stream from the clientsocket to read and write data
                NetworkStream networkStream = tcpClient.GetStream();

                //Flush the stream to remove any residual unsent data
                networkStream.Flush();

                //Write the sendBytes bytes to the networkStream
                networkStream.Write(bytesToSend, 0, bytesToSend.Length);

                //Flush the network stream of any remaining bytes
                networkStream.Flush();

                //Set the return flag to true to indicate success
                returnFlag = true;
            }
            catch (Exception ex)
            {
                //Display exception message and write log to serverLog.txt
                displayLine("[Writing] " + ex.Message + " Thrown while writing to client");

                //Set the return flag to false to indicate failure
                returnFlag = false;
            }

            //Return operation success/failure status to calling function
            return returnFlag;
        }

Сторона сервера:

clientPublicKey = readByteArrayFromClient(10000);
                //displayInMainForm("[client public key] Length : " + clientPublicKey.Length.ToString() + " Key: " + BitConverter.ToString(clientPublicKey));
                //Key Exchange
                serverKeyGenerate();

public void serverKeyGenerate()
        {
            server = new ECDiffieHellmanCng();
            server.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
            server.HashAlgorithm = CngAlgorithm.Sha256;
            ServerPublicKey = server.PublicKey.ToByteArray();
            sessionKey = server.DeriveKeyMaterial(CngKey.Import(clientPublicKey, CngKeyBlobFormat.EccPublicBlob)); //THIS IS WHERE I AM GETTING THE EXCEPTION
        }

/// <summary>
        /// Reads a byte array from the client 
        /// </summary>
        /// <param name="timeout">Specifies how long the socket should wait for data, default value is infinite</param>
        /// <returns></returns>
        private byte[] readByteArrayFromClient(int timeout = Timeout.Infinite)
        {
            //Open network stream from the clientsocket to read and write data
            NetworkStream networkStream = clientSocket.GetStream();

            //Set read timeout value to as supplied by the user, default value is to wait forever
            networkStream.ReadTimeout = timeout;

            //Byte array buffer to read data coming from the clientsocket based on buffer size
            byte[] bytesFrom = new byte[(int)clientSocket.ReceiveBufferSize];

            //Read the data available from the network stream till the buffer is full
            networkStream.Read(bytesFrom, 0, (int)clientSocket.ReceiveBufferSize);

            //Flush networkstream after the read is complete
            networkStream.Flush();

            //Remove old array reference
            transient = null;

            //Use globally shared transient array to store the bytes read 
            transient = bytesFrom;

            int lastIndex = Array.FindLastIndex(bytesFrom, b => b != 0);
            Array.Resize(ref bytesFrom, lastIndex+1);

            return bytesFrom;
        }

Ожидаемый результат состоит в том, что сеансовый ключ должен генерироваться без исключения, которое я затем буду использовать для шифрования AES.

...