CryptographicEngine::SignHashedData not implemented error

0

I encountered an error while using cppwinrt. When I use CryptographicEngine::SignHashedData function to sign a hash value, it returns WinRT originate error - 0x80004001 : 'not implemented'.

Here is the code:

#include "pch.h"

using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Security::Cryptography;
using namespace Windows::Security::Cryptography::Core;
using namespace Windows::Storage::Streams;
using namespace std;

int main()
{
    init_apartment();
    IBuffer buffKeyPair; 
    IBuffer buffPublicKey;
    IBuffer nullBuff(nullptr);
    uint32_t asymmetricKeyLength = 512;
    hstring strMsg = L"zzp yes!";
    hstring strAsymmetricAlgName = AsymmetricAlgorithmNames::RsaPkcs1();
    hstring strAlgNameH = HashAlgorithmNames::Md5();
    AsymmetricKeyAlgorithmProvider objAlgProv = AsymmetricKeyAlgorithmProvider::OpenAlgorithm(strAsymmetricAlgName);
    CryptographicKey keyPair = objAlgProv.CreateKeyPair(asymmetricKeyLength);
    IBuffer buffUtf8Msg = CryptographicBuffer::ConvertStringToBinary(strMsg, BinaryStringEncoding::Utf8);
    HashAlgorithmProvider objAlgH = HashAlgorithmProvider::OpenAlgorithm(strAlgNameH);
    IBuffer buffHash = objAlgH.HashData(buffUtf8Msg);
    IBuffer signedBuff = CryptographicEngine::SignHashedData(keyPair, buffHash);
    hstring strHashHex = CryptographicBuffer::EncodeToHexString(signedBuff);
    std::cout << "the strHashHex is: " << winrt::to_string(strHashHex) << std::endl;
}

Could you please help me find the problem? Thanks!

c++-winrt
asked on Stack Overflow May 15, 2021 by Randy

2 Answers

0

I'm not too experienced in this space, but I think I figured out a couple issues. This is happening because you aren't using an algorithm that can be used for signing, and you aren't using a hash algorithm compatible with it. The docs seem a bit... sparse... in this regard, but the algorithm names that have "sign" in them looked promising.

After a little experimentation, I got this to work.

using namespace Windows::Security::Cryptography;
using namespace Windows::Security::Cryptography::Core;
using namespace Windows::Storage::Streams;
using namespace std;

int main()
{
    init_apartment();

    auto algo_name = AsymmetricAlgorithmNames::RsaSignPkcs1Sha1();
    auto asymmetric_provider = AsymmetricKeyAlgorithmProvider::OpenAlgorithm(algo_name);
    auto keyPair = asymmetric_provider.CreateKeyPair(512);

    auto md5_hasher = HashAlgorithmProvider::OpenAlgorithm(HashAlgorithmNames::Sha1());
    auto buffHash = md5_hasher.HashData(
        CryptographicBuffer::ConvertStringToBinary(
            L"Hello world", BinaryStringEncoding::Utf8));
    auto signature = CryptographicEngine::SignHashedData(keyPair, buffHash);

    auto publicKey = asymmetric_provider.ImportPublicKey(keyPair.ExportPublicKey());
    auto match = CryptographicEngine::VerifySignatureWithHashInput(
        publicKey, buffHash, signature);
}

Notice that I used RsaSignPkcs1Sha1 which seems to indicate that this algorithm can do signing. Also, for the hash algorithm, I used Sha1. Using Md5 gave a different runtime error (and Md5 is pretty weak, anyway). I also added the code to show how to use your key pair's public key to verify the signature.

answered on Stack Overflow May 15, 2021 by Ryan Shepherd
0

After try your code and more tests, I have found that RsaSignPkcs1Sha1 is needed when you want to sign a content, the RsaPkcs1 does not support signing. Besides, I found that Windows only support RSA signing with SHA hashes, it does not support sign a md5 hash. Further more, the two names (RsaSignPkcs1Sha1 and Sha1) must match, or you will encounter an error. I don't known how it works in the back. I also found that sign a content with the sign function is equvalent with sign a content's hash with SignHashedData function, It seems that sign function first computes the hash before signing it.

answered on Stack Overflow May 15, 2021 by Randy

User contributions licensed under CC BY-SA 3.0