为什么我的 ECDH 共享密钥生成有时会失败?

问题描述 投票:0回答:1

我正在处理 Apple Pay 的应用内钱包配置。我做了一个测试项目,它与我从苹果文档中获得的测试向量相匹配(利用 System.Security 和 BouncyCastle),所以很确定我在正确的轨道上。

但是,当我切换到我生成的临时密钥对(而不是给定的用于测试的密钥对)时,私钥在生成 ECDH 共享密钥时经常会导致错误。奇怪的是,它似乎有一半的时间没有错误。

这里是生成临时密钥对的代码:

ephemKeyPair = ECDiffieHellman.Create(CURVE); // System.Security.Cryptography.ECDiffieHellman
// save our public and private key bytes
ephemPublicKey = GetPublicKeyFromEncodedBytes(ephemKeyPair.PublicKey.ExportSubjectPublicKeyInfo());
ephemPrivateKey = ephemKeyPair.ExportParameters(true).D;
...
private static byte[] GetPublicKeyFromEncodedBytes(byte[] publicKeyEncoded)
{
     byte[] bytes = new byte[65];
     Array.Copy(publicKeyEncoded, 26, bytes, 0, bytes.Length);
     return bytes;
}

当我尝试生成我的共享密钥(基于 Apple 公钥 + 我的临时私钥)时,它会在大约一半的时间内抛出错误

Scalar is not in the interval [1, n - 1] (Parameter 'd')
。这是调用代码:

GenerateSharedSecret(ephemPrivateKey /* generated above */, applePublicKey /* extracted from input, currently a test .pem file. this has been verified in the Apple docs*/);

以及生成共享密钥的代码:

public void GenerateSharedSecret(byte[] privateKeyIn, byte[] publicKeyIn)
{
     ECDHCBasicAgreement agreement = new ECDHCBasicAgreement();
     X9ECParameters? curve = null;
     ECDomainParameters? ecParam = null;
     ECPrivateKeyParameters? privKey = null;
     ECPublicKeyParameters? pubKey = null;
     Org.BouncyCastle.Math.EC.ECPoint point;
     curve = NistNamedCurves.GetByName("P-256");
     ecParam = new ECDomainParameters(curve.Curve, curve.G, curve.N, curve.H, curve.GetSeed());
     BigInteger bigInt = new BigInteger(privateKeyIn);
     privKey = new ECPrivateKeyParameters(bigInt, ecParam); // *** ERROR HERE ***
     point = ecParam.Curve.DecodePoint(publicKeyIn);
     pubKey = new ECPublicKeyParameters(point, ecParam);

     agreement.Init(privKey);
     BigInteger secret = agreement.CalculateAgreement(pubKey);
     sharedSecret = secret.ToByteArrayUnsigned();
}

我是不是以某种方式不正确地生成了临时密钥,或者完全是其他原因?


**编辑 3/15/23

好的,所以我根据 Maarten 的反馈重写了部分内容。我现在使用所有 BC,而不是使用一些

System.Security
对象和一些
BouncyCastle
对象,它使事情变得更加顺利。我还没有验证加密数据的有效性,但我不再收到这些错误,现在更直接了。

更新代码:

private readonly X9ECParameters curve = NistNamedCurves.GetByName("P-256");
private ECDomainParameters ecParam { get; set; }
private ECPrivateKeyParameters privateKeyParameters { get; set; }
private AsymmetricCipherKeyPair ephemKeyPair { get; set; }
...
private void GenerateEphemeralKeyPair()
{
    ecParam = new ECDomainParameters(curve.Curve, curve.G, curve.N, curve.H, curve.GetSeed());
    var secureRandom = new SecureRandom();
    var keyParams = new ECKeyGenerationParameters(ecParam, secureRandom);
    var generator = new ECKeyPairGenerator("ECDH");
    generator.Init(keyParams);

    ephemKeyPair = generator.GenerateKeyPair();
    ECPublicKeyParameters publicKeyParameters = (ECPublicKeyParameters) 
    ephemKeyPair.Public;
    privateKeyParameters = (ECPrivateKeyParameters) ephemKeyPair.Private;
    ephemPublicKey = publicKeyParameters.Q.GetEncoded();
    ephemPrivateKey = privateKeyParameters.D.ToByteArrayUnsigned();
}
...
private void GenerateSharedSecret(byte[] publicKeyIn)
{
   Org.BouncyCastle.Math.EC.ECPoint point = ecParam.Curve.DecodePoint(publicKeyIn);
   ECPublicKeyParameters pubKey = new ECPublicKeyParameters(point, ecParam);

   ECDHCBasicAgreement agreement = new ECDHCBasicAgreement();
   agreement.Init(privateKeyParameters);

   BigInteger secret = agreement.CalculateAgreement(pubKey);

   sharedSecret = secret.ToByteArrayUnsigned();
   sharedSecretAsHex = Convert.ToHexString(sharedSecret);
}
c# cryptography bouncycastle applepay shared-secret
1个回答
0
投票

问题在这里:

BigInteger bigInt = new BigInteger(privateKeyIn);
。这将导致大约一半时间的负值。请参阅示例了解如何通过在末尾添加零字节来解决此问题(.NET 主要是小端)。

注意

BigInteger
假定小端。您可能首先必须颠倒字节顺序。例如,这是 .NET 上 D 参数的文档

代表椭圆曲线密码学 (ECC) 算法的私钥 D,以大端格式存储。

© www.soinside.com 2019 - 2024. All rights reserved.