RSA SHA256签名生成和验证

huangapple go评论91阅读模式
英文:

RSA SHA256 signature generation and validation

问题

我正在使用BouncyCastle在C#中生成RSA签名,并在Go中验证签名。

但由于某种原因,来自C#程序的签名无法在Go中验证。

具体情况如下:

公钥/私钥对是从在线RSA密钥生成器生成的示例。

哈希字节数组是使用SHA256生成的,并为简单起见进行了硬编码。

我尝试了不同的BouncyCastle签名算法,尝试了不同的密钥对,但似乎都不起作用。

我还验证了两种语言之间的签名字节数组是否匹配...

有人能告诉我在这里漏掉了什么吗?或者至少如何进一步调查?

以下是我用于生成签名的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();            
}

这是我用于验证签名的Go代码。我将C#代码的结果复制到了signature变量中:

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")
    }
}

如果我在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();

经过一些额外的测试,以下Go代码生成的签名字符串与C#代码完全不同,尽管私钥是相同的。有什么区别吗?

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)
}

希望这些信息对你有所帮助!

英文:

I am generating a RSA signature in C# by using BouncyCastle and validating the signature in Go.

But for some reason the signature from the C# program will not validate in Go.

The details:

The public/private keypair is an example generated from Online RSA Key Generator

The hash byte array is one that is generated by using SHA265 and hardcoded for simplicity.

I've tried different signature algorithms for BouncyCastle, played around with key pairs but nothing seems to work.

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

    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. I copy the result of the C# code into the signature variable

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.

        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. 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)
}

答案1

得分: 1

BouncyCastle在使用sig.GenerateSignature()计算签名时,会自动计算消息的sha256值。在调用sig.BlockUpdate()时,你应该传入要进行sha256和rsa签名的消息。所以实质上,你对消息使用了两次sha256。

你可以在这里查看示例:https://play.golang.org/p/mplEnmNbs9。在第27行,我对hashBytes再次调用了sha256,并将其传递给rsa.VerifyPKCS1v15(),结果正常。

英文:

BouncyCastle will automatically calculate the sha256 of your message when you calculate the signature with sig.GenerateSignature(). What you should pass into sig.BlockUpdate() is the message that you want sha256 and rsa signed. So essentially you've used sha256 twice on your message.

You can see this here: 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.

huangapple
  • 本文由 发表于 2017年2月6日 05:23:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/42057466.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定