I practice using the win32 APIs to do some crypto stuff.
I began with the code demo found here.
It compiled it with Visual 2017 under Windows 10 x64, and it worked fine.
Then I tried to play a little with it: changing signature algo, hash algo and key storage.
Here is what it looks like (+100 lines, sorry) :
// code widely inspired from the one here : https://docs.microsoft.com/fr-fr/windows/win32/seccng/signing-data-with-cng
#define WIN32_NO_STATUS
#include <windows.h>
#undef WIN32_NO_STATUS
#include <ntstatus.h>
#include <winerror.h>
#include <stdio.h>
#include <bcrypt.h>
#include <ncrypt.h>
// list of known errors
#define ERRORS(f) f(NTE_EXISTS,already exists)f(NTE_NOT_SUPPORTED,)f(NTE_INVALID_PARAMETER,)f(NTE_NO_MORE_ITEMS,)f(NTE_INVALID_HANDLE,)\
f(STATUS_NOT_FOUND,)f(STATUS_INVALID_SIGNATURE,)f(STATUS_NOT_SUPPORTED,)f(NTE_PERM,permission denied)
// error display management
const char * _pretty ( const char * s ) { static char r[50] ; while (*s++!='_') ; for (char*p=r;*s;s++,*++p=0) *p=*s=='_'?' ':'A'<=*s&&*s<='Z'?*s-'A'+'a':*s ; return r ;}
#define CASE(e,s) case int(e) : return *#s ? #s : _pretty(#e) ;
#define strerr(err) _strerr(int(err))
const char * _strerr ( int err ) { switch ( err ) { ERRORS(CASE) default: return "???" ;}}
#undef CASE
#define CHECK(action) { int _err = int(action) ; if (_err) { printf("%s line %d failed : %s (0x%08x)\n",#action,__LINE__,strerr(_err),_err ) ; goto Cleanup ;}}
int test ( LPCWSTR HashAlgo , LPCWSTR SignAlgo , LPCWSTR Storage , LPCWSTR BlobType )
{
NCRYPT_PROV_HANDLE hProv = NULL;
NCRYPT_KEY_HANDLE hKey = NULL;
BCRYPT_KEY_HANDLE hTmpKey = NULL;
BCRYPT_ALG_HANDLE hHashAlg = NULL,
hSignAlg = NULL;
BCRYPT_HASH_HANDLE hHash = NULL;
BYTE pbHashObject [500],
pbHash [100],
pbSignature [500],
pbBlob [500] ;
DWORD szProp = 0,
szHash = 0,
szBlob = sizeof( pbBlob ),
szSignature = sizeof( pbSignature ),
szHashObject = sizeof( pbHashObject );
int Res = 1 ;
const wchar_t KeyName [] = L"The lord of the Keys" ;
const char Message [] = "I am the message to be hashed and signed, and I am pretty long..." ;
wprintf(L"%-8s / %-12s / %-30s : ",HashAlgo,SignAlgo,Storage+10 ) ;
//--------------------------------------------- create the hash object
CHECK( BCryptOpenAlgorithmProvider( &hHashAlg,HashAlgo,NULL,0 )) ;
CHECK( BCryptCreateHash( hHashAlg, &hHash, pbHashObject, szHashObject, NULL, 0, 0)) ;
CHECK( BCryptGetProperty( hHashAlg,BCRYPT_HASH_LENGTH,(PBYTE)&szHash,sizeof(DWORD),&szProp,0)) ;
CHECK( BCryptCloseAlgorithmProvider( hHashAlg,0 )) ;
hHashAlg = NULL;
//--------------------------------------------- hash the data using the hash object
CHECK( BCryptHashData( hHash,(PBYTE)Message,sizeof(Message),0)) ;
CHECK( BCryptFinishHash( hHash, pbHash, szHash, 0)) ;
CHECK( BCryptDestroyHash( hHash )) ;
hHash = NULL ;
//--------------------------------------------- create a persistent asymmetric key pair
CHECK( NCryptOpenStorageProvider( &hProv,Storage,0 )) ;
CHECK( NCryptCreatePersistedKey( hProv,&hKey,SignAlgo,KeyName,0,NCRYPT_OVERWRITE_KEY_FLAG )) ;
CHECK( NCryptFinalizeKey( hKey,0 )) ;
CHECK( NCryptFreeObject( hProv )) ;
hProv = NULL;
//--------------------------------------------- sign the hash of the data
CHECK( NCryptSignHash( hKey,NULL,pbHash,szHash,pbSignature,szSignature,&szSignature,0)) ;
//--------------------------------------------- export the key from the key store into a blob
CHECK( NCryptExportKey( hKey,NULL,BlobType,NULL,pbBlob,szBlob,&szBlob,0)) ;
CHECK( NCryptDeleteKey( hKey,0 )) ;
hKey = NULL ;
//--------------------------------------------- verify the signature by re-importing the key from its blob
CHECK( BCryptOpenAlgorithmProvider( &hSignAlg,SignAlgo,NULL,0 )) ;
CHECK( BCryptImportKeyPair( hSignAlg,NULL,BlobType,&hTmpKey,pbBlob,szBlob,0)) ;
CHECK( BCryptVerifySignature( hTmpKey,NULL,pbHash,szHash,pbSignature,szSignature,0)) ;
printf( "ok\n" ) ;
Res = 0 ;
Cleanup:
if (hHashAlg) BCryptCloseAlgorithmProvider(hHashAlg,0);
if (hSignAlg) BCryptCloseAlgorithmProvider(hSignAlg,0);
if (hHash) BCryptDestroyHash(hHash);
if (hTmpKey) BCryptDestroyKey(hTmpKey);
if (hKey) NCryptDeleteKey(hKey, 0);
if (hProv) NCryptFreeObject(hProv);
return Res ;
}
int main ( int , const char ** )
{
int res = test( BCRYPT_SHA1_ALGORITHM , BCRYPT_ECDSA_P256_ALGORITHM , MS_KEY_STORAGE_PROVIDER , BCRYPT_ECCPUBLIC_BLOB ) +
test( BCRYPT_SHA256_ALGORITHM , BCRYPT_ECDSA_P256_ALGORITHM , MS_KEY_STORAGE_PROVIDER , BCRYPT_ECCPUBLIC_BLOB ) +
test( BCRYPT_SHA512_ALGORITHM , BCRYPT_ECDSA_P256_ALGORITHM , MS_KEY_STORAGE_PROVIDER , BCRYPT_ECCPUBLIC_BLOB ) +
test( BCRYPT_SHA256_ALGORITHM , BCRYPT_ECDSA_P256_ALGORITHM , MS_PLATFORM_CRYPTO_PROVIDER , BCRYPT_ECCPUBLIC_BLOB ) +
test( BCRYPT_SHA1_ALGORITHM , BCRYPT_DSA_ALGORITHM , MS_KEY_STORAGE_PROVIDER , BCRYPT_DSA_PUBLIC_BLOB ) +
test( BCRYPT_SHA256_ALGORITHM , BCRYPT_DSA_ALGORITHM , MS_KEY_STORAGE_PROVIDER , BCRYPT_DSA_PUBLIC_BLOB ) +
test( BCRYPT_SHA1_ALGORITHM , BCRYPT_DSA_ALGORITHM , MS_PLATFORM_CRYPTO_PROVIDER , BCRYPT_DSA_PUBLIC_BLOB ) +
test( BCRYPT_SHA1_ALGORITHM , BCRYPT_RSA_ALGORITHM , MS_KEY_STORAGE_PROVIDER , BCRYPT_RSAPUBLIC_BLOB ) +
test( BCRYPT_SHA256_ALGORITHM , BCRYPT_RSA_ALGORITHM , MS_KEY_STORAGE_PROVIDER , BCRYPT_RSAPUBLIC_BLOB ) ;
return res ;
}
and here is the output :
SHA1 / ECDSA_P256 / Software Key Storage Provider : ok
SHA256 / ECDSA_P256 / Software Key Storage Provider : ok
SHA512 / ECDSA_P256 / Software Key Storage Provider : ok
SHA256 / ECDSA_P256 / Platform Crypto Provider : ok
SHA1 / DSA / Software Key Storage Provider : ok
SHA256 / DSA / Software Key Storage Provider : NCryptSignHash( hKey,NULL,pbHash,szHash,pbSignature,szSignature,&szSignature,0) line 68 failed : invalid parameter (0x80090027)
SHA1 / DSA / Platform Crypto Provider : NCryptCreatePersistedKey( hProv,&hKey,SignAlgo,KeyName,0,NCRYPT_OVERWRITE_KEY_FLAG ) line 62 failed : not supported (0x80090029)
SHA1 / RSA / Software Key Storage Provider : NCryptSignHash( hKey,NULL,pbHash,szHash,pbSignature,szSignature,&szSignature,0) line 68 failed : invalid parameter (0x80090027)
SHA256 / RSA / Software Key Storage Provider : NCryptSignHash( hKey,NULL,pbHash,szHash,pbSignature,szSignature,&szSignature,0) line 68 failed : invalid parameter (0x80090027)
I though that all my tries should be working, but they're not.
Any idea about the why?
Thanks in advance.
Captain'Flam
User contributions licensed under CC BY-SA 3.0