您可以使用 ECDiffieHellman 来加密消息。您有两个选择:静态静态 ECDH 和静态临时 ECDH:
对于静态 ECDH,接收者需要知道发送者的公钥(这可能是您的应用程序中的一个选项,也可能不是)。您还应该有一些对于此消息是唯一的数据(它可能是您从协议或数据库行中的其他位置获得的序列号,或者它可能是随机数)。然后,您使用 ECDH 生成密钥并使用它来加密您的数据。这将为您提供所需的 16 字节的加密数据长度,但它并非完全不对称:加密器还能够解密消息(同样:这可能是您的应用程序中的问题,也可能不是问题)。
Static-ephemeral 有点不同:这里加密器生成一个临时(临时)EC 密钥对。然后,他使用该密钥对与接收者的公钥一起生成可用于加密数据的密钥。最后,他将临时密钥对的公钥与加密数据一起发送给接收方。这可能更适合您的应用程序,但是使用 ECDH-256 和 AES 的完整加密数据现在将是 2*32+16=80 字节(正如 GregS 指出的那样,您可以通过仅发送公共的 x 坐标来节省 32 个字节-键,但我不相信 .NET 公开了重新计算 y 坐标的功能。
这是一个小类,将做静态-静态 ECDH:
public static class StaticStaticDiffieHellman
{
private static Aes DeriveKeyAndIv(ECDiffieHellmanCng privateKey, ECDiffieHellmanPublicKey publicKey, byte[] nonce)
{
privateKey.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
privateKey.HashAlgorithm = CngAlgorithm.Sha256;
privateKey.SecretAppend = nonce;
byte[] keyAndIv = privateKey.DeriveKeyMaterial(publicKey);
byte[] key = new byte[16];
Array.Copy(keyAndIv, 0, key, 0, 16);
byte[] iv = new byte[16];
Array.Copy(keyAndIv, 16, iv, 0, 16);
Aes aes = new AesManaged();
aes.Key = key;
aes.IV = iv;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
return aes;
}
public static byte[] Encrypt(ECDiffieHellmanCng privateKey, ECDiffieHellmanPublicKey publicKey, byte[] nonce, byte[] data){
Aes aes = DeriveKeyAndIv(privateKey, publicKey, nonce);
return aes.CreateEncryptor().TransformFinalBlock(data, 0, data.Length);
}
public static byte[] Decrypt(ECDiffieHellmanCng privateKey, ECDiffieHellmanPublicKey publicKey, byte[] nonce, byte[] encryptedData){
Aes aes = DeriveKeyAndIv(privateKey, publicKey, nonce);
return aes.CreateDecryptor().TransformFinalBlock(encryptedData,0, encryptedData.Length);
}
}
// Usage:
ECDiffieHellmanCng key1 = new ECDiffieHellmanCng();
ECDiffieHellmanCng key2 = new ECDiffieHellmanCng();
byte[] data = Encoding.UTF8.GetBytes("TestTestTestTes");
byte[] nonce = Encoding.UTF8.GetBytes("whatever");
byte[] encryptedData = StaticStaticDiffieHellman.Encrypt(key1, key2.PublicKey, nonce, data);
Console.WriteLine(encryptedData.Length); // 16
byte[] decryptedData = StaticStaticDiffieHellman.Decrypt(key2, key1.PublicKey, nonce, encryptedData);
Console.WriteLine(Encoding.UTF8.GetString(decryptedData));