CryptDeriveKey für AES



  • Hallo zusammen,

    ich möchte aus einem Passwort einen Session Key für AES Verschlüsselung erzeugen. Der Algorithmus ist CALG_AES, die Schlüssellänge ist 128 bit. Der Aufruf von CryptDeriveKey schlägt mit der Fehlermeldung "Ungültiger Algorithmus angegeben" fehl (Fehlercode 0x80090008). Wenn ich statt CALG_AES CALG_RC4 benutze funktioniert alles ohne Probleme.

    #include <windows.h>
    #include <wincrypt.h>
    
    #include <string>
    #include <algorithm>
    
    using namespace std;
    
    HCRYPTPROV create_provider( ALG_ID CryptAlgo )
    {
    	string ProviderNameNew = "Microsoft Enhanced RSA and AES Cryptographic Provider";
    	string ProviderNameOld = "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)";
    
    	HCRYPTPROV retVal;
    	if( ::CryptAcquireContext( &retVal, nullptr, nullptr, PROV_RSA_AES, 0 ) )
    	{
    		return retVal;
    	}
    	if( ::CryptAcquireContext( &retVal, nullptr, ProviderNameNew.c_str(), PROV_RSA_AES, CRYPT_VERIFYCONTEXT ) )
    	{
    		return retVal;
    	}
    	else if( ::CryptAcquireContext( &retVal, nullptr, ProviderNameOld.c_str(), PROV_RSA_AES, CRYPT_VERIFYCONTEXT ) )
    	{
    		return retVal;
    	}
    	else if( ::CryptAcquireContext( &retVal, nullptr, nullptr, PROV_RSA_FULL, 0 ) )
    	{
    		return retVal;
    	}
    	return 0;
    }
    
    bool update_hash( HCRYPTHASH Hash,
    				  const string& Data )
    {
    	if( Data.empty() )  return true;
    	else				return ::CryptHashData( Hash, reinterpret_cast<const BYTE*>( Data.data() ), Data.size(), 0 );
    }
    
    HCRYPTHASH create_session_hash( HCRYPTPROV CryptProvider,
    								ALG_ID HashAlgo,
    								const string& Pass )
    {
    	HCRYPTHASH retVal;
    	if( ::CryptCreateHash( CryptProvider, HashAlgo, 0, 0, &retVal ) )
    	{
    		if( update_hash( retVal, Pass ) ) 
    		{
    			return retVal;
    		}
    		else
    		{
    			::CryptDestroyHash( CryptHash );
    		}
    	}
    	return 0;
    }
    
    HCRYPTKEY create_session_key( HCRYPTPROV Provider,
    							  ALG_ID CryptAlgo,
    							  const string& Pass )
    {
    	HCRYPTHASH CryptHash = create_session_hash( Provider, CALG_MD5, Pass );
    	if( CryptHash )
    	{
    		HCRYPTKEY retVal;
    		DWORD KeyLength = 128;
    		DWORD Flags     = CRYPT_EXPORTABLE | (KeyLength << 16);
    		BOOL Result = ::CryptDeriveKey( Provider, CryptAlgo, CryptHash, Flags, &retVal );
    		::CryptDestroyHash( CryptHash );
    		return retVal;
    	}
    	return 0;
    }
    
    vector<unsigned char> encrypt( ALG_ID CryptAlgo,
    							   const string& Pass,
    							   void const* Data,
    							   unsigned int Size )
    {
    	vector<unsigned char> retVal;
    	if( Data && Size > 0  )
    	{
    		HCRYPTPROV CryptProvider = create_provider( CryptAlgo );
    		if( !CryptProvider )
    		{
    			WIN32_RAISE_LAST_ERROR;
    		}
    		HCRYPTKEY CryptKey = create_session_key( CryptProvider, CryptAlgo, Pass );
    		if( !CryptKey )
    		{
    			::CryptReleaseContext( CryptProvider, 0 );
    			WIN32_RAISE_LAST_ERROR;
    		}
    		const char*   CharBuf = reinterpret_cast<const char*>( Data );
    		unsigned char CryptMem[BUFFER_SIZE];
    		for( int BytesLeft = Size; BytesLeft > 0; BytesLeft -= BLOCK_SIZE )
    		{
    			BOOL FinalBlock			= BytesLeft <= BLOCK_SIZE ? TRUE : FALSE;
    			unsigned long BlockSize = BytesLeft <= BLOCK_SIZE ? BytesLeft : BLOCK_SIZE;
    
    			copy( CharBuf, CharBuf + BlockSize, CryptMem );
    			if( !::CryptEncrypt( CryptKey, 0, FinalBlock, 0, CryptMem, &BlockSize, BUFFER_SIZE ) )
    			{
    				::CryptDestroyKey( CryptKey );
    				::CryptReleaseContext( CryptProvider, 0 );
    				WIN32_RAISE_LAST_ERROR;
    			}
    			CharBuf += BlockSize;
    			retVal.insert( retVal.end(), CryptMem, CryptMem + BlockSize );
    		}
    		::CryptDestroyKey( CryptKey );
    		::CryptReleaseContext( CryptProvider, 0 );
    	}
    	return retVal;
    }
    

    CryptDeriveKey in Zeile 72 liefert mir für CALG_RC4 1 zurück, aber 0 für CALG_AES . Kann/darf ich für AES keinen Session Key aus einem Passwort generieren? Oder mache ich da irgendwas grundsätzlich falsch?

    Edit:
    Zeilennummer korrigiert


Anmelden zum Antworten