使用BouncyCastle加载SM2私钥时抛出Scalar区间异常问题排查
SM2私钥加载报错:Scalar is not in [1, n-1]的原因及解决
核心原因分析
私钥格式解析错误
SM2私钥的Base64字符串大多不是私钥大整数的原始裸字节,而是遵循PKCS#8等标准的ASN.1编码格式,里面包含了算法标识、版本号等额外信息。直接将整个Base64解码后的字节转成BigInteger,得到的不是真正的私钥d值,自然会超出SM2曲线的阶n的有效范围(1 ≤ d ≤ n-1)。BigInteger构造的符号位问题
默认new BigInteger(data)会把字节数组当作带符号的大端数据处理,如果私钥字节的最高位是1,会被解析为负数,或者数值被错误偏移,导致结果不在有效区间内。必须指定无符号模式来构造BigInteger。私钥本身无效
生成的私钥字符串对应的数值本身不符合SM2规范:要么是0,要么大于等于曲线阶n,这类私钥本身就是非法的,无法被BouncyCastle加载。
修正代码示例
情况1:私钥是PKCS#8格式的Base64
using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; // 解码Base64得到PKCS#8格式字节 byte[] pkcs8Bytes = Convert.FromBase64String(privateKeyString); // 解析ASN.1结构 Asn1Sequence pkcs8Seq = Asn1Sequence.GetInstance(pkcs8Bytes); DerOctetString privateKeyOctet = (DerOctetString)pkcs8Seq[1]; byte[] dBytes = privateKeyOctet.GetOctets(); // 无符号解析私钥大整数 BigInteger d = new BigInteger(1, dBytes); // 构造私钥参数 ECPrivateKeyParameters privateKeyParams = new ECPrivateKeyParameters(d, sm2Parameters);
情况2:私钥是原始裸字节的Base64
byte[] data = Convert.FromBase64String(privateKeyString); // 必须指定1作为第一个参数,表示无符号解析 BigInteger privateKey = new BigInteger(1, data); ECPrivateKeyParameters privateKeyParams = new ECPrivateKeyParameters(privateKey, sm2Parameters);
内容的提问来源于stack exchange,提问作者bright bian
相关产品推荐
相关产品推荐

