// This is a part of the Active Template Library.
// Copyright (C) 1996-2001 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Active Template Library Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Active Template Library product.

#ifndef __ATLCRYPT_H__
#define __ATLCRYPT_H__

#pragma once

#include <wincrypt.h>

namespace ATL
{

class CCryptKey;

class CCryptProv
{
protected:
	HCRYPTPROV m_hProv;

public:
	CCryptProv() throw();
	CCryptProv( const CCryptProv& prov ) throw();
	explicit CCryptProv( HCRYPTPROV hProv, BOOL bTakeOwnership = FALSE ) throw();
	~CCryptProv() throw();

	CCryptProv& operator=( const CCryptProv& prov ) throw();

	HRESULT AddRef() throw();
	void Attach( HCRYPTPROV hProv, BOOL bTakeOwnership = FALSE ) throw();
	HCRYPTPROV Detach() throw();
	HRESULT Release() throw();

	
	HRESULT Initialize(DWORD dwProviderType = PROV_RSA_FULL, 
		LPCTSTR szContainer = NULL, LPCTSTR szProvider = MS_DEF_PROV,
		DWORD dwFlags = 0) throw();
	HRESULT InitVerifyContext(DWORD dwProviderType = PROV_RSA_FULL, 
		LPCTSTR szProvider = MS_DEF_PROV, DWORD dwFlags = 0) throw();
	HRESULT InitCreateKeySet(DWORD dwProviderType = PROV_RSA_FULL,
		LPCTSTR szContainer = NULL, LPCTSTR szProvider = MS_DEF_PROV,
		DWORD dwFlags = 0) throw();

	HRESULT DeleteKeySet(DWORD dwProviderType = PROV_RSA_FULL, 
		LPCTSTR szContainer = NULL, LPCTSTR szProvider = MS_DEF_PROV,
		DWORD dwFlags = 0) throw();
	
	HRESULT Uninitialize();

	HRESULT GetParam(DWORD dwParam, BYTE * pbData, DWORD * pdwDataLen, DWORD dwFlags = 0) throw();
	HRESULT SetParam( DWORD dwParam, BYTE* pbData, DWORD dwFlags = 0) throw();
	HRESULT GetName(LPSTR szBuf, DWORD * pdwLength) throw();
	HRESULT GetContainer(LPSTR szBuf, DWORD * pdwLength) throw();
	HRESULT GetImpType(DWORD * pdwImpType) throw();
	HRESULT GetVersion(DWORD * pdwVersion) throw();
	HRESULT GetProvType(DWORD * pdwType) throw();
	HRESULT GetSecurityDesc(SECURITY_INFORMATION * pSecInfo) throw();
	HRESULT SetSecurityDesc(SECURITY_INFORMATION SecInfo) throw();

	HRESULT GenRandom(ULONG nLength, BYTE* pbBuffer ) throw();
	
/* 
 * No longer exist:
	HRESULT GetUniqueContainer(LPSTR szBuf, DWORD * pdwLength) 
	HRESULT GetSigKeySizeInc(DWORD * pdwInc);
	HRESULT GetKeyxKeySizeInc(DWORD * pdwInc);
 */

	inline HCRYPTPROV GetHandle() throw()
	{
		return m_hProv;
	}
}; // class CCryptProv


// class CCryptHash
// Provides base functionality of hashes.
class CCryptHash
{
protected:
	HCRYPTHASH m_hHash;

public:
	CCryptHash() throw();
	CCryptHash( const CCryptHash& hash ) throw();
	explicit CCryptHash( HCRYPTHASH hHash, BOOL bTakeOwnership = FALSE ) throw();
	~CCryptHash() throw();

	void Attach( HCRYPTHASH hHash, BOOL bTakeOwnership = FALSE ) throw();
	void Destroy() throw();
	HCRYPTHASH Detach() throw();
	HCRYPTHASH Duplicate() const throw();

