简体   繁体   English

RSA SHA256 签名生成和验证

[英]RSA SHA256 signature generation and validation

I am generating a RSA signature in C# by using BouncyCastle and validating the signature in Go.我正在通过使用 BouncyCastle 并在 Go 中验证签名在 C# 中生成 RSA 签名。

But for some reason the signature from the C# program will not validate in Go.但出于某种原因,来自 C# 程序的签名不会在 Go 中验证。

The details:细节:

The public/private keypair is an example generated from Online RSA Key Generator公钥/私钥对是从Online RSA Key Generator生成的示例

The hash byte array is one that is generated by using SHA265 and hardcoded for simplicity.哈希字节数组是一种使用 SHA265 生成并为简单起见进行硬编码的数组。

I've tried different signature algorithms for BouncyCastle, played around with key pairs but nothing seems to work.我为 BouncyCastle 尝试了不同的签名算法,使用了密钥对,但似乎没有任何效果。

I've also validated that the byte array of the signature matches between the two languages...我还验证了签名的字节数组在两种语言之间匹配...

Can anyone tell me what I am missing here?谁能告诉我我在这里缺少什么? Or at least how to investigate further?或者至少如何进一步调查?

My C# code to generate the signature我的 C# 代码生成签名

    static void Main(string[] args)
    {
        byte[] hashBytes = new byte[32] { 152, 154, 255, 19, 168, 20, 167, 43, 232, 133, 146, 13, 183, 80, 186, 85, 180, 249, 95, 142, 234, 71, 93, 188, 29, 147, 220, 164, 248, 83, 196, 80 };
        String privateKeyPemStr = @"-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCIw68jARnmvTh+xvMcv5iugtoHXt60NWEebfbghLTFuTlQvK0e
xY5hxnN/uD2UVc/S3QGnBQn0AfynhxlEZkedpYBb5RWoVChGZMHu7hbZukMjByjx
ec0LjtuEQhY4m18XaVNmAQWD/EiROMGTghMwykkQ+SBtx4Gl/O/BB6F4SQIDAQAB
AoGAJLarODFee6OGG/paXvhMC2TTFLFyBVxjAuEwKdtWD9IGQdc0fhM4gqTccofJ
+B0FGiz7+ZMPtfImme5ZaRQv2wx7KOPbOdAyYxC7nLFCHYqDWZJ8/cCoS+hPJFd5
9OeGLGz3QKfEEPtYEAw4+E/UjilYAtRNREkISkYoB9Va8PUCQQDDHMPRSCfXbfZV
ufmlRZj2bH8sjVaSBbJIw+y9HKJ3ORRnKGjtIZ/+z70EwMwtbbQKnl71SruO5HB9
AUTtRka/AkEAs3GWQhplPbuH/fAlaEPy5GQilUNRt76NMsgtIFWPMXnt82cxTUUR
RIKwX7M96WBppPZ2Dy7uLrX8O+3fr6BK9wJATZ0lsBy57JKLiTJ/wmTbIjuqozhe
FZw6fYOiqt+3KSIFobuLcbkMgjp1AG0JS5D2K7swHvdpgMASl0dn+dMY1QJBAIPw
9QbN2bs2dJvnQ9oSfDoq1rLhuOheF/xK68Nmpc8/VBMwwTOLoVK6tWzoopFC7ur4
vX4Uh9WYwkpecab1OakCQD0SCs4zIggA/2NkUx8J5H07/drbm9uH+98EQUvzjTdz
qSW2jJPCA4GYYmtnnDRduukjmkJlbaaTdEH5YLCilF0=
-----END RSA PRIVATE KEY-----";

        StringReader strReader = new StringReader(privateKeyPemStr);
        PemReader pemReader = new PemReader(strReader);
        AsymmetricCipherKeyPair keyPair = (AsymmetricCipherKeyPair)pemReader.ReadObject();
        RsaKeyParameters privateKey = (RsaKeyParameters)keyPair.Private;


        ISigner sig = SignerUtilities.GetSigner("SHA256withRSA");
        sig.Init(true, privateKey);
        sig.BlockUpdate(hashBytes, 0, hashBytes.Length);
        byte[] signedBytes = sig.GenerateSignature();

        var signedStr = Convert.ToBase64String(signedBytes);

        Console.WriteLine(signedStr);
        Console.ReadLine();            
    }

This is my Go code to validate the signature.这是我验证签名的 Go 代码。 I copy the result of the C# code into the signature variable我将 C# 代码的结果复制到签名变量中

func main() {
pubKeyStr := `-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCIw68jARnmvTh+xvMcv5iugtoH
Xt60NWEebfbghLTFuTlQvK0exY5hxnN/uD2UVc/S3QGnBQn0AfynhxlEZkedpYBb
5RWoVChGZMHu7hbZukMjByjxec0LjtuEQhY4m18XaVNmAQWD/EiROMGTghMwykkQ
+SBtx4Gl/O/BB6F4SQIDAQAB
-----END PUBLIC KEY-----`
pemBlockPub, _ := pem.Decode([]byte(pubKeyStr))
pub, _ := x509.ParsePKIXPublicKey(pemBlockPub.Bytes)
publicKey, _ := pub.(*rsa.PublicKey)

signatureStr := "YJxDTSMnFb4uh/orsUjHTHEsW1dkxuStsGP0PmjmObJhog/7OQfWgBcBZ58w0qWoknLGMVBBgZTgJtKq1ZSSTsx9uXhNKEhNEI3a+7ZhmPiHp6JRLbftsEoGKe7FKU8vXkp6Bo90qMOoJz54YI2xue8EA9b5PTgjkGbDbKdimF8="
signatureBytes, err := base64.StdEncoding.DecodeString(signatureStr)
hashBytes := [32]byte{152, 154, 255, 19, 168, 20, 167, 43, 232, 133, 146, 13, 183, 80, 186, 85, 180, 249, 95, 142, 234, 71, 93, 188, 29, 147, 220, 164, 248, 83, 196, 80}

err := rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, hashBytes[:], signatureBytes)

