Java数字签名和C++ CryptSignMessage导致的结果不同

标签 java c++ windows cryptography digital-signature

我正在尝试将数字签名的生成从 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==

我确信同一个证书用于对消息进行签名。

非常感谢您的想法。

最佳答案

您使用的 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。

关于Java数字签名和C++ CryptSignMessage导致的结果不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27153549/

相关文章:

c++ - 在函数中使用引用或返回

c++ - 如何使用密码(C/C++)锁定Windows 7计算机屏幕

c++ - 地址清理器不适用于 Windows 上的 bash

windows - 通过 PsExec 在远程计算机中执行批处理文件

java - 不能使用 try/catch block 处理 java 未经检查的异常吗?

java - 如何通过基于 Java 的 Web 服务在现有数据模型上轻松公开 CRUD 操作?

java - 为什么 64 位 JVM 比 32 位更快?

java - 使用java在ms word文件中创建任何一年的日历

c++ - 如何在Qt C++中更新QWindow,文本不显示

c++ - vb.net 将数组传递给 C++ 导致堆栈错误