Я устанавливаю криптографический слой для моего 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.