if err != nil {
    fmt.Printf("err: %v\n", err)
} else {
    fmt.Printf("ok")
}

} }

If I use the following code in C# to validate the signature, it is fine.如果我在 C# 中使用以下代码来验证签名,那就没问题了。

        String publicKeyPemStr = @"-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCIw68jARnmvTh+xvMcv5iugtoH
Xt60NWEebfbghLTFuTlQvK0exY5hxnN/uD2UVc/S3QGnBQn0AfynhxlEZkedpYBb
5RWoVChGZMHu7hbZukMjByjxec0LjtuEQhY4m18XaVNmAQWD/EiROMGTghMwykkQ
+SBtx4Gl/O/BB6F4SQIDAQAB
-----END PUBLIC KEY-----";

        strReader = new StringReader(publicKeyPemStr);
        pemReader = new PemReader(strReader);
        RsaKeyParameters publicKey = (RsaKeyParameters)((AsymmetricKeyParameter)pemReader.ReadObject());

        sig = SignerUtilities.GetSigner("SHA256withRSA");
        sig.Init(false, publicKey);
        sig.BlockUpdate(hashBytes, 0, hashBytes.Length);

        if (sig.VerifySignature(signedBytes))
        {
            Console.WriteLine("Ok");
        }
        else
        {
            Console.WriteLine("NOK");
        }

        Console.ReadLine();

Did some additional tests, the following Go code produces a totally different signature string from the C# code although the private key is the same.做了一些额外的测试,下面的 Go 代码产生了与 C# 代码完全不同的签名字符串,尽管私钥是相同的。 Where is the difference??区别在哪里??

func main() {
privKeyStr := `-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCIw68jARnmvTh+xvMcv5iugtoHXt60NWEebfbghLTFuTlQvK0e
xY5hxnN/uD2UVc/S3QGnBQn0AfynhxlEZkedpYBb5RWoVChGZMHu7hbZukMjByjx
ec0LjtuEQhY4m18XaVNmAQWD/EiROMGTghMwykkQ+SBtx4Gl/O/BB6F4SQIDAQAB
AoGAJLarODFee6OGG/paXvhMC2TTFLFyBVxjAuEwKdtWD9IGQdc0fhM4gqTccofJ
+B0FGiz7+ZMPtfImme5ZaRQv2wx7KOPbOdAyYxC7nLFCHYqDWZJ8/cCoS+hPJFd5
9OeGLGz3QKfEEPtYEAw4+E/UjilYAtRNREkISkYoB9Va8PUCQQDDHMPRSCfXbfZV
ufmlRZj2bH8sjVaSBbJIw+y9HKJ3ORRnKGjtIZ/+z70EwMwtbbQKnl71SruO5HB9
AUTtRka/AkEAs3GWQhplPbuH/fAlaEPy5GQilUNRt76NMsgtIFWPMXnt82cxTUUR
RIKwX7M96WBppPZ2Dy7uLrX8O+3fr6BK9wJATZ0lsBy57JKLiTJ/wmTbIjuqozhe
FZw6fYOiqt+3KSIFobuLcbkMgjp1AG0JS5D2K7swHvdpgMASl0dn+dMY1QJBAIPw
9QbN2bs2dJvnQ9oSfDoq1rLhuOheF/xK68Nmpc8/VBMwwTOLoVK6tWzoopFC7ur4
vX4Uh9WYwkpecab1OakCQD0SCs4zIggA/2NkUx8J5H07/drbm9uH+98EQUvzjTdz
qSW2jJPCA4GYYmtnnDRduukjmkJlbaaTdEH5YLCilF0=
-----END RSA PRIVATE KEY-----`

pemBlockPriv, _ := pem.Decode([]byte(privKeyStr))
privateKey, _ := x509.ParsePKCS1PrivateKey(pemBlockPriv.Bytes)

hashBytes := [32]byte{152, 154, 255, 19, 168, 20, 167, 43, 232, 133, 146, 13, 183, 80, 186, 85, 180, 249, 95, 142, 234, 71, 93, 188, 29, 147, 220, 164, 248, 83, 196, 80}

signatureByte, _ := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, hashBytes[:])
signatureStr := base64.StdEncoding.EncodeToString(signatureByte)

fmt.Printf("%v\n", signatureStr)
}

BouncyCastle will automatically calculate the sha256 of your message when you calculate the signature with sig.GenerateSignature().当您使用 sig.GenerateSignature() 计算签名时,BouncyCastle 将自动计算您的消息的 sha256。 What you should pass into sig.BlockUpdate() is the message that you want sha256 and rsa signed.您应该传递给 sig.BlockUpdate() 的是您希望 sha256 和 rsa 签名的消息。 So essentially you've used sha256 twice on your message.所以基本上你已经在你的消息中使用了两次 sha256。

You can see this here: https://play.golang.org/p/mplEnmNbs9 .您可以在此处查看: https : //play.golang.org/p/mplEnmNbs9 On line 27 I added another call to sha256 on your hashBytes and then passed that to rsa.VerifyPKCS1v15() and works fine.在第 27 行,我在您的 hashBytes 上添加了另一个对 sha256 的调用,然后将其传递给 rsa.VerifyPKCS1v15() 并且工作正常。

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

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