如何在 C# 中使用 PFX 证书签署请求?
How to sign an request using PFX certificate in c#?
我正在尝试使用非官方 API 文档。我需要用我自己的证书签署所有请求,但文档只提供了 Java 代码供使用,这里是:
public class EncryptionUtils {
private static final String ALGORITHM_NAME = "SHA1withRSA";
private static final String CERT_TYPE = "pkcs12";
private static final String CONTAINER_NAME = "LoginCert";
private static final String PASSWORD = "CE75EA598C7743AD9B0B7328DED85B06";
public static String signContent(byte[] contents, final InputStream cert) throws IOException, GeneralSecurityException, NullPointerException {
final KeyStore instance = KeyStore.getInstance(CERT_TYPE);
instance.load(cert, PASSWORD.toCharArray());
final PrivateKey privateKey = (PrivateKey) instance.getKey(CONTAINER_NAME, PASSWORD.toCharArray());
final Signature instance2 = Signature.getInstance(ALGORITHM_NAME);
instance2.initSign(privateKey);
instance2.update(contents);
return Base64.getEncoder().encodeToString(instance2.sign());
}}
我想出了这个代码
private static string password = "CE75EA598C7743AD9B0B7328DED85B06";
public static string Sign(string text, string cert)
{
X509Certificate2 certificate = new X509Certificate2(DecodeCrt(cert), password, X509KeyStorageFlags.Exportable);
RSA provider = (RSA)certificate.PrivateKey;
// Hash the data
var hash = HashText(text);
// Sign the hash
var signature = provider.SignHash(hash, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
return Convert.ToBase64String(signature);
}
public static byte[] HashText(string text)
{
SHA1Managed sha1Hasher = new SHA1Managed();
UnicodeEncoding encoding = new UnicodeEncoding();
byte[] data = encoding.GetBytes(text);
byte[] hash = sha1Hasher.ComputeHash(data);
return hash;
}
public static byte[] DecodeCrt(string crt)
{
return Convert.FromBase64String(crt);
}
但输出与 Java 的版本不同。
我试过从 c# 临时 运行 java 任务,所以我知道它是否有效,而且确实如此。
有没有办法用c#写这个?
两种代码都用于带有 Pkcs#1 v1.5 填充和 SHA1 的签名 RSA,它在 Java 代码中通过 and in the C# code explicitly in the RSA#SignHash
method via the 2nd and 3rd parameter. Since the Pkcs#1 v1.5 variant for signatures (RSASSA-PKCS1-v1_5 指定)是确定性的,两种代码必须提供相同的签名(假设要签名的数据和私钥相同)。
如果不是这样,其实只有两个合理的解释:
- 首先,使用的编码:在Java代码中,数据传输为
byte[]
,因此无法根据发布的代码确定使用哪种编码。相反,在 C# 代码中,数据作为字符串传递并在 HashText
中转换为 byte[]
。为此,必须使用 UnicodeEncoding
is used, which applies UTF16LE and a byte order mark (BOM). For UTF8 (without BOM) UTF8Encoding
的标准构造函数。 关键 在 C# 代码中应用与 Java 代码相同的编码,否则通常会生成不同的签名。
- 其次,pfx/p12文件:pfx/p12个文件可以包含several certificates. In the Java code,
KeyStore#getKey
references the private key with its alias (the same applies to the certificate), in the C# code, X509Certificate2(Byte[], String, X509KeyStorageFlags)
references the first certificate in the container, see also here个。为确保 same certificate/key 在两个代码中都被引用,因此 pfx/p12 文件可能仅包含 exactly one 证书包括对应的私钥。
如果考虑到这一点,两个代码在我的机器上生成相同的签名(假设要签名的数据相同,pfx/p12文件相同)。
最后,需要注意的是,在两个代码中,cert
用于不同的对象。在Java代码中表示InputStream
,在C#代码中表示pfx/pf12文件的Base64编码二进制数据。
我正在尝试使用非官方 API 文档。我需要用我自己的证书签署所有请求,但文档只提供了 Java 代码供使用,这里是:
public class EncryptionUtils {
private static final String ALGORITHM_NAME = "SHA1withRSA";
private static final String CERT_TYPE = "pkcs12";
private static final String CONTAINER_NAME = "LoginCert";
private static final String PASSWORD = "CE75EA598C7743AD9B0B7328DED85B06";
public static String signContent(byte[] contents, final InputStream cert) throws IOException, GeneralSecurityException, NullPointerException {
final KeyStore instance = KeyStore.getInstance(CERT_TYPE);
instance.load(cert, PASSWORD.toCharArray());
final PrivateKey privateKey = (PrivateKey) instance.getKey(CONTAINER_NAME, PASSWORD.toCharArray());
final Signature instance2 = Signature.getInstance(ALGORITHM_NAME);
instance2.initSign(privateKey);
instance2.update(contents);
return Base64.getEncoder().encodeToString(instance2.sign());
}}
我想出了这个代码
private static string password = "CE75EA598C7743AD9B0B7328DED85B06";
public static string Sign(string text, string cert)
{
X509Certificate2 certificate = new X509Certificate2(DecodeCrt(cert), password, X509KeyStorageFlags.Exportable);
RSA provider = (RSA)certificate.PrivateKey;
// Hash the data
var hash = HashText(text);
// Sign the hash
var signature = provider.SignHash(hash, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
return Convert.ToBase64String(signature);
}
public static byte[] HashText(string text)
{
SHA1Managed sha1Hasher = new SHA1Managed();
UnicodeEncoding encoding = new UnicodeEncoding();
byte[] data = encoding.GetBytes(text);
byte[] hash = sha1Hasher.ComputeHash(data);
return hash;
}
public static byte[] DecodeCrt(string crt)
{
return Convert.FromBase64String(crt);
}
但输出与 Java 的版本不同。 我试过从 c# 临时 运行 java 任务,所以我知道它是否有效,而且确实如此。 有没有办法用c#写这个?
两种代码都用于带有 Pkcs#1 v1.5 填充和 SHA1 的签名 RSA,它在 Java 代码中通过 RSA#SignHash
method via the 2nd and 3rd parameter. Since the Pkcs#1 v1.5 variant for signatures (RSASSA-PKCS1-v1_5 指定)是确定性的,两种代码必须提供相同的签名(假设要签名的数据和私钥相同)。
如果不是这样,其实只有两个合理的解释:
- 首先,使用的编码:在Java代码中,数据传输为
byte[]
,因此无法根据发布的代码确定使用哪种编码。相反,在 C# 代码中,数据作为字符串传递并在HashText
中转换为byte[]
。为此,必须使用UnicodeEncoding
is used, which applies UTF16LE and a byte order mark (BOM). For UTF8 (without BOM)UTF8Encoding
的标准构造函数。 关键 在 C# 代码中应用与 Java 代码相同的编码,否则通常会生成不同的签名。 - 其次,pfx/p12文件:pfx/p12个文件可以包含several certificates. In the Java code,
KeyStore#getKey
references the private key with its alias (the same applies to the certificate), in the C# code,X509Certificate2(Byte[], String, X509KeyStorageFlags)
references the first certificate in the container, see also here个。为确保 same certificate/key 在两个代码中都被引用,因此 pfx/p12 文件可能仅包含 exactly one 证书包括对应的私钥。
如果考虑到这一点,两个代码在我的机器上生成相同的签名(假设要签名的数据相同,pfx/p12文件相同)。
最后,需要注意的是,在两个代码中,cert
用于不同的对象。在Java代码中表示InputStream
,在C#代码中表示pfx/pf12文件的Base64编码二进制数据。