TL;DR:我没有找到一种方法可以使用NIST SP 800-56A第5.8.1节中描述的KDF仅使用.NET 4.0内置类推导出对称密钥。
好消息(对我来说 :-))是在.NET 4.0中使用可爱的BouncyCastle库(NuGet: Install-Package BouncyCastle-Ext-Version"1.7.0")是可能的。以下是具体步骤:
第1步:获取对方的公钥
根据情况,这可能从证书中读取,也可能作为包含加密数据的消息的一部分传递给您。一旦获得Base64编码的公钥,请像下面这样将其读入Org.BouncyCastle.Crypto.Parameters.ECPublicKeyParameters对象中:
var publicKeyBytes = Convert.FromBase64String(base64PubKeyStr);
ECPublicKeyParameters otherPartyPublicKey = (ECPublicKeyParameters)PublicKeyFactory.CreateKey(publicKeyBytes);
步骤2:读取您的私钥
通常情况下,这涉及从PFX/P12证书中读取私钥。运行代码的Windows帐户应该可以访问PFX/P12,并且如果证书已导入到证书存储中,则需要通过certmgr.msc中的“所有任务”->“管理私钥”菜单授予权限。
using (StreamReader reader = new StreamReader(path))
{
var fs = reader.BaseStream;
string password = "<password for the PFX>";
Pkcs12Store store = new Pkcs12Store(fs, passWord.ToCharArray());
foreach (string n in store.Aliases)
{
if (store.IsKeyEntry(n))
{
AsymmetricKeyEntry asymmetricKey = store.GetKey(n);
if (asymmetricKey.Key.IsPrivate)
{
ECPrivateKeyParameters privateKey = asymmetricKey.Key as ECPrivateKeyParameters;
}
}
}
}
第三步:计算共享密钥
IBasicAgreement aKeyAgree = AgreementUtilities.GetBasicAgreement("ECDH");
aKeyAgree.Init(privateKey);
BigInteger sharedSecret = aKeyAgree.CalculateAgreement(otherPartyPublicKey);
byte[] sharedSecretBytes = sharedSecret.ToByteArray();
第四步:准备计算对称密钥所需的信息:
byte[] algorithmId = Encoding.ASCII.GetBytes(("<prependString/Hex>" + "id-aes256-GCM"));
byte[] partyUInfo = Encoding.ASCII.GetBytes("<as-per-agreement>");
byte[] partyVInfo = <as-per-agreement>;
MemoryStream stream = new MemoryStream(algorithmId.Length + partyUInfo.Length + partyVInfo.Length);
var sr = new BinaryWriter(stream);
sr.Write(algorithmId);
sr.Flush();
sr.Write(partyUInfo);
sr.Flush();
sr.Write(partyVInfo);
sr.Flush();
stream.Position = 0;
byte[] keyCalculationInfo = stream.GetBuffer();
步骤五:推导对称密钥
// NOTE: Use the digest/Hash function as per your agreement with the other party
IDigest digest = new Sha256Digest();
byte[] symmetricKey = new byte[digest.GetDigestSize()];
digest.Update((byte)(1 >> 24));
digest.Update((byte)(1 >> 16));
digest.Update((byte)(1 >> 8));
digest.Update((byte)1);
digest.BlockUpdate(sharedSecret, 0, sharedSecret.Length);
digest.BlockUpdate(keyCalculationInfo, 0, keyCalculationInfo.Length);
digest.DoFinal(symmetricKey, 0);
现在您已经准备好对称密钥可以进行解密了。使用AES执行解密,可以使用BouncyCastle IWrapper。通过调用WrapperUtilities.GetWrapper("AES//")(例如"AES/CBC/PKCS7")来获取一个IWrapper,这取决于两个通信方之间的协议。
使用对称密钥和初始化向量(IV)初始化密码(IWrapper),然后调用Unwrap方法获取明文字节。最后,使用所使用的字符编码(例如UTF8/ASCII/Unicode)转换为字符串文字。