转换Python(pyelliptic,openssl)ecc键并签名到c#(BouncyCastle?)

时间:2013-04-12 11:29:09

标签: c# cryptography openssl bouncycastle pyopenssl

项目https://github.com/Bitmessage/PyBitmessage使用库https://github.com/yann2192/pyelliptic来使用openssl。

pyelliptic测试用例:

#!/usr/bin/python
import pyelliptic
from pyelliptic import arithmetic as a

#privkey  = a.changebase('02ca0020215c5516f277ac6246cbbaad81cd848328bf9bf11e98959e2b991191a71ad81a',16,256)
pubkey    = a.changebase('02ca0020012e0e59b564c025b15a587da5d33d3599df5e04deca47c783eaed25ebe5af46002032e00af993efc71a2c033a45187918f5b3c03e0e7bb539cecdc0aaa237717db1',16,256)
signature = a.changebase('30450221008538ac52dbe2b67148e99f23ad78b4c6c4939a26d789ece590c6f1e44a271454022027d4a09e5e74bb3445019a557bd2202154d2510a4df939b9f4645b311255ee37',16,256)

ecc = pyelliptic.ECC(curve='secp256k1',pubkey=pubkey)
print ecc.verify(signature,'hello')

我将PyBitmessage移植到c#https://github.com/sharpbitmessage/SharpBitmessage/。对于openssl,我使用BouncyCastle。

我的测试用例是(写错):

using System;
using System.Text;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Sec;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Signers;
using Org.BouncyCastle.Utilities.Encoders;

namespace ConsoleApplication2
{
internal class Program
{
    //private static readonly byte[] _privkey  = "02ca0020215c5516f277ac6246cbbaad81cd848328bf9bf11e98959e2b991191a71ad81a".HexToBytes();
    private static readonly byte[] _pubkey =
        Hex.Decode(
            "02ca0020012e0e59b564c025b15a587da5d33d3599df5e04deca47c783eaed25ebe5af46002032e00af993efc71a2c033a45187918f5b3c03e0e7bb539cecdc0aaa237717db1");

    private static readonly byte[] _signature =
        Hex.Decode(
            "30450221008538ac52dbe2b67148e99f23ad78b4c6c4939a26d789ece590c6f1e44a271454022027d4a09e5e74bb3445019a557bd2202154d2510a4df939b9f4645b311255ee37");

    private static readonly byte[] _hello = Encoding.ASCII.GetBytes("hello");

    private static byte[] ConvertKeyFormat(byte[] k)
    {
        // convert key to 04012e0e59b564c025b15a587da5d33d3599df5e04deca47c783eaed25ebe5af4632e00af993efc71a2c033a45187918f5b3c03e0e7bb539cecdc0aaa237717db1
        byte[] result = new byte[k.Length-4+1-2];
        result[0] = 4;
        Buffer.BlockCopy(k,4     ,result,1 ,32);
        Buffer.BlockCopy(k,4+32+2,result,33,32);
        return result;
    }

    private static void Main()
    {
        var signer = new ECDsaSigner();

        X9ECParameters secp256K1 = SecNamedCurves.GetByName("secp256k1");
        ECDomainParameters ecParams = new ECDomainParameters(secp256K1.Curve, secp256K1.G, secp256K1.N, secp256K1.H);
        ECPublicKeyParameters param = new ECPublicKeyParameters(ecParams.Curve.DecodePoint(ConvertKeyFormat(_pubkey)), ecParams);

        signer.Init(false, param);

        DerSequence seq = (DerSequence)(new Asn1InputStream(_signature)).ReadObject();
        DerInteger r = (DerInteger)seq[0];
        DerInteger s = (DerInteger)seq[1];

        Console.WriteLine(signer.VerifySignature(_hello, r.Value, s.Value));
    }
}
}

如何在c#中验证来自pyelliptic的签名?

1 个答案:

答案 0 :(得分:0)

我拒绝BouncyCastle支持OpenSSL。

下面的工作代码(注释是来自pyelliptic的python代码):

using System;
using System.Text;
using OpenSSL.Core; // I get Native.cs from http://openssl-net.sourceforge.net/
using Org.BouncyCastle.Utilities.Encoders; // only for Hex.Decode

namespace openssl
{
class Program
{
    private static readonly byte[] _signature =
        Hex.Decode(             "30450221008538ac52dbe2b67148e99f23ad78b4c6c4939a26d789ece590c6f1e44a271454022027d4a09e5e74bb3445019a557bd2202154d2510a4df939b9f4645b311255ee37");

    private static readonly byte[] _hello = Encoding.ASCII.GetBytes("hello");

