显然(!).NET和Mono之间的签名不一致;单声道签名不是幂等的

时间:2015-09-23 17:09:58

标签: c# mono cryptoapi

Google云端存储提供用于生成签名网址的Java,C#代码示例:

https://cloud.google.com/storage/docs/access-control?hl=en#signing-code-csharp

我正在使用代码示例。使用相同的服务帐户|密钥,存储桶和对象,Java代码和C#代码(在Windows上)工作。当我在Mono / Linux上尝试C#代码时,它不起作用。错误是:

Code: SignatureDoesNotMatch
Message: The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.

注入一些调试代码可以证实这个错误。

以下是执行签名的扩充方法:

private String signString(String stringToSign)  {
    if (key == null) throw new Exception("Certificate not initialized");
    CspParameters cp = new CspParameters(
        24,
        "Microsoft Enhanced RSA and AES Cryptographic Provider",
        ((RSACryptoServiceProvider)key.PrivateKey).CspKeyContainerInfo.KeyContainerName
        );
    RSACryptoServiceProvider provider = new RSACryptoServiceProvider(cp);
    byte[] buffer = Encoding.UTF8.GetBytes(stringToSign);
    byte[] rawSignature = provider.SignData(buffer, CryptoConfig.MapNameToOID("SHA256"));
    Console.WriteLine ("signature == ");
    Console.WriteLine (BitConverter.ToString(rawSignature).Replace("-", string.Empty));
    return Convert.ToBase64String(rawSignature);
}

我希望(可能不正确)重复调用带有相同字符串值的signString,将返回相同的rawSignature和结果。在Java和Windows上,这是事实。在Mono上,值会发生变化

String testString="helloworld";
Console.WriteLine("Signing '" + testString + "' == " + this.signString(testString));
Console.WriteLine("Signing '" + testString + "' == " + this.signString(testString));
Console.WriteLine("Signing '" + testString + "' == " + this.signString(testString));

返回,缩写结果:

signature == 
4415768E8E2FB862...
Signing 'helloworld' == RBV2jo4v...
signature == 
95E589C2F8DAD7ED...
Signing 'helloworld' == leWJwvja...
signature == 
0589E4454FE4FB3A...
Signing 'helloworld' == BYnkRU/k...

使用Java,使用Google示例的类似测试会返回:

rawSignature == 
3E56F09EE9CF7D98...
Signing 'helloworld' == PlbwnunP...
rawSignature == 
3E56F09EE9CF7D98...
Signing 'helloworld' == PlbwnunP...
rawSignature == 
3E56F09EE9CF7D98...
Signing 'helloworld' == PlbwnunP...

我做错了什么?

1 个答案:

答案 0 :(得分:1)

我完全没有使用CspParameters,而是使用PrivateKey的{​​{1}}属性,设法获得一致的结果。我现在的便携式"不幸的是,实现需要一个让我感到紧张的演员表,但它似乎在Windows和Linux上(在Mono 4.0.2下)给出相同的结果,并且这些结果与原始示例代码相同。这是一个在Mono下工作的简短测试应用程序:

X509Certificate2

正如评论中所述,由于未知原因,此在.NET下无法运行 :(

现在我没有尝试使用它来制作任何云存储请求,但我希望它能够正常运行。

在更现代的平台上,您可以使用using System; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text; public class Test { static void Main() { var key = new X509Certificate2("key.p12", "notasecret"); byte[] buffer = Encoding.UTF8.GetBytes("test string"); // This is the slightly dodgy bit... var rsa = (RSACryptoServiceProvider) key.PrivateKey; byte[] signature = rsa.SignData(buffer, "SHA256"); Console.WriteLine(Convert.ToBase64String(signature)); } } 具有SignData方法的事实,并使用GetPrivateRSAKey() extension method获取RSA个实例:

RSA

您也可以在Mono上使用此功能,具体取决于您定位的版本。