RSA SHA256签名生成和验证

时间:2017-02-05 21:23:21

标签: c# go rsa bouncycastle sha256

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

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

细节:

公钥/私钥对是从Online RSA Key Generator

生成的示例

哈希字节数组是使用SHA265生成的,为简单起码而硬编码。

我为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#代码的结果复制到签名变量

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

1 个答案:

答案 0 :(得分:1)

当您使用sig.GenerateSignature()计算签名时,BouncyCastle将自动计算邮件的sha256。你应该传递给sig.BlockUpdate()的是你希望sha256和rsa签名的消息。所以基本上你已经在你的消息上使用了sha256两次了。

您可以在此处看到:https://play.golang.org/p/mplEnmNbs9。在第27行,我在你的hashBytes上添加了对sha256的另一个调用,然后将其传递给rsa.VerifyPKCS1v15()并且工作正常。