简体   繁体   English

在在线编译器中运行的 C# ECDSA 签名失败

[英]C# ECDSA signature running in an online compiler fails

I'm running this code successfully on my Windows machine (Win 10 x64, running dotnet 4.7.2).我在我的 Windows 机器(Win 10 x64,运行 dotnet 4.7.2)上成功运行了此代码。 It generates an EC keypair ("P-256"), hashes the plaintext with SHA-256, signs the hash with the ec private key and verifies the signature against the hashed plaintext with the ec public key.它生成一个 EC 密钥对(“P-256”),使用 SHA-256 对明文进行哈希处理,使用 ec 私钥对 hash 进行签名,并使用 ec 公钥根据哈希明文验证签名。

I'm getting this output so everything works fine:我得到这个 output 所以一切正常:

EC signature curve secp256r1 / P-256 string
dataToSign: The quick brown fox jumps over the lazy dog
* * * sign the plaintext with the EC private key * * *
EC keysize: 256
signature (Base64): cwLBRSt1vtO33tHWcTdx1OTu9lBFXHEJgvdRyDUynLLE5eMakUZUAKLwaJvYoS7NBylx2Zz0+G6dvgJ6xv5qNA==
* * *verify the signature against hash of plaintext with the EC public key * * *
signature verified: True

Now I'm trying to find any online compiler that is been able to run the code.现在我正在尝试找到任何能够运行代码的在线编译器。 My favorite compiler ( https://repl.it/ , Mono C# compiler version 6.8.0.123, full code: https://repl.it/@javacrypto/EcSignatureFull#main.cs ) is running into this error: My favorite compiler ( https://repl.it/ , Mono C# compiler version 6.8.0.123, full code: https://repl.it/@javacrypto/EcSignatureFull#main.cs ) is running into this error:

Unhandled Exception:
System.NotImplementedException: The method or operation is not implemented.
  at EcSignatureString.Main () [0x00036] in <13e2ad358a924efc874a89efad35ffe7>:0
[ERROR] FATAL UNHANDLED EXCEPTION: System.NotImplementedException: The method or operation is not implemented.
  at EcSignatureString.Main () [0x00036] in <13e2ad358a924efc874a89efad35ffe7>:0
exit status 1

