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!
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.
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.
User contributions licensed under CC BY-SA 3.0