跨平台 C# 加密:无法生成正确的密钥/选择正确的算法



我正在创建一个加密类,用于我的聊天客户端(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.

关闭这个问题,Topaco 在评论中回答了这个问题

在代码中,共享密钥直接用作对称密钥,由于大小不同,这会导致错误。相反,对称密钥(具有适当的大小(通常派生自共享密钥,此处和此处。

最新更新