.Net中无法使用可用的ECDSA签名的问题

时间:2018-09-04 15:21:47

标签: c# openssl cross-platform digital-signature ecdsa

我无法在OpenSSL.Net中创建可以在OpenSSL命令行中进行验证的签名。

我的规格是这样的:

$ openssl ecparam -name prime192v1 -genkey -noout -out priv192v1B.pem
$ openssl ec -in priv192v1B.pem -pubout -out pub192v1B.pem
read EC key
writing EC key
$ openssl dgst -sha256 -sign priv192v1B.pem -out cmdlineSig192v1B.bin <        ./testCardDataB.bin
$ openssl dgst -sha256 -verify pub192v1B.pem -signature cmdlineSig192v1B.bin < ./testCardDataB.bin
Verified OK

其中testCardDataB.bin由下面的C#代码创建,该代码也使testCardSigB.bin成为可能。我应该用C#编写代码,以使签名可以通过OpenSSL命令行验证。如果我的代码正确,那么此命令行也应该起作用:

$ openssl dgst -sha256 -verify pub192v1B.pem -signature testCardSigB.bin < ./testCardDataB.bin
Verification Failure

但是没有,所以我的C#做错了。这是C#:

        private void OsslTestSignature()
    {
        PrintToFeedback("Duplicating ecdsa_example.sh IN OPENSSL...");
        //openssl ecparam -name prime192v1 -genkey -noout -out priv192v1B.pem
        string privPemB64 = "MF8CAQEEGMrXsw/qyViETP1eMx/AWCOB0iPdrknfb6AKBggqhkjOPQMBAaE0AzIABJLZCUtkaxiPsguGULH5NxVSpdSraU08X+yPizrXODuiXtK3JguVnfO8Ii2pFEN8iQ=="; // priv192v1B.pem
        byte[] keyData = Convert.FromBase64String(privPemB64);
        string szkeyData = ByteArrayToHexString(keyData);
        //openssl dgst -sha256 -sign priv192v1B.pem -out cmdlineSig192v1B.bin < ./testCardDataB.bin
        string sigKey = GetIndexedElementFromAsn1ObjectAsString(szkeyData, 1, true);  // D is the Private Key
        OpenSSL.Core.BigNumber dNumber = OpenSSL.Core.BigNumber.FromHexString(sigKey);
        string szmsg = "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223";
        byte[] message = HexStringToByteArray(szmsg);
        System.Security.Cryptography.SHA256 mySHA256 = System.Security.Cryptography.SHA256Managed.Create();
        byte[] hash = mySHA256.ComputeHash(message);
        OpenSSL.Crypto.MessageDigestContext md_ctx = new OpenSSL.Crypto.MessageDigestContext(OpenSSL.Crypto.MessageDigest.ECDSA);
        //byte[] digest = md_ctx.Digest(message); // try this in case the hash happens automagically - NO
        byte[] digest = md_ctx.Digest(hash);
        OpenSSL.Core.Asn1Object curveObject = new OpenSSL.Core.Asn1Object("prime192v1");
        OpenSSL.Crypto.EC.Key key = OpenSSL.Crypto.EC.Key.FromCurveName(curveObject);
        var rc = key.GL_SetPrivateKey(dNumber);
        key.GenerateKey(); // ec_key_simple_generate_key uses existing private key
        var check = key.CheckKey(); // true
        /* create signature */
        byte[] sigBytes = new byte[key.Size];
        var sigSize = key.Sign(
            0,                 // type???
            digest,            // md_ctx.Digest(hash)
            /*out*/ sigBytes); // sigBytes gets filled with the signature
        if (null == sigBytes)
        {
            PrintToFeedback("Signature generation failed");
        }
        else
        {
            Array.Resize(ref sigBytes, (int)sigSize); // needed for self verify!
            PrintToFeedback("msg: " + szmsg);
            PrintToFeedback("sig: " + ByteArrayToHexString(sigBytes));
            File.WriteAllBytes("testCardDataB.bin", HexStringToByteArray(szmsg));
            File.WriteAllBytes("testCardSigB.bin", sigBytes);
            bool selfVerify = key.Verify(0, digest, sigBytes);
            PrintToFeedback("Self Verify: " + selfVerify.ToString());
        }
    }