Using another platform ( https://dotnetfiddle.net/ , Compiler .net 5, full code: https://dotnetfiddle.net/lSPpjz ) is giving this similar error:使用另一个平台( https://dotnetfiddle.net/ ,编译器 .net 5,完整代码: https://dotnetfiddlenet给出了类似的错误:

Unhandled exception. System.PlatformNotSupportedException: Windows Cryptography Next Generation (CNG) is not supported on this platform.
   at System.Security.Cryptography.ECDsaCng..ctor(Int32 keySize)
   at EcSignatureString.Main()
Command terminated by signal 6

So my question: is there any online compiler available that is been able to run the code?所以我的问题是:是否有任何可用的在线编译器能够运行代码?

I assume my question might be a slice off-topic for SO - in this case - is there any other stackexchange-site that would be a better place for my question?我认为我的问题可能与 SO 无关——在这种情况下——是否还有其他 stackexchange-site 可以更好地解决我的问题?

Warning : the following code has no exception handling and is for educational purpose only:警告:以下代码没有异常处理,仅用于教育目的:

using System;
using System.Security.Cryptography;

class EcSignatureString {
    static void Main() {

    Console.WriteLine("EC signature curve secp256r1 / P-256 string");
    string dataToSignString = "The quick brown fox jumps over the lazy dog";
    byte[] dataToSign = System.Text.Encoding.UTF8.GetBytes(dataToSignString);
    Console.WriteLine("dataToSign: " + dataToSignString);
    try {
        Console.WriteLine("\n* * * sign the plaintext with the EC private key * * *");

        ECDsaCng ecDsaKeypair = new ECDsaCng(256);
        Console.WriteLine("EC keysize: " + ecDsaKeypair.KeySize);

        byte[] hashedData = null;
        byte[] signature = null;
        // create new instance of SHA256 hash algorithm to compute hash
        HashAlgorithm hashAlgo = new SHA256Managed();
        hashedData = hashAlgo.ComputeHash(dataToSign);

        // sign Data using private key
        signature = ecDsaKeypair.SignHash(hashedData);
        string signatureBase64 = Convert.ToBase64String(signature);
        Console.WriteLine("signature (Base64): " + signatureBase64);

        // get public key from private key
        string ecDsaPublicKeyParametersXml = ecDsaKeypair.ToXmlString(ECKeyXmlFormat.Rfc4050);

        // verify
        Console.WriteLine("\n* * *verify the signature against hash of plaintext with the EC public key * * *");
        ECDsaCng ecDsaVerify = new ECDsaCng();
        bool signatureVerified = false;
        ecDsaVerify.FromXmlString(ecDsaPublicKeyParametersXml, ECKeyXmlFormat.Rfc4050);
        signatureVerified = ecDsaVerify.VerifyHash(hashedData, signature);
        Console.WriteLine("signature verified: " + signatureVerified);
        }
        catch(ArgumentNullException) {
            Console.WriteLine("The data was not signed or verified");
        }
    }
}

Microsoft has decided that encryption and hashing must be fully delegated to the OS (in .NET Framework it was half and half), so now .NET 5 (and .NET Core) has multiple backends for encryption (for example for ECDsa it has ECDsaCng that uses Windows services and ECDsaOpenSsl for Linux/MacOs that uses OpenSsl (see MSDN ) Microsoft has decided that encryption and hashing must be fully delegated to the OS (in .NET Framework it was half and half), so now .NET 5 (and .NET Core) has multiple backends for encryption (for example for ECDsa it has ECDsaCng that uses Windows使用 OpenSsl 的 Linux/MacO 服务和ECDsaOpenSsl (请参阅MSDN

Now... the solution for your problem is to use the ECDsa class and let it select its backend.现在......您的问题的解决方案是使用ECDsa class 并让它 select 作为其后端。 There are some problems with it.它有一些问题。 You can't easily export the keys to xml format, nor you can easily export them to PEM format.您不能轻松地将密钥导出为 xml 格式,也不能轻松地将它们导出为 PEM 格式。 You can easily export them to a byte[] , and you can easily import them from PEM format.您可以轻松地将它们导出为byte[] ,并且可以轻松地从 PEM 格式导入它们。 This isn't really a big problem, because rarely you'll need to generate keys, and normally your program receives its keys from an external source, or if it generates them itself, it can save them to binary format to reuse them later.这并不是一个真正的大问题,因为您很少需要生成密钥,并且通常您的程序从外部源接收其密钥,或者如果它自己生成它们,它可以将它们保存为二进制格式以便以后重用。

var dataToSignString = "Hello world!";
var dataToSign = Encoding.UTF8.GetBytes(dataToSignString);

Console.WriteLine("dataToSign: " + dataToSignString);

try
{
    Console.WriteLine("\n* * * sign the plaintext with the EC private key * * *");

    var ecDsaKeypair = ECDsa.Create(ECCurve.NamedCurves.nistP256);

    // Normally here:
    //ecDsaKeypair.ImportFromPem()

    Console.WriteLine("EC keysize: " + ecDsaKeypair.KeySize);

    byte[] hashedData = null;
    byte[] signature = null;
    // create new instance of SHA256 hash algorithm to compute hash
    HashAlgorithm hashAlgo = new SHA256Managed();
    hashedData = hashAlgo.ComputeHash(dataToSign);

    // sign Data using private key
    signature = ecDsaKeypair.SignHash(hashedData);
    string signatureBase64 = Convert.ToBase64String(signature);
    Console.WriteLine("signature (Base64): " + signatureBase64);

    // get public key from private key
    string ecDsaPublicKeyParameters = Convert.ToBase64String(ecDsaKeypair.ExportSubjectPublicKeyInfo());

    // verify
    Console.WriteLine("\n* * *verify the signature against hash of plaintext with the EC public key * * *");

    var ecDsaVerify = ECDsa.Create(ECCurve.NamedCurves.nistP256);
    bool signatureVerified = false;

    // Normally here:
    //ecDsaKeypair.ImportFromPem()
    var publicKey = Convert.FromBase64String(ecDsaPublicKeyParameters);
    ecDsaVerify.ImportSubjectPublicKeyInfo(publicKey, out _);

    signatureVerified = ecDsaVerify.VerifyHash(hashedData, signature);
    Console.WriteLine("signature verified: " + signatureVerified);
}
catch (ArgumentNullException)
{
    Console.WriteLine("The data was not signed or verified");
}

About the From/ToXmlFormat , the current comment on them on the github of .NET Core is :关于From/ToXmlFormat当前对 .NET Core 的 github 的评论是

// There is currently not a standard XML format for ECC keys, so we will not implement the default
// To/FromXmlString so that we're not tied to one format when a standard one does exist. Instead we'll
// use an overload which allows the user to specify the format they'd like to serialize into.

Mmmh from some tests done, exporting in PEM format seems to be quite easy:嗯,从完成的一些测试来看,以 PEM 格式导出似乎很容易:

public static IEnumerable<string> Split(string str, int chunkSize)
{
    for (int i = 0; i < str.Length; i += chunkSize)
    {
        yield return str.Substring(i, Math.Min(chunkSize, str.Length - i));
    }
}

and then接着

string b64privateKey = Convert.ToBase64String(ecDsaKeypair.ExportPkcs8PrivateKey());
b64privateKey = string.Join("\r\n", Split(b64privateKey, 64));
string pemPrivateKey = "-----BEGIN PRIVATE KEY-----\r\n" + b64privateKey + "\r\n-----END PRIVATE KEY-----";

or或者

string b64publicKey = Convert.ToBase64String(ecDsaKeypair.ExportSubjectPublicKeyInfo());
b64publicKey = string.Join("\r\n", Split(b64publicKey, 64));
string pemPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" + b64publicKey + "\r\n-----END PUBLIC KEY-----";

(note that I had to split the string manually in blocks of 64 characters, that is the exact number given in the rfc7468, because Convert.ToBase64String() supports only the 76 line length) (请注意,我必须手动将字符串拆分为 64 个字符的块,这是 rfc7468 中给出的确切数字,因为Convert.ToBase64String()仅支持 76 行长度)

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

相关问题 使用C#中的Bouncy Castle验证ECDSA签名 - Verifying ECDSA signature with Bouncy Castle in C# ECDSA 签名的 PDF 无法使用 iText 7 (C#) 进行签名验证,但使用 Adobe Reader DC 成功 - ECDSA signed PDF fails signature verification with iText 7 (C#), but succeeds with Adobe Reader DC 带有 C# 和 Bouncy Castle 的 ECDSA 签名与 MS ECDsa 签名不匹配 - ECDSA signature with C# and Bouncy Castle does not match MS ECDsa signature C#无法从OpenSSL控制台行命令验证ECDSA(384位)base 64数字签名 - C# fails to verify ECDSA (384-bit) base 64 digital signature from OpenSSL console line commands 如何在 C# 中使用 SHA256 签名对 ECDSA 进行签名和验证 - How to sign and verify an ECDSA with SHA256 signature in C# 使用BouncyCastle进行数字签名验证 - 带有SHA 256,C#的ECDSA - Digital Signature Verification using BouncyCastle - ECDSA with SHA 256, C# C# 使用带有 SHA256 证书的 ECDSA 进行签名验证 - C# signature verification using ECDSA with SHA256 certificate 从 ECDSA 签名 signedxml c# 中提取 r 和 s - Extract r and s from ECDSA signature signedxml c# ECDSA 签名生成 KeyPair Java 到 C# - JcaPEMKeyConverter() - ECDSA signature generation KeyPair Java to C# - JcaPEMKeyConverter() ECDSA 使用公钥和 Java 签名在 C# 中验证签名 - ECDSA Verify Signature in C# using public key and signature from Java
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM