2

我在使用ECDiffieHellmanCng类交换密钥时遇到问题:

第 1 步 - 创建公钥

public byte[] CreatePublicKey()
{
    using (ECDiffieHellmanCng cng = new ECDiffieHellmanCng())
    {
        cng.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
        cng.HashAlgorithm = CngAlgorithm.Sha512;
        return cng.PublicKey.ToByteArray();
    }
}

第 2 步 - 交换并获取私钥

public byte[] CreatePrivateKey(byte[] publicKey1, byte[] publicKey2)
{
    using(ECDiffieHellmanCng cng = new ECDiffieHellmanCng(CngKey.Import(publicKey1, CngKeyBlobFormat.EccPublicBlob)))
    {
        cng.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
        cng.HashAlgorithm = CngAlgorithm.Sha512;
        return cng.DeriveKeyMaterial(CngKey.Import(publicKey2, CngKeyBlobFormat.EccPublicBlob));
    }
}

例子

byte[] alicePublicKey = CreatePublicKey();
byte[] bobPublicKey = CreatePublicKey();

// This fails
byte[] alicePrivateKey = CreatePrivateKey(alicePublicKey, bobPublicKey);
byte[] bobPrivateKey = CreatePrivateKey(bobPublicKey, alicePublicKey);

具体来说,它在该方法的这一行失败CreatePrivateKey(...)

return cng.DeriveKeyMaterial(CngKey.Import(publicKey2, CngKeyBlobFormat.EccPublicBlob));

错误

System.Security.Cryptography.CryptographicException:“密钥不存在。”

我究竟做错了什么?

4

1 回答 1

4

问题是您正在尝试DeriveKeyMaterial使用两个公钥导出共享密钥(的结果)。这是行不通的,因为您需要一方的私钥和另一方的公钥(不需要第一方的公钥,因为它可以从私钥派生)。这是一个示例(我修正了一些术语,因为现在它们具有误导性 -CreatePrivateKey不创建私钥)。请注意,您通常不会像这样导出私钥并将它们存储在容器中,例如:

public static (byte[] publicKey, byte[] privateKey) CreateKeyPair() {
    using (ECDiffieHellmanCng cng = new ECDiffieHellmanCng(
        // need to do this to be able to export private key
        CngKey.Create(
            CngAlgorithm.ECDiffieHellmanP256,
            null,
            new CngKeyCreationParameters
                { ExportPolicy = CngExportPolicies.AllowPlaintextExport }))) {
        cng.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
        cng.HashAlgorithm = CngAlgorithm.Sha512;
        // export both private and public keys and return
        var pr = cng.Key.Export(CngKeyBlobFormat.EccPrivateBlob);
        var pub = cng.PublicKey.ToByteArray();
        return (pub, pr);
    }
}

public static byte[] CreateSharedSecret(byte[] privateKey, byte[] publicKey) {
    // this returns shared secret, not private key
    // initialize algorithm with private key of one party
    using (ECDiffieHellmanCng cng = new ECDiffieHellmanCng(CngKey.Import(privateKey, CngKeyBlobFormat.EccPrivateBlob))) {
        cng.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
        cng.HashAlgorithm = CngAlgorithm.Sha512;
        // use public key of another party
        return cng.DeriveKeyMaterial(CngKey.Import(publicKey, CngKeyBlobFormat.EccPublicBlob));
    }
}

现在上面有两个函数:

var aliceKeyPair = CreateKeyPair();
var bobKeyPair = CreateKeyPair();                                
byte[] bobSharedSecret = CreateSharedSecret(bobKeyPair.privateKey, aliceKeyPair.publicKey);
byte[] aliceSharedSecret = CreateSharedSecret(aliceKeyPair.privateKey, bobKeyPair.publicKey);
// derived shared secrets are the same - the whole point of this algoritm
Debug.Assert(aliceSharedSecret.SequenceEqual(bobSharedSecret));
于 2018-01-30T13:38:28.607 回答