OpenSSL 和 BouncyCastle 之间的 ECDSA 密钥大小差异

ECDSA key size difference between OpenSSL and BouncyCastle

我正在使用 BouncyCastle 在 C# 中实现 192 位 ECDSA 签名。它是由我的客户在文本中指定的。在我开始在 BouncyCastle 中实施后,他们向我发送了一份 OpenSSL 规范。现在我在 OpenSSL 和 BouncyCastle 之间移动密钥时遇到问题。我想我一定是遗漏了一些要点,并请求您的帮助以了解 ECDSA 192 如何在两个库中工作。

规范的第一行是:

openssl ecparam -name secp192r1 -genkey -noout -out priv.pem

生成的 priv.pem 包含一个解码为 97 字节的 Base64 字符串。当我使用 192 位曲线将该密钥提供给 BouncyCastle 时,出现异常。

ECDomainParameters spec = GetEcdsaCurveParamsForInit();
// D is the Private Key
BigInteger d = new BigInteger(tbSigKeyHex.Text, 16);
ECPrivateKeyParameters sKey = new ECPrivateKeyParameters("ECDSA", d, spec);
ECPublicKeyParameters vKey = GL_ECKeyPairGenerator.GetCorrespondingPublicKey(sKey); // EXCEPT on d > 24byte max value

具体异常是EcKeyPairGenerator.cs这一行System.InvalidOperationException:

ECPoint q = new FixedPointCombMultiplier().Multiply(ec.G, privKey.D);

如果我将 Ascii-hex 输入字符串截断为 48 个字节,那么 privKey.D 永远不会超过 24 个字节的最大值,一切运行正常。但是现在我的代码与规范不同。

我还注意到 BouncyCastle 使用 192 位曲线制作 24 字节密钥:

AsymmetricCipherKeyPair keyPair = GenerateKeys(192); // bit length selects curve in GL_ECKeyPairGenerator
ECPrivateKeyParameters sKey = (ECPrivateKeyParameters)keyPair.Private;
string szD = sKey.D.ToString(16);
PrintToFeedback(string.Format("Generated Private D Key {0} bytes: {1}", szD.Length/2, szD));
ECPublicKeyParameters vKey = (ECPublicKeyParameters)keyPair.Public;

打印出来:

Generated Private D Key 24 bytes: 92e67f4a42c3031349f7e88d082a8e1f122eaee8d8b0823d

当我破解并检查 sKey 时,我没有看到任何看起来像 97 字节数字的东西。我看到 24 字节如何映射到 192 位,而不是 97 位。由于我的客户说 OpenSSL 是规范,所以我必须假设这是正确的。但是我有点迷路了。在他们向我发送 OpenSSL 规范之前,我已经说服自己 ECDSA192 使用 24 字节的私钥(和 48 字节的 public 密钥,或多或少),但是这个 97 字节的 OpenSSL 密钥再次让一切都变得可疑。我的专长是实时和 RFID,而不是加密。

有人可以帮助我了解如何将 OpenSSL 97 字节密钥与 BouncyCastle 一起使用吗?或者我应该撕掉 BouncyCastle 并用 OpenSSL.Net 重写?

我是运行在Win10下的Cygwin bashwindow,openssl版本是:

OpenSSL 1.0.2o 27 Mar 2018

谢谢。

您的 openssl ecparam 命令生成的文件 priv.pem 包含的不仅仅是构成密钥私有部分的字节。特别是,它还包括密钥对的 public 部分,以及密钥在哪种曲线上的一些信息。当你做的时候你可以看到这个

$ openssl ec -in priv.pem -noout -text

read EC key
Private-Key: (192 bit)
priv:
    74:6b:13:17:a5:6e:bb:8e:76:b1:65:a2:c2:59:16:
    72:36:56:ee:42:b9:91:26:53
pub: 
    04:9b:d5:f3:61:6b:06:86:c2:d2:1b:c8:1f:86:ae:
    ee:58:8a:ac:b3:04:2b:93:c5:8c:1b:24:6e:90:2d:
    9c:aa:69:7e:30:15:86:48:06:97:b6:78:35:a6:48:
    46:1a:2c:4e
ASN1 OID: prime192v1

因此要单独使用私有部分,您必须先将其提取出来。

要更深入地了解 priv.pem 中究竟存储了什么,您可以使用 asn1parse 应用程序:

$ openssl asn1parse -in priv.pem -dump
    0:d=0  hl=2 l=  95 cons: SEQUENCE          
    2:d=1  hl=2 l=   1 prim: INTEGER           :01
    5:d=1  hl=2 l=  24 prim: OCTET STRING      
      0000 - 74 6b 13 17 a5 6e bb 8e-76 b1 65 a2 c2 59 16 72   tk...n..v.e..Y.r
      0010 - 36 56 ee 42 b9 91 26 53-                          6V.B..&S
   31:d=1  hl=2 l=  10 cons: cont [ 0 ]        
   33:d=2  hl=2 l=   8 prim: OBJECT            :prime192v1
   43:d=1  hl=2 l=  52 cons: cont [ 1 ]        
   45:d=2  hl=2 l=  50 prim: BIT STRING        
      0000 - 00 04 9b d5 f3 61 6b 06-86 c2 d2 1b c8 1f 86 ae   .....ak.........
      0010 - ee 58 8a ac b3 04 2b 93-c5 8c 1b 24 6e 90 2d 9c   .X....+....$n.-.
      0020 - aa 69 7e 30 15 86 48 06-97 b6 78 35 a6 48 46 1a   .i~0..H...x5.HF.
      0030 - 2c 4e                                             ,N

或者,如果您使用的是 Windows,请试试这个出色的 ASN.1 Editor 工具。