我正在尝试将数字签名的生成从Java移植到C ++。
我尝试过的大部分工作都是有效的,除了用C ++创建的数字签名似乎包含的信息比Java创建的要多。我不知道这些字节是什么,我也不知道如何防止它们被写入。
以下是两段代码段。首先是现有的Java代码:
KeyStore keyStore = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
keyStore.load(null);
PrivateKey key = (PrivateKey) keyStore.getKey(alias, null);
Signature sign = Signature.getInstance("SHA1withRSA", keyStore.getProvider());
sign.initSign(key);
String msg = "message";
sign.update(msg.getBytes("UTF-8"));
byte[] ba = sign.sign();
String signature = new String(Base64.encodeBase64(ba), "UTF-8");
以下是我在C ++中发现的上述问题。代码是根据MSDN示例Signing a Message and Verifying a Message Signature编写的:
HCERTSTORE hCertStore = CertOpenStore(
CERT_STORE_PROV_SYSTEM,
0,
NULL,
CERT_SYSTEM_STORE_CURRENT_USER,
L"MY"));
PCCERT_CONTEXT pCertContext = CertFindCertificateInStore(
hCertStore,
MY_ENCODING_TYPE,
0,
CERT_FIND_SUBJECT_STR,
alias,
NULL);
CRYPT_SIGN_MESSAGE_PARA SigParams;
SigParams.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA);
SigParams.dwMsgEncodingType = MY_ENCODING_TYPE;
SigParams.pSigningCert = pCertContext;
SigParams.HashAlgorithm.pszObjId = szOID_RSA_SHA1RSA;
SigParams.HashAlgorithm.Parameters.cbData = NULL;
SigParams.dwFlags = CRYPT_MESSAGE_KEYID_SIGNER_FLAG;
SigParams.dwInnerContentType = 0;
SigParams.pvHashAuxInfo = nullptr;
SigParams.rgAuthAttr = NULL;
SigParams.cMsgCert = 0;
SigParams.cAuthAttr = 0;
SigParams.cMsgCrl = 0;
SigParams.cUnauthAttr = 0;
std::string msg("message");
const BYTE* MessageArray[] = {(BYTE*)msg.c_str()};
DWORD MessageSizeArray[] = {msg.size()};
// First, get the size of the signed BLOB.
DWORD cbSignedMessageBlob = 0;
CryptSignMessage(
&SigParams,
TRUE,
1,
MessageArray,
MessageSizeArray,
NULL,
&cbSignedMessageBlob);
// Allocate memory for the signed BLOB.
BYTE* pbSignedMessageBlob = (BYTE*)malloc(cbSignedMessageBlob);
CryptSignMessage(
&SigParams,
TRUE,
1,
MessageArray,
MessageSizeArray,
pbSignedMessageBlob,
&cbSignedMessageBlob);
const std::string signedMessageBase64 =
Base64::Encode(pbSignedMessageBlob, cbSignedMessageBlob);
从Java代码创建的签名:
messageyoPTn33Z/c1P05BoY6COW+VrbG5MTsog2YhNrXkbVy3PfXQtERQ4j9BXKnPAidYmMPaOxyT/Lh+D3ZyiXmtBwgV4oMMIp4PnMj5MO77ZCGc86NzYTbyk0FqLJFiMAR/+2h9fEsVd3NQlci3gxFHSO2tlDDppQBePjl39nXPlkrfUqRxtr7cGDLV6mX7iI5nuKXLKgbywmkVB4NT15vbTqLQaCMMJrRpNp5jg3NG17u1LthfeOwrkNk4SE6fxfoyZOU6mQ+ACbYCIn3lYCwVtHLDvoMDhmjWvgyBQwfSNr5SlPx5qiPSZrPg7AO2svqmNeEibvW1YPpfilNg83MWeOg==
从C ++代码创建的签名:
messageMIIBdwYJKoZIhvcNAQcCoIIBaDCCAWQCAQMxDzANBgkqhkiG9w0BAQUFADALBgkqhkiG9w0BBwExggE/MIIBOwIBA4AUn87cY1dT9wKLDn9zdZu0Rrm0j54wDQYJKoZIhvcNAQEFBQAwDQYJKoZIhvcNAQEBBQAEggEAyoPTn33Z/c1P05BoY6COW+VrbG5MTsog2YhNrXkbVy3PfXQtERQ4j9BXKnPAidYmMPaOxyT/Lh+D3ZyiXmtBwgV4oMMIp4PnMj5MO77ZCGc86NzYTbyk0FqLJFiMAR/+2h9fEsVd3NQlci3gxFHSO2tlDDppQBePjl39nXPlkrfUqRxtr7cGDLV6mX7iI5nuKXLKgbywmkVB4NT15vbTqLQaCMMJrRpNp5jg3NG17u1LthfeOwrkNk4SE6fxfoyZOU6mQ+ACbYCIn3lYCwVtHLDvoMDhmjWvgyBQwfSNr5SlPx5qiPSZrPg7AO2svqmNeEibvW1YPpfilNg83MWeOg==
我确信使用相同的证书对邮件进行签名。
非常感谢你的想法。
答案 0 :(得分:3)
您使用的Java代码会生成PKCS#1(使用PKCS#1 v1.5签名方案)和SHA-1中定义的“原始”签名。您的C ++代码生成PKCS#7(CMS)签名。这是一个包含在容器格式中的签名以及消息,您可以看到here。
如果您对PKCS#7签名中包含的签名进行十六进制编码,您将看到与在Java中生成的值相同的值。它们都生成以下签名(使用十六进制作为表示):
CA83D39F7DD9FDCD4FD3906863A08E5BE56B6C6E4C4ECA20D9884DAD791B572DCF7D742D1114388FD0572A73C089D62630F68EC724FF2E1F83DD9CA25E6B41C20578A0C308A783E7323E4C3BBED908673CE8DCD84DBCA4D05A8B24588C011FFEDA1F5F12C55DDCD425722DE0C451D23B6B650C3A6940178F8E5DFD9D73E592B7D4A91C6DAFB7060CB57A997EE22399EE2972CA81BCB09A4541E0D4F5E6F6D3A8B41A08C309AD1A4DA798E0DCD1B5EEED4BB617DE3B0AE4364E1213A7F17E8C99394EA643E0026D80889F79580B056D1CB0EFA0C0E19A35AF832050C1F48DAF94A53F1E6A88F499ACF83B00EDACBEA98D78489BBD6D583E97E294D83CDCC59E3A
您需要一个生成PKCS#1签名而不是PKCS#7(CMS)容器的代码,例如尝试CryptSignHash的示例代码,该代码也默认为PKCS#1 v1.5签名方案和SHA-1。