Usage of Win32 API Ncrypt and Bcrypt : why the tutorial code fails after a very simple variation?

0

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

c
visual-studio
security
winapi
cryptography
asked on Stack Overflow Feb 19, 2021 by Captain'Flam

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0