简体   繁体   English

使用 .NET 库 ECDsaCng 验证 BouncyCastle ECDsa 签名

[英]Verify BouncyCastle ECDsa signature with .NET libraries ECDsaCng

An existing system generated signatures using Bouncy Castle (.NET) and I need to verify these existing signatures using the Microsoft ECDsaCng class.现有系统使用 Bouncy Castle (.NET) 生成签名,我需要使用 Microsoft ECDsaCng 类验证这些现有签名。

Consider the following code that attempts to do this:考虑以下尝试执行此操作的代码:

   public static void InterchangeTest()
{
    //AsymmetricCipherKeyPair bKeyPair_0 = Crypto.GenerateEcdsaKey();
    String sPassPhrase = "bob is your uncle";
    byte[] bPassPhrase = new UTF8Encoding(false).GetBytes(sPassPhrase);

    int SaltBitSize = 128;
    int EcdsaBitLength = 521;

    byte[] bSalt = new byte[SaltBitSize / 8];
    new SecureRandom().NextBytes(bSalt);

    if (EcdsaBitLength != 192 && EcdsaBitLength != 256 && EcdsaBitLength != 521)
    {
        throw new ArgumentException("Invalid EcdsaBitLength length () " + EcdsaBitLength + " ECDSA supports 192, 256, and 521 bit lengths.");
    }

    string curveName = "P-" + EcdsaBitLength.ToString();
    X9ECParameters ecP = NistNamedCurves.GetByName(curveName);
    ECDomainParameters ecSpec = new ECDomainParameters(ecP.Curve, ecP.G, ecP.N, ecP.H, ecP.GetSeed());
    IAsymmetricCipherKeyPairGenerator g = GeneratorUtilities.GetKeyPairGenerator("ECDH");
    g.Init(new ECKeyGenerationParameters(ecSpec, new SecureRandom()));
    AsymmetricCipherKeyPair aKeyPair = g.GenerateKeyPair();

    ECPrivateKeyParameters mPrivateKey = (ECPrivateKeyParameters)aKeyPair.Private;
    ECPublicKeyParameters mPublicKey = (ECPublicKeyParameters)aKeyPair.Public;

    byte[] bPrivateKey = ((ECPrivateKeyParameters)aKeyPair.Private).D.ToByteArray();

    String SignerName = "SHA-256withECDSA";
    ISigner bSigner = SignerUtilities.GetSigner(SignerName);
    bSigner.Init(true, aKeyPair.Private);
    bSigner.BlockUpdate(bPassPhrase, 0, bPassPhrase.Length);
    byte[] bouncySignature = bSigner.GenerateSignature();

    ISigner bVerifier = SignerUtilities.GetSigner(SignerName);
    bVerifier.Init(false, aKeyPair.Public);
    bVerifier.BlockUpdate(bPassPhrase, 0, bPassPhrase.Length);
    bool passed = bVerifier.VerifySignature(bouncySignature);
    Console.WriteLine("Verified with Bouncy: " + passed);

    var xmlImport = "<ECDSAKeyValue xmlns='http://www.w3.org/2001/04/xmldsig-more#'>\n"
    + "  <DomainParameters>\n"
    + "    <NamedCurve URN='urn:oid:1.3.132.0.35' />\n"
    + "  </DomainParameters >\n"
    + "   <PublicKey >\n"
    + "     <X Value='" + ((ECPublicKeyParameters)aKeyPair.Public).Q.X.ToBigInteger().ToString() + "' xsi:type='PrimeFieldElemType' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' />\n"
    + "     <Y Value='" + ((ECPublicKeyParameters)aKeyPair.Public).Q.Y.ToBigInteger().ToString() + "' xsi:type='PrimeFieldElemType' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' />\n"
    + "  </PublicKey >\n"
    + " </ECDSAKeyValue>";

    //using (StreamWriter outputFile = new StreamWriter(@"C:\Dev\x2.txt"))
    //{
    //    outputFile.WriteLine(xmlImport);
    //}

    ECDsaCng eccImporter = new ECDsaCng();
    eccImporter.FromXmlString(xmlImport, ECKeyXmlFormat.Rfc4050);

    Console.WriteLine("hash algorithm = " + eccImporter.HashAlgorithm + " Probably " + CngAlgorithm.Sha256);
    Console.WriteLine("Signature algorithm = " + eccImporter.SignatureAlgorithm + " Probably ECDsa");
    Console.WriteLine("After import, key size = " + eccImporter.KeySize + " probably 521");

    try
    {
        if (eccImporter.VerifyData(bPassPhrase, bouncySignature))
        {
            Console.WriteLine("Verified the signature from bouncy castle using .NET");
        }
    }
    catch (CryptographicException e)
    {
        // "The parameter is incorrect"
        Console.WriteLine("Did not verify bouncy signature with .NET because: " + e.Message);
    }


    CngKey msKey = CngKey.Create(CngAlgorithm.ECDsaP521, null, new CngKeyCreationParameters { ExportPolicy = CngExportPolicies.AllowPlaintextArchiving });
    ECDsaCng ms_ecdsaCNG = new ECDsaCng(msKey);

    String xmlExport = ms_ecdsaCNG.ToXmlString(ECKeyXmlFormat.Rfc4050);

    eccImporter = new ECDsaCng();
    eccImporter.FromXmlString(xmlExport, ECKeyXmlFormat.Rfc4050);

    byte[] ms_SignedData = ms_ecdsaCNG.SignData(bPassPhrase);
    Console.WriteLine("Verify .NET signature with .NET: " + ms_ecdsaCNG.VerifyData(bPassPhrase, ms_SignedData));
    Console.WriteLine("Verify .NET signature with imported .NET: " + eccImporter.VerifyData(bPassPhrase, ms_SignedData));

    //Console.WriteLine();
    //Console.WriteLine(xmlExport);
    //Console.WriteLine();

}