	HRESULT Uninitialize() throw();
	HRESULT Detach(HCRYPTHASH * phHash) throw();
	HRESULT AddData(const BYTE * pbData, DWORD dwDataLen, DWORD dwFlags = 0) throw();
	HRESULT AddString(LPCTSTR szData, DWORD dwFlags = 0) throw();
	HRESULT GetParam(DWORD dwParam, BYTE * pbData, DWORD * pdwDataLen, DWORD dwFlags = 0) throw();
	HRESULT SetParam(DWORD dwParam, BYTE * pbData, DWORD dwFlags = 0) throw();
	HRESULT GetAlgId(ALG_ID * pAlgId) throw();
	HRESULT GetSize(DWORD * pdwSize) throw();
	HRESULT GetValue(BYTE * pBuf, DWORD * pdwSize) throw();
	HRESULT SetValue(BYTE * pBuf) throw();
	HRESULT Sign(
		BYTE * pbSignature,
		DWORD * pdwSigLen,
		DWORD dwFlags = 0,
		DWORD dwKeySpec = AT_SIGNATURE) throw();
	HRESULT VerifySignature(
		const BYTE * pbSignature,
		DWORD pdwSignLen,
		CCryptKey &PubKey,
		DWORD dwFlags = 0) throw();

	inline HCRYPTHASH GetHandle()
	{
		return m_hHash;
	}
	static CCryptHash EmptyHash;

}; // class CCryptHash

// class CCryptKey
// Provides the functionality for cryptographic keys, i.e. encrypting, decrypting.
class CCryptKey
{
protected:
	HCRYPTKEY m_hKey;

public:
	CCryptKey() throw();
	CCryptKey( const CCryptKey& key ) throw();
	explicit CCryptKey( HCRYPTKEY hKey, BOOL bTakeOwnership = FALSE ) throw();
	~CCryptKey() throw();

	void Attach( HCRYPTKEY hKey, BOOL bTakeOwnership = FALSE ) throw();
	void Destroy() throw();
	HCRYPTKEY Detach() throw();
	HCRYPTKEY Duplicate() const throw();

	HRESULT Uninitialize() throw();
	HRESULT Encrypt(
		BOOL final,
		BYTE * pbData,
		DWORD * pdwDataLen,
		DWORD dwBufLen,
		CCryptHash &Hash = CCryptHash::EmptyHash) throw();

	HRESULT Encrypt(
		const BYTE * pbPlainText,
		DWORD dwPlainTextLen,
		BYTE * pbCipherText,
		DWORD * pdwCipherTextLen,
		CCryptHash &Hash = CCryptHash::EmptyHash) throw();

