密码学:为什么我会根据从哪个证书库加载证书而获得不同的 RSA 签名?
Cryptography: Why am I getting different RSA signatures depending on which certificate store the certificate was loaded from?
如果我从文件或当前用户的商店加载证书,我有一些工作代码可以生成正确的字符串签名。但是,如果我从机器证书存储区加载完全相同的证书(相同的 .p12 和相同的指纹),它的行为会有所不同。从该商店加载时,我的 C# 代码生成的签名是长度的一半(1024 位而不是 2048 位)并且不正确。在这两种情况下,私钥似乎都能正确加载。
为什么从哪个商店加载证书对生成哪个签名有影响?为什么签名会是一半的长度?
从当前用户加载:
Thumbprint: FBBE05A1C5F2AEF637CDE20A7985CD1011861651
Has private key:True
rsa.KeySize (bits) =2048
Signature Length (bits): 2048
Signature: kBC2yh0WCo/AU8aVo+VUbRoh67aIJ7SWM4dRMkNvt...
(正确)
从 LocalMachine 加载:
Thumbprint: FBBE05A1C5F2AEF637CDE20A7985CD1011861651
Has private key: True
rsa.KeySize (bits) = 1024
Signature Length (bits): 1024
Signature: RijmdQ73DXHK1IUYkOzov2R+WRdHW8tLqsH....
(不正确 - 请注意 1024 位密钥大小和签名长度)
这是我正在使用的 C#:
string s = "AE0DE01564,1484821101811,http://localhost:8080/example_site/CallBack";
var inputData = Encoding.UTF8.GetBytes(s);
var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
string thumbprint = CleanThumbPrint("fb be 05 a1 c5 f2 ae f6 37 cd e2 0a 79 85 cd 10 11 86 16 51");
X509Certificate2Collection col = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
// TODO: close store.
X509Certificate2 certificate = null;
Console.WriteLine("Cert count: " + col.Count);
if (col.Count == 1)
{
certificate = col[0];
RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)col[0].PrivateKey;
// Force use of the Enhanced RSA and AES Cryptographic Provider with openssl-generated SHA256 keys
var enhCsp = new RSACryptoServiceProvider().CspKeyContainerInfo;
var cspparams = new CspParameters(enhCsp.ProviderType, enhCsp.ProviderName, rsa.CspKeyContainerInfo.KeyContainerName);
rsa = new RSACryptoServiceProvider( cspparams);
Console.WriteLine("Name: " + certificate.SubjectName.Name);
Console.WriteLine("Thumbprint: " + certificate.Thumbprint);
Console.WriteLine("Has private key: " + certificate.HasPrivateKey);
Console.WriteLine("Sig algorithm: " + certificate.SignatureAlgorithm);
Console.WriteLine("rsa.KeySize (bits) =" + rsa.KeySize);
var sha256 = CryptoConfig.CreateFromName("SHA256");
byte[] signature = rsa.SignData(inputData, sha256);
Console.WriteLine("Signature Length (bits): " + signature.Length * 8);
Console.WriteLine("Signature: " + System.Convert.ToBase64String(signature));
Console.WriteLine();
}
事实证明,这与我使用 OpenSSL 创建的证书的文件格式以及未设置加密提供程序这一事实有关。关键命令是下面的第 5 条:
以下是我用来创建工作证书的命令:
- 生成密钥对:
openssl genrsa -out private_key.pem 2048
- 提取 public 密钥:
openssl rsa -pubout -in private_key.pem -out public_key.pem
- 从私钥创建 CSR 证书签名请求:
openssl req -new -key private_key.pem -out csr.csr
- 生成自签名证书:
openssl x509 -req -days 1095 -in csr.csr -signkey private_key.pem -out certificate.crt
- 使用指定的 CSP 创建 PFX 格式的证书:
openssl pkcs12 -export -in certificate.crt -inkey private_key.pem -CSP "Microsoft Enhanced RSA and AES Cryptographic Provider" -out TEST_pfx.pfx
如果我从文件或当前用户的商店加载证书,我有一些工作代码可以生成正确的字符串签名。但是,如果我从机器证书存储区加载完全相同的证书(相同的 .p12 和相同的指纹),它的行为会有所不同。从该商店加载时,我的 C# 代码生成的签名是长度的一半(1024 位而不是 2048 位)并且不正确。在这两种情况下,私钥似乎都能正确加载。
为什么从哪个商店加载证书对生成哪个签名有影响?为什么签名会是一半的长度?
从当前用户加载:
Thumbprint: FBBE05A1C5F2AEF637CDE20A7985CD1011861651
Has private key:True
rsa.KeySize (bits) =2048
Signature Length (bits): 2048
Signature: kBC2yh0WCo/AU8aVo+VUbRoh67aIJ7SWM4dRMkNvt...
(正确)
从 LocalMachine 加载:
Thumbprint: FBBE05A1C5F2AEF637CDE20A7985CD1011861651
Has private key: True
rsa.KeySize (bits) = 1024
Signature Length (bits): 1024
Signature: RijmdQ73DXHK1IUYkOzov2R+WRdHW8tLqsH....
(不正确 - 请注意 1024 位密钥大小和签名长度)
这是我正在使用的 C#:
string s = "AE0DE01564,1484821101811,http://localhost:8080/example_site/CallBack";
var inputData = Encoding.UTF8.GetBytes(s);
var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
string thumbprint = CleanThumbPrint("fb be 05 a1 c5 f2 ae f6 37 cd e2 0a 79 85 cd 10 11 86 16 51");
X509Certificate2Collection col = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
// TODO: close store.
X509Certificate2 certificate = null;
Console.WriteLine("Cert count: " + col.Count);
if (col.Count == 1)
{
certificate = col[0];
RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)col[0].PrivateKey;
// Force use of the Enhanced RSA and AES Cryptographic Provider with openssl-generated SHA256 keys
var enhCsp = new RSACryptoServiceProvider().CspKeyContainerInfo;
var cspparams = new CspParameters(enhCsp.ProviderType, enhCsp.ProviderName, rsa.CspKeyContainerInfo.KeyContainerName);
rsa = new RSACryptoServiceProvider( cspparams);
Console.WriteLine("Name: " + certificate.SubjectName.Name);
Console.WriteLine("Thumbprint: " + certificate.Thumbprint);
Console.WriteLine("Has private key: " + certificate.HasPrivateKey);
Console.WriteLine("Sig algorithm: " + certificate.SignatureAlgorithm);
Console.WriteLine("rsa.KeySize (bits) =" + rsa.KeySize);
var sha256 = CryptoConfig.CreateFromName("SHA256");
byte[] signature = rsa.SignData(inputData, sha256);
Console.WriteLine("Signature Length (bits): " + signature.Length * 8);
Console.WriteLine("Signature: " + System.Convert.ToBase64String(signature));
Console.WriteLine();
}
事实证明,这与我使用 OpenSSL 创建的证书的文件格式以及未设置加密提供程序这一事实有关。关键命令是下面的第 5 条:
以下是我用来创建工作证书的命令:
- 生成密钥对:
openssl genrsa -out private_key.pem 2048
- 提取 public 密钥:
openssl rsa -pubout -in private_key.pem -out public_key.pem
- 从私钥创建 CSR 证书签名请求:
openssl req -new -key private_key.pem -out csr.csr
- 生成自签名证书:
openssl x509 -req -days 1095 -in csr.csr -signkey private_key.pem -out certificate.crt
- 使用指定的 CSP 创建 PFX 格式的证书:
openssl pkcs12 -export -in certificate.crt -inkey private_key.pem -CSP "Microsoft Enhanced RSA and AES Cryptographic Provider" -out TEST_pfx.pfx