我正在尝试使用非官方的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#编写吗?
答案 0 :(得分:0)
这两个代码都用于具有Pkcs#1 v1.5填充和SHA1的签名RSA,这在Java代码中通过SHA1withRSA
指定,在C#代码中通过RSA#SignHash
方法明确指定。第二和第三参数。由于签名(RSASSA-PKCS1-v1_5)的Pkcs#1 v1.5变量是确定性的,因此两个代码必须提供相同的签名(假定要签名的数据和私钥相同)。
如果不是这种情况,实际上只有两种合理的解释:
byte[]
的形式传输,因此无法根据发布的代码确定使用哪种编码。相反,在C#代码中,数据作为字符串传递,并转换为byte[]
中的HashText
。为此,使用了UnicodeEncoding
的标准指针,它应用了UTF16LE和字节顺序标记(BOM)。对于UTF8(无BOM),必须使用UTF8Encoding
。至关重要的是,在C#代码中使用与Java代码中相同的编码,否则通常会生成不同的签名。 KeyStore#getKey
引用私钥及其别名(对证书也是如此),在C#代码中,X509Certificate2(Byte[], String, X509KeyStorageFlags)
引用容器中的 first 证书,另请参见here。为了确保在两个代码中都引用相同证书/密钥,因此pfx / p12文件可能只包含完全相同的一个证书,包括相应的私钥。如果考虑到这一点,则两个代码都会在我的计算机上生成相同的签名(假设要签名的数据和pfx / p12文件相同)。
最后,应该注意的是,两个代码cert
用于不同的对象。在Java代码中,它表示InputStream
,在C#代码中,它表示pfx / pf12文件的 Base64编码二进制数据。