数字签名SunMSCAPI提供商和MS Crypto API

我想与SunMSCAPI提供商签署文件。 由于需要使用MS Crypto API导入公钥和签名。

通常使用SHA1withRSA生成签名,最终使用big-endian到little-endian(字节顺序)转换。

 //generate keystore with java keytool $Keytool -genkey -alias tsign -keystore c:\test\tsignjks.p12 - keyalg rsa -storetype pkcs12 

在Java应用程序中:

 //for signing and getting keystore, assuming windows certificate is installed ..ks = KeyStore.getInstance("Windows-MY","SunMSCAPI"); PrivateKey priv = ks.getKey("tsign",password); Signature rsa = Signature.getInstance("SHA1withRSA","SunMSCAPI"); rsa.initSign(priv); .. rsa.update(buffer, 0, len); .. byte[] realSig = rsa.sign(); //for writing public key for ms crypto api or exporting it from windows certificate store Certificate cert = ks.getCertificate("tsign"); byte[] encodedCert = cert.getEncoded(); FileOutputStream certfos = new FileOutputStream("tsigncer.cer"); certfos.write(encodedCert); //for writing signatures for ms crypto api FileOutputStream sigfos = new FileOutputStream(targetPath + "/" + signatureName); sigfos.write(realSig); 

我相信SunMSCAPI可以解决我的问题,但我不知道何时使用MS Crypto API导入公钥,它从不在第一阶段导入(除非我将大端更改为小端字节顺序)下面是我的加密代码API。

 LPCSTR file = "tsigncer.cer"; //LPCSTR file = "omsign.p12"; BOOL crypt_res = FALSE; HCRYPTPROV crypt_prov_hndl = NULL; crypt_res = CryptAcquireContext(&crypt_prov_hndl, NULL, NULL, PROV_RSA_FULL, 0/*CRYPT_NEWKEYSET*/); //crypt_res = CryptAcquireContext(&crypt_prov_hndl, NULL, NULL, PROV_DSS, CRYPT_VERIFYCONTEXT/*CRYPT_NEWKEYSET*/); if (!crypt_res) { HRESULT decode_hr = __HRESULT_FROM_WIN32(GetLastError()); return decode_hr; } // Load key file HANDLE fileHandle = CreateFile(file, // name of the write GENERIC_READ, // open for writing 0, // do not share NULL, // default security OPEN_EXISTING, // create new file only FILE_ATTRIBUTE_NORMAL, // normal file NULL); // no attr. template if (fileHandle == INVALID_HANDLE_VALUE) { DWORD d = GetLastError(); return -1; } BYTE buffer[2056]; DWORD fileSize = 0; DWORD fileSizeResult = GetFileSize(fileHandle, &fileSize); DWORD numBytesRead = 0; BOOL fileLoadResult = ReadFile(fileHandle, (PVOID)buffer, fileSizeResult, &numBytesRead, NULL); // Import key BOOL result = ImportKey(crypt_prov_hndl, (LPBYTE)buffer, numBytesRead); //result is always false.. 

如果您使用MSCAPI,则假定您已将密钥添加到Microsoft证书存储区。 您可以通过转到“Internet属性”>“内容”>“证书”来检查密钥是否存在,该证书为您提供了可用的证书列表。 如果您的证书不存在,则无法使用。 如果它在那里,你需要这个代码:

 SunMSCAPI providerMSCAPI = new SunMSCAPI(); Security.addProvider(providerMSCAPI); KeyStore ks = KeyStore.getInstance("Windows-MY"); ks.load(null, null); 

从那以后,代码非常标准。 有关更多信息,请参阅我的数字签名书(该书是免费的)。

重要补充:我忘了提到64位版本的Java 6中没有SunMSCAPI(我不知道Java 7)。 您可以通过安装32位版本来解决此问题。