	HRESULT Decrypt(
		BOOL final,
		BYTE * pbData,
		DWORD * pdwDataLen,
		CCryptHash &Hash = CCryptHash::EmptyHash) throw();
	HRESULT Decrypt(
		const BYTE * pbCipherText,
		DWORD dwCipherTextLen,
		BYTE * pbPlainText,
		DWORD * pdwPlainTextLen,
		CCryptHash &Hash = CCryptHash::EmptyHash) throw();
	HRESULT EncryptString(
		LPCTSTR szPlainText,
		BYTE * pbCipherText,
		DWORD * pdwCipherTextLen,
		CCryptHash &Hash = CCryptHash::EmptyHash) throw();
	HRESULT ExportSimpleBlob(
		CCryptKey &ExpKey,
		DWORD dwFlags,
		BYTE * pbData,
		DWORD * pdwDataLen) throw();
	HRESULT ExportPublicKeyBlob(
		CCryptKey &ExpKey,
		DWORD dwFlags,
		BYTE * pbData,
		DWORD * pdwDataLen) throw();
	HRESULT ExportPrivateKeyBlob(
		CCryptKey &ExpKey,
		DWORD dwFlags,
		BYTE * pbData,
		DWORD * pdwDataLen) throw();
	HRESULT GetParam(DWORD dwParam, BYTE * pbData, DWORD * pdwDataLen, DWORD dwFlags = 0) throw();
	HRESULT SetParam(DWORD dwParam, BYTE * pbData, DWORD dwFlags = 0) throw();
	HRESULT GetAlgId(ALG_ID * pAlgId) throw();
	HRESULT SetAlgId(ALG_ID AlgId, DWORD dwFlags) throw();
	HRESULT GetBlockLength(DWORD * pdwBlockLen) throw();
	HRESULT GetKeyLength(DWORD * pdwKeyLen) throw();
	HRESULT GetSalt(BYTE * pbSalt, DWORD * pdwLength) throw();
	HRESULT SetSalt(BYTE * pbSalt) throw();
	HRESULT SetSaltEx(_CRYPTOAPI_BLOB * pBlobSalt) throw();
	HRESULT GetPermissions(DWORD * pdwPerms) throw();
	HRESULT SetPermissions(DWORD dwPerms) throw();
	HRESULT GetP(BYTE * pbP, DWORD * pdwLength) throw();
	HRESULT SetP(_CRYPTOAPI_BLOB * pBlobP) throw();
	HRESULT SetP(BYTE * pbP, DWORD dwLength) throw();
	HRESULT GetQ(BYTE * pbQ, DWORD * pdwLength) throw();
	HRESULT SetQ(_CRYPTOAPI_BLOB * pBlobQ) throw();
	HRESULT SetQ(BYTE * pbQ, DWORD dwLength) throw();
	HRESULT GetG(BYTE * pbG, DWORD * pdwLength) throw();
	HRESULT SetG(_CRYPTOAPI_BLOB * pBlobG) throw();
	HRESULT SetG(BYTE * pbG, DWORD dwLength) throw();
	HRESULT SetX() throw();
	HRESULT GetEffKeyLen(DWORD * pdwEffKeyLen) throw();
	HRESULT SetEffKeyLen(DWORD dwEffKeyLen) throw();
	HRESULT GetPadding(DWORD * pdwPadding) throw();
	HRESULT SetPadding(DWORD dwPadding) throw();
	HRESULT GetIV(BYTE * pbIV, DWORD * pdwLength) throw();
	HRESULT SetIV(BYTE * pbIV) throw();
	HRESULT GetMode(DWORD * pdwMode) throw();
	HRESULT SetMode(DWORD dwMode) throw();
	HRESULT GetModeBits(DWORD * pdwModeBits) throw();
	HRESULT SetModeBits(DWORD dwModeBits) throw();

	inline HCRYPTKEY GetHandle() throw()
	{
		return m_hKey;
	}

