我通过使用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)
}
答案 0 :(得分:1)
当您使用sig.GenerateSignature()计算签名时,BouncyCastle将自动计算邮件的sha256。你应该传递给sig.BlockUpdate()的是你希望sha256和rsa签名的消息。所以基本上你已经在你的消息上使用了sha256两次了。
您可以在此处看到:https://play.golang.org/p/mplEnmNbs9。在第27行,我在你的hashBytes上添加了对sha256的另一个调用,然后将其传递给rsa.VerifyPKCS1v15()并且工作正常。