WIN32上的JWT验证

问题描述

我正在尝试使用 WIN32 加密功能验证 RS512 JWT。我已经获得了公钥、要验证的数据和作为内存数组的签名数据。我能够创建证书上下文并导入公钥,但到目前为止我还无法验证签名。无论我尝试什么,我都会得到 STATUS_INVALID_ParaMETER 结果。

我看过几篇关于必须反转部分或全部数据的帖子:

  1. 反转公钥可防止其加载。
  2. 反转 dataBuffer 和 signatureBuffer 中的一个/两个仍然会导致 STATUS_INVALID_ParaMETER。
BCRYPT_ALG_HANDLE cryptAlg = nullptr;
if( BCRYPT_SUCCESS( BCryptOpenAlgorithmProvider( &cryptAlg,BCRYPT_RSA_ALGORITHM,nullptr,0 ) ) )
{
    auto signingKeyBuffer = signingKey.publicKeyBuffer();
    PCCERT_CONTEXT cryptCert = CertCreateCertificateContext( X509_ASN_ENCODING,signingKeyBuffer.getBuffer(),signingKeyBuffer.getSize() );
    if( cryptCert != nullptr )
    {
        BCRYPT_KEY_HANDLE cryptKey;
        if( BCRYPT_SUCCESS( CryptImportPublicKeyInfoEx2( X509_ASN_ENCODING,&cryptCert->pCertInfo->SubjectPublicKeyInfo,&cryptKey ) ) )
        {
            BCRYPT_PKCS1_PADDING_INFO pkcs1Info;
            pkcs1Info.pszAlgid = BCRYPT_SHA512_ALGORITHM;
            auto dataBuffer = data;//.reversed();
            auto signatureBuffer = signature;//.reversed();
            auto status = BCryptVerifySignature( cryptKey,&pkcs1Info,dataBuffer.getBuffer(),dataBuffer.getSize(),signatureBuffer.getBuffer(),signatureBuffer.getSize(),BCRYPT_PAD_PKCS1 );

            //status is always STATUS_INVALID_ParaMETER here...
            
            BCryptDestroyKey( cryptKey );
        }
        CertFreeCertificateContext( cryptCert );
    }
    BCryptCloseAlgorithmProvider( cryptAlg,0 );
}

解决方法

我错过了文档中说数据需要散列的部分。在对数据 (SHA512) 应用相同的哈希后,我能够验证签名。这是工作代码减去错误检查:

//Hash data here.
auto hashedData = data.hash( HashType::SHA512 );

auto signingKeyBuffer = signingKey.publicKeyBuffer();
PCCERT_CONTEXT cryptCert = CertCreateCertificateContext( X509_ASN_ENCODING,signingKeyBuffer.getBuffer(),signingKeyBuffer.getSize() );
if( cryptCert != nullptr )
{
    BCRYPT_KEY_HANDLE cryptKey;
    if( BCRYPT_SUCCESS( CryptImportPublicKeyInfoEx2( X509_ASN_ENCODING,&cryptCert->pCertInfo->SubjectPublicKeyInfo,nullptr,&cryptKey ) ) )
    {
        BCRYPT_PKCS1_PADDING_INFO pkcs1Info;
        pkcs1Info.pszAlgId = cNEHash::algorithmIdForHashType( cAlgorithmType::hashType( algorithm ) );
        auto status = BCryptVerifySignature( cryptKey,&pkcs1Info,hashedData.getBuffer(),hashedData.getSize(),signature.getBuffer(),signature.getSize(),BCRYPT_PAD_PKCS1 );
        if( BCRYPT_SUCCESS( status ) )
            verified = true;
        BCryptDestroyKey( cryptKey );
    }
    CertFreeCertificateContext( cryptCert );
}