	static CCryptKey EmptyKey;
}; // class CCryptKey



// Specific instances of Keys and Hashes

// class CCryptDerivedKey
// A key that is derived from a hashed password.  Two keys derived 
// from the same password will be identical.
class CCryptDerivedKey : public CCryptKey
{
public:
	HRESULT Initialize(
		CCryptProv &Prov,
		CCryptHash &Hash,
		ALG_ID algid = CALG_RC4,
		DWORD dwFlags = CRYPT_EXPORTABLE) throw();
}; // class CCryptDerivedKey

// class CCryptRandomKey
// A randomly generated key.  Can be used internally by a program 
// to protect data during execution, or can be exported with Crypt.Export
// REVIEW: Currently it is possible to pass in AT_KEYEXCHANGE or AT_SIGNATURE 
// for algid, but these two will generate keys for the current key set, and 
// the resulting handle can only be used for exporting and importing keys or 
// signing hashes.
class CCryptRandomKey : public CCryptKey
{
public:
	HRESULT Initialize(
		CCryptProv &Prov,
		ALG_ID algid = CALG_RC4,
		DWORD dwFlags = CRYPT_EXPORTABLE) throw();
}; // class CCryptRandomKey

// class CCryptUserExKey
// Obtains the user's key exchange key pair.
class CCryptUserExKey : public CCryptKey
{
public:
	HRESULT Initialize(CCryptProv &Prov) throw();
	HRESULT Create(CCryptProv &Prov) throw();
}; // class CCryptUserExKey

// class CCryptUserSigKey
// Obtains the user's signature key pair
class CCryptUserSigKey : public CCryptKey
{
public:
	HRESULT Initialize(CCryptProv &Prov) throw();
	HRESULT Create(CCryptProv &Prov) throw();
}; // class CCryptUserSigKey

// class CCryptImportKey
// Forms a key from an imported key blob
class CCryptImportKey : public CCryptKey
{
public:
	HRESULT Initialize(
		CCryptProv &Prov,
		BYTE * pbData,
		DWORD dwDataLen,
		CCryptKey &PubKey,
		DWORD dwFlags) throw();
}; // class CCryptImportKey


// class CCryptHash
// A generic hash that may or may not take a key.  
// HMAC and MAC are examples or keyed hashes, while
// MD5 and SHA are examples of unkeyed hashes.  This 
// class is for additional hashes that may be added 
// by future Cryptographic Service Providers.
class CCryptKeyedHash : public CCryptHash
{
public:

	HRESULT Initialize(CCryptProv &Prov, ALG_ID Algid, CCryptKey &Key, DWORD dwFlags) throw();
}; // class CCryptKeyedHash

// class CCryptMD5Hash
// RSA's MD5 hash (RSA's most recent hash as of 9/7/99);
class CCryptMD5Hash : public CCryptHash
{
public:

	HRESULT Initialize(CCryptProv &Prov, LPCTSTR szText = NULL) throw();
}; // class CCryptMD5Hash

// class CCryptMD4Hash
// RSA's MD4 hash
class CCryptMD4Hash : public CCryptHash
{
public:

	HRESULT Initialize(CCryptProv &Prov, LPCTSTR szText = NULL) throw();
}; // class CCryptMD4Hash


// class CCryptMD2Hash
// RSA's MD2 hash
class CCryptMD2Hash : public CCryptHash
{
public:

	HRESULT Initialize(CCryptProv &Prov, LPCTSTR szText = NULL) throw();
}; // class CCryptMD2Hash


// class CCryptSHAHash
// The Secure Hash Algorithm hash, from NIST and NSA.  Technically, SHA-1.
class CCryptSHAHash : public CCryptHash
{
public:

	HRESULT Initialize(CCryptProv &Prov, LPCTSTR szText = NULL) throw();
}; // class CCryptSHAHash

// The Secure Hash Algorithm, from NIST and NSA.  Identical to CCryptSHA
typedef CCryptSHAHash CCryptSHA1Hash;


// class CCryptHMACHash
// Hash-base Message Authentication Code keyed hash
class CCryptHMACHash : public CCryptHash
{
public:
	HRESULT Initialize(CCryptProv &Prov, CCryptKey &Key, LPCTSTR szText = NULL) throw();
}; // class CCryptHMACHash

// class CCryptMACHash
// Message Authentication Code keyed hash.  Believed to be less secure than HMAC
class CCryptMACHash : public CCryptHash
{
public:
	HRESULT Initialize(CCryptProv &Prov, CCryptKey &Key, LPCTSTR szText = NULL) throw();
}; // class CCryptMACHash

// class CCryptSSL3SHAMD4Hash
// Hash algorithm used by Secure Socket Layer
class CCryptSSL3SHAMD4Hash : public CCryptHash
{
public:
	HRESULT Initialize(CCryptProv &Prov, CCryptKey &Key, LPCTSTR szText = NULL) throw();
}; // class CCryptSSl3SHAMD4Hash

}; // namespace ATL

#include <atlcrypt.inl>

#endif  // __ATLCRYPT_H__