显然(!).NET 和 Mono 之间的签名不一致;单声道签名不是幂等的
Apparently (!) inconsistent signing between .NET and Mono; Mono signing is not idempotent
Google Cloud Storage 提供 Java,用于生成签名 URL 的 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,return 会得到相同的 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));
returns,缩略结果:
signature ==
4415768E8E2FB862...
Signing 'helloworld' == RBV2jo4v...
signature ==
95E589C2F8DAD7ED...
Signing 'helloworld' == leWJwvja...
signature ==
0589E4454FE4FB3A...
Signing 'helloworld' == BYnkRU/k...
With Java,使用 Google 样本的类似测试 returns:
rawSignature ==
3E56F09EE9CF7D98...
Signing 'helloworld' == PlbwnunP...
rawSignature ==
3E56F09EE9CF7D98...
Signing 'helloworld' == PlbwnunP...
rawSignature ==
3E56F09EE9CF7D98...
Signing 'helloworld' == PlbwnunP...
我做错了什么?
我完全不使用 CspParameters
,而是使用 X509Certificate2
的 PrivateKey
属性,从而获得了一致的结果。不幸的是,我当前的 "portable" 实现需要强制转换,这让我很紧张,但它似乎在 Windows 和 Linux 上(在 Mono 4.0.2 下)给出了相同的结果,这些是结果与原始示例代码相同。这是一个在 Mono 下运行的简短测试应用程序:
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));
}
}
如评论中所述,由于未知原因,在 .NET 下无法 工作:(
现在我还没有尝试使用它来发出任何云存储请求,但我希望它会起作用。
在更现代的平台上,您可以使用 RSA
具有 SignData
method, and use the GetPrivateRSAKey()
extension method 的事实来获取 RSA
实例:
var rsa = key.GetRSAPrivateKey();
var signature = rsa.SignData(
buffer, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
您也可以在 Mono 上使用它,具体取决于您的目标版本。
Google Cloud Storage 提供 Java,用于生成签名 URL 的 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,return 会得到相同的 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));
returns,缩略结果:
signature ==
4415768E8E2FB862...
Signing 'helloworld' == RBV2jo4v...
signature ==
95E589C2F8DAD7ED...
Signing 'helloworld' == leWJwvja...
signature ==
0589E4454FE4FB3A...
Signing 'helloworld' == BYnkRU/k...
With Java,使用 Google 样本的类似测试 returns:
rawSignature ==
3E56F09EE9CF7D98...
Signing 'helloworld' == PlbwnunP...
rawSignature ==
3E56F09EE9CF7D98...
Signing 'helloworld' == PlbwnunP...
rawSignature ==
3E56F09EE9CF7D98...
Signing 'helloworld' == PlbwnunP...
我做错了什么?
我完全不使用 CspParameters
,而是使用 X509Certificate2
的 PrivateKey
属性,从而获得了一致的结果。不幸的是,我当前的 "portable" 实现需要强制转换,这让我很紧张,但它似乎在 Windows 和 Linux 上(在 Mono 4.0.2 下)给出了相同的结果,这些是结果与原始示例代码相同。这是一个在 Mono 下运行的简短测试应用程序:
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));
}
}
如评论中所述,由于未知原因,在 .NET 下无法 工作:(
现在我还没有尝试使用它来发出任何云存储请求,但我希望它会起作用。
在更现代的平台上,您可以使用 RSA
具有 SignData
method, and use the GetPrivateRSAKey()
extension method 的事实来获取 RSA
实例:
var rsa = key.GetRSAPrivateKey();
var signature = rsa.SignData(
buffer, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
您也可以在 Mono 上使用它,具体取决于您的目标版本。