    static void Main(string[] args)
    {
//curve    = pubkey[0:2])[0]                      !!! 714
//tmplen1  = unpack('!H', pubkey[2:4])[0]         !!!  32
//pubkey_x = pubkey[4:4 + tmplen1]
//tmplen2  = unpack('!H', pubkey[4 + tmplen1:4 + tmplen1 + 2])[0]
//pubkey_y = pubkey[4 + tmplen1 + 2:4 + tmplen1 + 2 + tmplen2]

    //private static readonly byte[] _pubkey =
    //  Hex.Decode(
    //      "02ca" +
    //      "0020" +
    //      "012e0e59b564c025b15a587da5d33d3599df5e04deca47c783eaed25ebe5af46" +    !!!!!
    //      "0020" +
    //      "32e00af993efc71a2c033a45187918f5b3c03e0e7bb539cecdc0aaa237717db1");    !!!!!

        string pubkey_x = "012e0e59b564c025b15a587da5d33d3599df5e04deca47c783eaed25ebe5af46";
        string pubkey_y = "32e00af993efc71a2c033a45187918f5b3c03e0e7bb539cecdc0aaa237717db1";

//digest = OpenSSL.malloc(0, 64)
//dgst_len = OpenSSL.pointer(OpenSSL.c_int(0))
        byte[] digest = new byte[64];
        uint dgst_len = 0;

//key = OpenSSL.EC_KEY_new_by_curve_name(curve)
//if key == 0:
//  raise Exception("[OpenSSL] EC_KEY_new_by_curve_name FAIL ...")
        IntPtr key = Native.EC_KEY_new_by_curve_name(714);

//pub_key_x = OpenSSL.BN_bin2bn(pubkey_x, len(pubkey_x), 0)
//pub_key_y = OpenSSL.BN_bin2bn(pubkey_y, len(pubkey_y), 0)

        IntPtr pub_key_x;
        Native.BN_hex2bn(out pub_key_x, Encoding.ASCII.GetBytes(pubkey_x));

        IntPtr pub_key_y;
        Native.BN_hex2bn(out pub_key_y, Encoding.ASCII.GetBytes(pubkey_y));

//group = OpenSSL.EC_KEY_get0_group(key)
        IntPtr group = Native.EC_KEY_get0_group(key);
//pub_key = OpenSSL.EC_POINT_new(group)
        IntPtr pub_key = Native.EC_POINT_new(group);

//if (OpenSSL.EC_POINT_set_affine_coordinates_GFp(group, pub_key, pub_key_x, pub_key_y, 0)) == 0:       !!!!!!!!!
//  raise Exception("[OpenSSL] EC_POINT_set_affine_coordinates_GFp FAIL ...")
        if(Native.EC_POINT_set_affine_coordinates_GFp(group, pub_key, pub_key_x, pub_key_y, IntPtr.Zero)==0)
            throw new Exception("[OpenSSL] EC_POINT_set_affine_coordinates_GFp FAIL ...");

//if (OpenSSL.EC_KEY_set_public_key(key, pub_key)) == 0:
//  raise Exception("[OpenSSL] EC_KEY_set_public_key FAIL ...")
        if (Native.EC_KEY_set_public_key(key, pub_key) == 0)
            throw new Exception("[OpenSSL] EC_KEY_set_public_key FAIL ...");

//if (OpenSSL.EC_KEY_check_key(key)) == 0:
//  raise Exception("[OpenSSL] EC_KEY_check_key FAIL ...")
        if (Native.EC_KEY_check_key(key) == 0)
            throw new Exception("[OpenSSL] EC_KEY_check_key FAIL ...");

//md_ctx = OpenSSL.EVP_MD_CTX_create()
        var md_ctx = Native.EVP_MD_CTX_create();
//OpenSSL.EVP_MD_CTX_init(md_ctx)
        Native.EVP_MD_CTX_init(md_ctx);
//OpenSSL.EVP_DigestInit(md_ctx, OpenSSL.EVP_ecdsa())
        Native.EVP_DigestInit_ex(md_ctx, Native.EVP_ecdsa(), IntPtr.Zero);
//if (OpenSSL.EVP_DigestUpdate(md_ctx, inputb, len(inputb))) == 0:
//  raise Exception("[OpenSSL] EVP_DigestUpdate FAIL ...")
        if (Native.EVP_DigestUpdate(md_ctx, _hello, (uint)_hello.Length)==0)
            throw new Exception("[OpenSSL] EVP_DigestUpdate FAIL ...");
//OpenSSL.EVP_DigestFinal(md_ctx, digest, dgst_len)
        Native.EVP_DigestFinal_ex(md_ctx, digest, ref dgst_len);

//ret = OpenSSL.ECDSA_verify(0, digest, dgst_len.contents, sig, len(sig), key)
        //key.Verify(null, _signature);
        int ret = Native.ECDSA_verify(0, digest, (int) dgst_len, _signature, _signature.Length, key);

        Console.WriteLine(ret == 1);

        Console.ReadKey();

        //  todo free memory from openssl resource!!!
    }
}

}