You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Apple Pay钱包配置中ECDH共享密钥生成偶发失败排查

问题:Apple Pay应用内钱包ECDH共享密钥生成随机报错

我正在开发Apple Pay应用内钱包的配置功能,已经基于Apple文档提供的测试向量完成测试项目(使用System.Security和BouncyCastle组件),确认实现方向正确。但切换到自行生成的临时密钥对(而非测试用给定密钥对)时,ECDH共享密钥生成操作时常报错,奇怪的是约半数情况可正常运行。

生成临时密钥对的代码:

ephemKeyPair = ECDiffieHellman.Create(CURVE); // System.Security.Cryptography.ECDiffieHellman
// 保存公钥和私钥字节数据
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 /* 上述代码生成 */, applePublicKey /* 从输入提取,当前为测试.pem文件,已通过Apple文档验证*/);

生成共享密钥的代码:

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); // *** 错误发生位置 ***
     point = ecParam.Curve.DecodePoint(publicKeyIn);
     pubKey = new ECPublicKeyParameters(point, ecParam);

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

是否是临时密钥对生成方式有误,或是其他问题导致?


2023年3月15日更新

根据Maarten的反馈,我重写了部分代码,不再混用System.Security与BouncyCastle对象,转而全部使用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);
}

内容的提问来源于stack exchange,提问作者Paul S

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 02:59:58