Everything works fine until I attempt to verify the signature in with the Microsoft classes, at which point it generates an exception stating that the Parameter is incorrect.一切正常,直到我尝试使用 Microsoft 类验证签名,此时它生成一个异常,指出参数不正确。

any thoughts?有什么想法吗?

Maarten Bodewes is correct. Maarten Bodewes 是正确的。 My problem is that the signature is encoded using BouncyCastly using ASN.1/DER format.我的问题是签名是使用 BouncyCastly 使用 ASN.1/DER 格式编码的。 MS uses an smaller format (I think that it is IEEE P-1393). MS 使用较小的格式(我认为它是 IEEE P-1393)。 So, I wrote this little routine in C# to transform the signatures.所以,我用 C# 编写了这个小例程来转换签名。

public static byte[] ConvertDerToP1393(byte[] data)
{
    byte[] b = new byte[132];
    int totalLength = data[1];
    int n = 0;
    int offset = 4;
    int thisLength = data[offset++];
    if (data[offset] == 0)  {
        // Negative number!
        ++offset;
        --thisLength;
    }
    for (int i= thisLength; i < 66; ++i) {
        b[n++] = 0;
    }
    if (thisLength > 66) {
        System.Console.WriteLine("BAD, first number is too big! " + thisLength);
    } else {
        for (int i = 0; i < thisLength; ++i) {
            b[n++] = data[offset++];
        }
    }
    ++offset;
    thisLength = data[offset++];

    for (int i = thisLength; i < 66; ++i){
        b[n++] = 0;
    }
    if (thisLength > 66) {
        System.Console.WriteLine("BAD, second number is too big! " + thisLength);
    } else {
        for (int i = 0; i < thisLength; ++i) {
            b[n++] = data[offset++];
        }
    }
    return b;
}

Although I have done only limited testing, the code has worked with my tests.尽管我只进行了有限的测试,但代码在我的测试中运行良好。

I convert private Key to public, with VB:我用 VB 将私钥转换为公钥:

Dim Point As Org.BouncyCastle.Math.EC.ECPoint = PrivateKey.Parameters.G.Multiply(PrivateKey.D)
Dim ToPublic = New Org.BouncyCastle.Crypto.Parameters.ECPublicKeyParameters(PrivateKey.AlgorithmName, Point, PrivateKey.PublicKeyParamSet)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM