【问题标题】:CryptoAPI: How to verify a DSA signature from OpenSSL or Java using CryptVerifySignatureCryptoAPI:如何使用 CryptVerifySignature 从 OpenSSL 或 Java 验证 DSA 签名
【发布时间】:2011-02-17 19:51:52
【问题描述】:

我希望能够使用 Microsoft CryptoAPI 验证 OpenSSL 生成的 DSA 签名。

假设您有以下输入:

  • 现有的 DSA 公钥:
  • 待验证的数据
  • 二进制签名

签名已经从 Base64 转换成一系列 48 字节。

【问题讨论】:

    标签: openssl digital-signature cryptoapi


    【解决方案1】:

    如果没有很好的 CryptoAPI 知识,这将变得更加困难。

    主要的绊脚石是:

    • 使用 CryptStringToBinaryA 和 CryptDecodeObjectEx 解码 X509 DSA 公钥
    • 转换 DSA 签名格式
      • OpenSSL 的 DSA_sign 生成 ASN.1 DER 格式的 DSA 签名
      • CryptoAPI 的 CryptVerifySignature 需要 P1363 格式的 DSA 签名

    这是我最终如何解决问题的粗略示例:

    const char* pubKey =  "MIIBtjCCASsGByqGSM44BAEwggEeAoGBANW/k8nYREKtRMvIShnJTSAwxF33haU4"
                          .....
                          "/FEGAibbOp31rjq9UfaJ2t06eN0t0B+DP1hjz/MfpGtPOxHqF3dQnDRa3ot1FSTP";
    
    bool verify(const unsigned char* msgData, unsigned int msgLength, const unsigned char* signature, unsigned int signatureLength)
    {
        HCRYPTPROV hCryptProv;
        if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_DSS, CRYPT_VERIFYCONTEXT))
        {
            return false;
        }
    
        bool result = false;
    
        unsigned char derPubKey[2048];
        DWORD  derPubKeyLen = 2048;
        CERT_PUBLIC_KEY_INFO *publicKeyInfo = NULL;
        DWORD  publicKeyInfoLen = 0;
    
        if ( CryptStringToBinaryA( pubKey, strlen(pubKey), CRYPT_STRING_BASE64, derPubKey, &derPubKeyLen, NULL, NULL ) &&
             CryptDecodeObjectEx( X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO, derPubKey, derPubKeyLen, 
                                  CRYPT_ENCODE_ALLOC_FLAG, NULL, &publicKeyInfo, &publicKeyInfoLen ) )
        {
            HCRYPTKEY hPubKey;
            if (CryptImportPublicKeyInfo(hCryptProv, X509_ASN_ENCODING, publicKeyInfo, &hPubKey))
            {
                HCRYPTHASH hHash;
                if (CryptCreateHash(hCryptProv, CALG_SHA1, 0, 0, &hHash))
                {
                    CryptHashData(hHash, msgData, msgLength, 0);
    
                    BYTE* dsaSignature = NULL;
                    DWORD dsaSignatureLen = 0;
                    if (CryptDecodeObjectEx( X509_ASN_ENCODING, X509_DSS_SIGNATURE, signature, signatureLength,
                                             CRYPT_ENCODE_ALLOC_FLAG, NULL, &dsaSignature, &dsaSignatureLen ) )
                    {
                        if (CryptVerifySignature(hHash, dsaSignature, dsaSignatureLen, hPubKey, NULL, 0))
                        {
                            result = true;
                        }
                        LocalFree(dsaSignature);
                    }
    
                    CryptDestroyHash(hHash);
                }
                CryptDestroyKey(hPubKey);
            }
            LocalFree(publicKeyInfo);
        }
        CryptReleaseContext(hCryptProv, 0);
        return result;
    }
    

    【讨论】:

      【解决方案2】:

      请注意,Microsoft 的加密 API 不支持大于 1024 的 DSA 密钥长度。CryptImportPublicKeyInfo() 将失败并显示 NTE_BAD_DATA。

      【讨论】:

      • 谢谢!顺便说一句:我在使用大于 1024 (Win10) 的 DSA 密钥时打赌 E_INVALIDARG(0x80070057)。
      猜你喜欢
      • 1970-01-01
      • 2017-07-24
      • 1970-01-01
      • 2011-08-17
      • 2011-03-28
      • 1970-01-01
      • 2017-05-16
      • 2014-02-24
      • 2015-10-06
      相关资源
      最近更新 更多