【问题标题】:Digital Signature SunMSCAPI provider & MS Crypto API数字签名 SunMSCAPI 提供者和 MS Crypto API
【发布时间】:2013-03-27 19:18:42
【问题描述】:

我想用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..

【问题讨论】:

    标签: java rsa digital-signature cryptoapi mscapi


    【解决方案1】:

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

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

    从那时起,代码就非常标准了。更多信息请咨询my book on digital signatures(本书免费)。

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

    【讨论】:

    • 感谢您的回复,我正在使用 java keytool 创建密钥库,并使用上面代码中提到的 java 应用程序中的密钥库导出公钥,同时双击该文件我可以安装它,但它没有显示在证书列表。您能给我提供一种添加自签名证书的方法吗?
    • 首先:我认为 JKS 密钥不起作用。您需要创建一个 .p12 文件。我通常不双击文件,而是转到证书概述,然后手动导入密钥。这样,我就知道会发生什么。
    • 好的!我使用 java keytool 创建了 .p12 文件并安装到 Windows 证书中。一切正常我可以使用 Signature.getInstance("SHA1withRSA","SunMSCAPI") 对文件进行签名,但为了验证,我仍然无法使用 MS Crypto API 导入公钥(我在上面的代码中创建),我认为这仍然是一个大/小端格式问题。
    • 嗯,从 Windows 证书存储中导出公钥可能更容易。您可以从那里选择各种格式。
    • 问题变得更长,因此更难理解。事实上:我没有看到这个问题。请通过接受答案并发布一个仅包含您的新问题的新问题来结束此问题。
    猜你喜欢
    • 2023-03-20
    • 2014-01-02
    • 2013-01-09
    • 1970-01-01
    • 1970-01-01
    • 2015-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多