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
相关产品推荐
相关产品推荐