其中GL_SetPrivateKey()是我添加到ManagedOpenSSL:key.cs的内容:

public int GL_SetPrivateKey(BigNumber pNewKey)
{
  return Native.EC_KEY_set_private_key(ptr, pNewKey.Handle);
}

GetIndexedElementFromAsn1ObjectAsString正确解析:

0 1
1 #cad7b30feac958844cfd5e331fc0582381d223ddae49df6f
2 [0]1.2.840.10045.3.1.1
3 [1]#0332000492D9094B646B188FB20B8650B1F9371552A5D4AB694D3C5FEC8F8B3AD7383BA25ED2B7260B959DF3BC222DA914437C89

相比于命令行:

$ openssl asn1parse -inform PEM -dump  < ./priv192v1B.pem
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 - ca d7 b3 0f ea c9 58 84-4c fd 5e 33 1f c0 58 23   ......X.L.^3..X#
  0010 - 81 d2 23 dd ae 49 df 6f-                          ..#..I.o
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 92 d9 09 4b 64 6b-18 8f b2 0b 86 50 b1 f9   .....Kdk.....P..
  0010 - 37 15 52 a5 d4 ab 69 4d-3c 5f ec 8f 8b 3a d7 38   7.R...iM<_...:.8
  0020 - 3b a2 5e d2 b7 26 0b 95-9d f3 bc 22 2d a9 14 43   ;.^..&....."-..C
  0030 - 7c 89                                             |.

这是PrintToFeedback输出:

Duplicating ecdsa_example.sh IN OPENSSL...
msg: 0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223
sig: 3036021900B443A7B77E71FF1054F417AD76FC2120159B0E070B7E008B021900DDE7DC267152BACD049229B32C002560F20DE512E5B0209F
Self Verify: True

全局是:

  • 从priv〜.pem中提取D
  • 设置ECDSA曲线并导出密钥
  • 将密钥的私钥从priv〜.pem设置为D
  • 进行签名
  • 调整数组大小-如果没有此步骤,自我验证就会失败
  • 验证签名
  • 保存数据以进行命令行验证

以下是输出文件:

-rwxrwx---+ 1 Larry Larry 35 Sep  4 09:29 testCardData.bin
000000 04 01 02 03 04 05 80 01 49 54 50 31 01 00 01 00
000010 00 02 fa f0 fe 01 01 00 00 00 00 00 00 00 00 00
000020 00 00 01
000023
-rwxrwx---+ 1 Larry Larry 54 Sep  4 09:29 testCardSig.bin
000000 30 34 02 18 37 f5 75 fd dc 0f 80 8a 46 6d 24 46
000010 70 13 1e 50 42 82 c0 67 65 37 09 49 02 18 5e b6
000020 6f 0f d7 ea 14 d0 b9 6a 1e 88 56 a2 e5 6c 8b f0
000030 8d 7f 47 74 1f 8e

.Net的签名采用二进制PEM格式,就像命令行中的签名一样:

$ od -t x1 -A x cmdlineSig192v1B.bin
000000 30 35 02 18 6c dc af 35 9f 22 7e df 8e 49 77 91
000010 ab 07 a6 1d 7f d2 53 ee af a9 1e 44 02 19 00 d7
000020 e4 ef 25 e7 d9 02 cb fb be 23 86 23 d2 90 f2 2f
000030 dd 68 b3 10 dc c9 53

我想我的主要问题是,我是否认为私钥应该以这种方式使用,即登录.Net并使用外部创建的公钥进行外部验证,我是否能摆脱?如果没有:

  • 您应该如何在OpenSSL.Net中设置私钥?
  • Key.Sign()中的类型参数是什么?
  • 如何将公共密钥转储到.Net中?

开火,谢谢。

0 个答案:

没有答案