*--------------------------------------------------------------------------------------------------------------------------------------------------------
* (EN) AUTOGENERATED - ATTENTION!! - NOT INTENDED FOR EXECUTION!! USE ONLY FOR MERGING CHANGES AND STORING WITH SCM TOOLS!!
*--------------------------------------------------------------------------------------------------------------------------------------------------------
*< FOXBIN2PRG: Version="1.21" SourceFile="_crypt.vcx" CPID="1252" /> (Solo para binarios VFP 9 / Only for VFP 9 binaries)
*
*
DEFINE CLASS _cryptapi AS custom 		&& Windows Crypt API Library
 	*< CLASSDATA: Baseclass="custom" Timestamp="" Scale="Pixels" Uniqueid="" />

	#INCLUDE "wincrypt.h"
	*<DefinedPropArrayMethod>
		*m: apideclarations		&& Declare API Fnuctions
		*m: apierror		&& Get the Last Error Number from the System and Display an Error Message on the Screen
		*m: apisetup		&& Initalization Code for this Class
		*m: bintostr		&& Convert a Number to a byte stream, puttnig the least significate byte first and the most significan last.
		*m: createnewkeycontainer		&& Create a New Named Key Container in the Cryptography Service Provider for storage of Signature and Exchange Pairs
		*m: createrandomcryptkeys		&& Create a Key Container, Signature and Exchange Public/Private Key Pairs for that Container.
		*m: cryptacquirecontext		&& See Crypto API documentation.
		*m: cryptcreatehash		&& See Crypto API documentation.
		*m: cryptdecrypt		&& See Crypto API documentation.
		*m: cryptderivekey		&& See Crypto API documentation.
		*m: cryptdestroyhash		&& See Crypto API documentation.
		*m: cryptdestroykey		&& See Crypto API documentation.
		*m: cryptencrypt		&& See Crypto API documentation.
		*m: cryptexportkey		&& See Crypto API documentation.
		*m: cryptgenkey		&& See Crypto API documentation.
		*m: cryptgetkeyparam		&& See Crypto API documentation.
		*m: cryptgetprovparam		&& See Crypto API documentation.
		*m: cryptgetuserkey		&& See Crypto API documentation.
		*m: crypthashdata		&& See Crypto API documentation.
		*m: cryptimportkey		&& See Crypto API documentation.
		*m: cryptreleasecontext		&& See Crypto API documentation.
		*m: cryptsignhash		&& Sign a Hash with a Private Key.
		*m: cryptverifysignature		&& Verify a Signed Hash
		*m: decryptsessionblockfile		&& Decrypt a File using a Session Block Key
		*m: decryptsessionblockstring		&& Decrypt a Strnig using a Block Session Key
		*m: decryptsessionstreamfile		&& Decrypt a File with a session stream key
		*m: decryptsessionstreamstring		&& Decrypt a String using a Session Stream Key
		*m: decryptstr		&& Simple call that returns a decrypted string.
		*m: deletekeycontainer		&& Delete a Cryptography Service Provider Named Key Container
		*m: doubledecrypterror
		*m: doubleencrypterror		&& Calculation of Error Number returned by getlasterror() for Double Encryption/Decryption of a Block String
		*m: encryptsessionblockfile		&& Encrypt a File using a Session Block Key
		*m: encryptsessionblockstring		&& Encrypt a Strnig Using a Session Block Key
		*m: encryptsessionstreamfile		&& Encrypt a File using a Session Stream Key
		*m: encryptsessionstreamstring		&& Encrypt a Strnig using a SessionStream Key
		*m: encryptstrblock
		*m: encryptstrstream
		*m: exportexchangepairkeys		&& Export the Exchange Key Pair
		*m: exportexchangepublickey		&& Export an Exchange Key from a named key container
		*m: exportsessionkey		&& Export a Session Key Encrypted with an Exchange Key
		*m: exportsignaturepairkeys		&& Export the Signature Key Pair
		*m: exportsignaturepublickey		&& Export a Signature Key from a named Container
		*m: formatmessage		&& Formats a system error message into a string for display.
		*m: getcryptblocklength		&& Returns the Block length of a block key. This is need to calculate even block boundries during a block encryption of a large amount of text. To break it down into smaller chunks.
		*m: getcryptsessionkeyhandle		&& Simple call for returning a session key handle.
		*m: getcryptuserkeyhandle		&& Simple call for returning a user key. (Public Key part of a private.public key pair)
		*m: getdoubledecrypterror		&& Return Logical Error Value of Last Rnu of Block Decryption
		*m: getdoubleencrypterror		&& Return Logical Error Value of Last Rnu of Block Encryption
		*m: getisinstalled		&& Return the Flag value for the init check of the Crypto Service Provider Installation
		*m: getlastapierror		&& Returns the last error message trapped by this api. Each low level API call traps the error number returned in this parameter. This is needed for an error check from a form. By the time a form looks for the error number, another one may have occured.
		*m: getlastapierrorcode		&& Returns the code from an error number (BITS 1-16)
		*m: getlastapierrorcustomercodeflag		&& Returns the Customer flag from a system error number (Bit 29)
		*m: getlastapierrorfacility		&& Returns the facitily code of an error number. (Bits 17-28)
		*m: getlastapierrorseverity		&& Return the severity code of an error number (BITS 31-32)
		*m: getlasterror		&& Return the last system error number.
		*m: importpublickey		&& Import a Public Key into a Key Handle Structure
		*m: releasecryptkeyhandle		&& Release handle and free memory allocated to it.
		*m: signfile		&& Create a Signature for a File.
		*m: strtobin		&& Convert a byte stream  with the  least significate byte first and the most significan last into a Number.
		*m: systemmessage		&& Look an Error Number up in the system table and return the string message text.
		*m: usekeycontanier		&& Make a Named or Default key container the one currently in use
		*m: verifyfilesignature		&& Verify File Signature
		*p: ccontainername		&& Name of Crypto Container for Use with this Class
		*p: cprovidername		&& Name of Crypto Provider for use with this class
		*p: hproviderhandle		&& Handle of Crypto Provider/Containter Initialized during setup of this class. For use within this class.
		*p: ldisplayhighlevelapierrors
		*p: ldisplaylowlevelapierrors		&& Display Low Level API Error's as they are encountered (in apierror function)
		*p: ldoubledecrypterror		&& Error for Last Run of Block Decryption
		*p: ldoubleencrypterror		&& Error for Last Run of Block Encryption
		*p: lisinstalled		&& Flag for Crypt Provider Installed
		*p: nlastapierror		&& See Crypto API documentation.
	*</DefinedPropArrayMethod>

	HIDDEN hproviderhandle,ldoubledecrypterror,ldoubleencrypterror,lisinstalled,nlastapierror
	*<PropValue>
		ldisplayhighlevelapierrors = .T.
		Name = "_cryptapi"
		nlastapierror = 0
	*</PropValue>
	
	HIDDEN PROCEDURE apideclarations		&& Declare API Fnuctions
		*** Declare Parameter Types and Location
		*** of the Windows API Crypt Functions
		*** See Crypto API Documentation for Information on Calls
		
		Declare INTEGER CryptAcquireContextA ;
			IN WIN32API AS CryptAcquireContext ;
			INTEGER @hProvHandle, ;
			STRING  cContainer, ;
			STRING  cProvider, ;
			INTEGER nProvType, ;
			INTEGER nFlags
		
		Declare INTEGER CryptCreateHash ;
			IN WIN32API AS CryptCreateHash ;
			INTEGER hProviderHandle, ;
			INTEGER nALG_ID, ;
			INTEGER hKeyhandle, ;
			INTEGER nFlags, ;
			INTEGER @hCryptHashHandle
		
		Declare INTEGER CryptDeriveKey ;
			IN WIN32API AS CryptDeriveKey ;
			INTEGER hProviderHandle, ;
			INTEGER nALG_ID, ;
			INTEGER hBaseDataHandle, ;
			INTEGER nFlags, ;
			INTEGER @hCryptKeyHandle
		
		Declare INTEGER CryptDecrypt ;
			IN WIN32API as CryptDecrypt ;
			INTEGER hKeyHandle, ;
			INTEGER hHashHandle, ;
			SHORT   nFinished, ;
			INTEGER nFlags, ;
			STRING  @cData, ;
			STRING  @nDataLen   && Pointer to DWORD INTEGER
		
		Declare INTEGER CryptDestroyKey ;
			IN WIN32API AS CryptDestroyKey;
			INTEGER hKeyHandle
		
		Declare INTEGER CryptDestroyHash ;
			IN WIN32API AS CryptDestroyHash;
			INTEGER hKeyHandle
		
		Declare INTEGER CryptEncrypt ;
			IN WIN32API as CryptEncrypt ;
			INTEGER hKeyHandle, ;
			INTEGER hHashHandle, ;
			SHORT   nFinished, ;
			INTEGER nFlags, ;
			STRING  @cData, ;
			STRING  @cDataLen, ; && Pointer to DWORD value
			INTEGER nBufLen
		
		Declare INTEGER CryptExportKey ;
			IN WIN32API AS CryptExportKey ;
			INTEGER hKey, ;
			INTEGER hExpKey, ;
			INTEGER nBlobType, ;
			INTEGER nFlags, ;
			STRING  @lcData, ;
			STRING  @lcDataLen    && Pointer to DWORD INTEGER
		
		Declare INTEGER CryptGenKey ;
			IN WIN32API AS CryptGenKey ;
			INTEGER hProviderHandle, ;
			INTEGER nALG_ID, ;
			INTEGER nFlags, ;
			INTEGER @hCryptKeyHandle
		
		Declare INTEGER CryptGetUserKey ;
			IN WIN32API AS CryptGetUserKey;
			INTEGER hProvHandle, ;
			INTEGER nKeySpec, ;
			INTEGER @hUserKey
		
		Declare INTEGER CryptGetKeyParam ;
			IN WIN32API as CryptGetKeyParam ;
			INTEGER hKeyHandle, ;
			INTEGER nParam, ;
			STRING  @cData, ;
			STRING  @nDataLen, ; && Pointer to DWORD INTEGER
			INTEGER nFlags
		
		Declare INTEGER CryptGetProvParam ;
			IN WIN32API as CryptGetProvParam ;
			INTEGER hKeyHandle, ;
			INTEGER nParam, ;
			STRING  @cData, ;
			STRING  @nDataLen, ; && Pointer to DWROD INTEGER
			INTEGER nFlags
		
		Declare INTEGER CryptHashData ;
			IN WIN32API AS CryptHashData ;
			INTEGER hHashHandle, ;
			STRING  @cData, ;
			INTEGER nDataLen, ;
			INTEGER nFlags
		
		Declare INTEGER CryptImportKey ;
			IN WIN32API AS CryptImportKey ;
			INTEGER hProviderHandle, ;
			STRING  @cEncryptedBlob, ;
			INTEGER nEncryptedBlobLen, ;
			INTEGER hDecryptionKeyHandle, ;
			INTEGER nFlags, ;
			STRING  @cImportKeyHandle
		
		Declare INTEGER CryptReleaseContext ;
			IN WIN32API AS CryptReleaseContext ;
			INTEGER hProvHandle, ;
			INTEGER nReserved
		
		Declare INTEGER CryptSignHash ;
			IN WIN32API AS CryptSignHash ;
			INTEGER hHashKeyHandle, ;
			INTEGER nKeyType, ;
			STRING  @cDescription, ;
			INTEGER inFlags, ;
			STRING  @cSignature, ;
			STRING  @cSignatureLen  && Pointer to DWROD INTEGER
		
		Declare INTEGER CryptVerifySignature ;
			IN WIN32API AS CryptVerifySignature ;
			INTEGER hHashKeyHandle, ;
			STRING  @cSignature, ;
			INTEGER nSignatureLen, ;
			INTEGER inPublicKeyHandle, ;
			STRING  @cDescription, ;
			INTEGER inFlags 
		
		Declare INTEGER GetLastError ;
			in win32api as GetLastError
		
		
		Declare INTEGER FindWindow ;
			IN WIN32API ;
			STRING cNull, ;
			STRING cWinName
		
		Declare INTEGER FormatMessage ;
			IN WIN32API ;
			INTEGER nFlags, ;
			STRING @cSource, ;
			INTEGER nMessageId, ;
			INTEGER nLanguageId, ;
			STRING @cMessage, ;
			INTEGER nMessageLen, ;
			STRING @cArgum
			
		
	ENDPROC

	PROCEDURE apierror		&& Get the Last Error Number from the System and Display an Error Message on the Screen
		LPARAMETER picProgram
		LOCAL lnError, lcErrorMessage
		
		*** picProgram - Progrm/User Defined Message String
		***              that Initiated the Call
		*** Returns    - .T.
		
		*** 
		*** Displays the last Windows error using the Windows API
		***
		
		lnError = this.getlasterror()
		lcErrorMessage = this.SystemMessage(lnError)
		
		if this.lDisplayLowLevelApiErrors then
				messagebox(dcErrorIn+picProgram+chr(13)+chr(10)+ ;
		    	       dcErrorSeverity+alltrim(str(this.GetLastApiErrorSeverity(),10))+chr(13)+chr(10)+ ;
		        	   dcErrorFacility+alltrim(str(this.GetLastApiErrorFacility(),10))+chr(13)+chr(10)+ ;
			           dcErrorCode+alltrim(str(this.GetLastApiErrorCode(),10))+chr(13)+chr(10)+ ;
		    	       lcErrorMessage+chr(13)+chr(10), ;
		        	   16, ;
			           dcError)
		endif
		
	ENDPROC

	HIDDEN PROCEDURE apisetup		&& Initalization Code for this Class
		LOCAL lhProviderHandle, lcProviderName, lcContainerName
		*** Create Handle to Crypto Provider
		
		
		If type('this.cProviderName') != T_CHARACTER then
			this.cProviderName = dcEmpty	&& Default
		EndIf
		lcProviderName = this.cProviderName
		If type('this.cContainerName') != T_CHARACTER then
			this.cContainerName = dcFOXPRO_APP	&& Default
		EndIf
		lcContainerName = this.cContainerName
		lhProviderHandle = 0
		
		if !this.CreateRandomCryptKeys(lcContainerName,lcProviderName,dnPROV_RSA_FULL)
			return .F.
		endif
		
		this.CryptAcquireContext(@lhProviderHandle,lcContainerName,lcProviderName,dnPROV_RSA_FULL,0)
		this.hProviderHandle = lhProviderHandle
		
		Return .T.
		
	ENDPROC

	HIDDEN PROCEDURE bintostr		&& Convert a Number to a byte stream, puttnig the least significate byte first and the most significan last.
		LPARAMETER pinInput, pinStringLen
		
		*** pinInput - Integer to be encoded into a character string
		*** return   - Integer represented by character string
		***            Left most Character is least significant
		***            Right most character is most significant
		
		*** Converts an Integer into a Character String
		
		LOCAL lnreturn, lnCounter
		
		lcReturn = dcEmpty
		for lnCounter = 1 to pinStringLen
		   lcReturn = lcReturn + chr(bitand(bitrshift(pinInput,bitlshift((lnCounter-1),3)),255))
		endfor
		
		return lcReturn
	ENDPROC

	PROCEDURE createnewkeycontainer		&& Create a New Named Key Container in the Cryptography Service Provider for storage of Signature and Exchange Pairs
		LPARAMETER pcContainerName
		*** Creates a new Key Container and Makes it the Container Currently in Use
		
		LOCAL lnError, lhProviderHandle
		
		lhProviderHandle = 0
		
		this.cContainerName = pcContainerName
		
		lnError = this.CryptAcquireContext(@lhProviderHandle,pcContainerName,this.cProviderName,dnPROV_RSA_FULL,dnCRYPT_NEWKEYSET)
		If lnError = 0
			this.hProviderHandle = 0
			if this.lDisplayLowLevelApiErrors
				messagebox(dcCRYPTNEWKEYCONTAINER_ERR_LOC,MB_APPLMODAL+MB_ICONEXCLAMATION+MB_OK,dcError)
			endif
			this.nlastapierror = getlasterror()
			this.apierror(program())
			return .F.
		else
			this.nlastapierror = 0
			this.hProviderHandle = lhProviderHandle
		endif
		
		return .T.
	ENDPROC

	HIDDEN PROCEDURE createrandomcryptkeys		&& Create a Key Container, Signature and Exchange Public/Private Key Pairs for that Container.
		LPARAMETER picContainerName, picProviderName, pinProviderType
		
		* pihProviderHandle	- 	Handle of CSP
		* picContainerName	- 	Name of Container to Create (NULL is Default)
		* picProviderName	- 	Name of CSP Provider (NULL is Default)
		* pihProviderType	-	MS Windows Defnied CSP provider Type
		
		* Returns			- 	.T. Success, .F. Error
		
		** Creates a Key Container in the CSP Provider
		
		local lnError, lhUserKey, lhProviderHandle
		
		lhProviderHandle = 0
		lhUserKey = 0
		* Create New Key Container
		lnError = CryptAcquireContext(@lhProviderHandle,picContainerName,picProviderName,pinProviderType,dnCRYPT_NEWKEYSET)
		if lnError = 0 then
			do case
				* Test for Key Containter Already Exists (This is an OK Condition)
				case bitxor(getlasterror(),0x8009000F)=0
					this.nlastapierror = 0
					* Open Context Normally
					lnError = CryptAcquireContext(@lhProviderHandle,picContainerName,picProviderName,pinProviderType,0)
					if lnError = 0
						this.nlastapierror = getlasterror()
						if this.lDisplayLowLevelApiErrors
							messagebox(dcCRYPTPROVTYP_ERR_LOC,MB_APPLMODAL+MB_ICONEXCLAMATION+MB_OK,dcError)
						endif
						this.apierror(program())
						return .F.
					endif
				* Test for Service Provider Not Defined Error
				case bitxor(getlasterror(),0x80090017)=0
					this.nlastapierror = getlasterror()
					if this.lDisplayLowLevelApiErrors
						messagebox(dcCRYPTPROVTYP_ERR_LOC,MB_APPLMODAL+MB_ICONEXCLAMATION+MB_OK,dcError)
					endif
					this.apierror(program())
					return .F.
				* Any Other Error
				otherwise
					this.nlastapierror = getlasterror()
					if this.lDisplayLowLevelApiErrors
						messagebox(dcCRYPTINITIALIZE_ERR_LOC,MB_APPLMODAL+MB_ICONEXCLAMATION+MB_OK,dcError)
					endif
					this.apierror(program())
					return .F.
			endcase
		else
			this.nlastapierror = 0
		endif
		
		* Try to Retrieve Signature Key
		lnError = CryptGetUserKey(lhProviderHandle,dnAT_SIGNATURE,@lhUserKey)
		if lnError = 0 then
			* Test for NTE_NO_KEY 
			if bitxor(getlasterror(),0x8009000D)=0 then
				* (Attempt to Create a Key)
				lnError = CryptGenKey(lhProviderHandle,dnAT_SIGNATURE,0,@lhUserKey)
				if lnError = 0 then
					this.nlastapierror = getlasterror()
					if this.lDisplayLowLevelApiErrors
						messagebox(dcCRYPTSIGGENKEY_ERR_LOC,MB_APPLMODAL+MB_ICONEXCLAMATION+MB_OK,dcError)
					endif
					this.apierror(program())
					this.CryptReleaseContext(lhProviderHandle)
					return .F.
				else
					this.nlastapierror = 0
				endif
			else
				this.nlastapierror = getlasterror()
				if this.lDisplayLowLevelApiErrors
					messagebox(dcCRYPTSIGGETKEY_ERR_LOC,MB_APPLMODAL+MB_ICONEXCLAMATION+MB_OK,dcError)
				endif
				this.apierror(program())
				this.CryptReleaseContext(lhProviderHandle)
				return .F.
			endif
		else
			this.nlastapierror = 0
		endif
		
		lnError = CryptDestroyKey(lhUserKey)
		
		* Try to Retrieve Exchange Key
		lnError = CryptGetUserKey(lhProviderHandle,dnAT_KEYEXCHANGE,@lhUserKey)
		if lnError = 0 then
			* Test for NTE_NO_KEY
			if bitxor(getlasterror(),0x8009000D)=0 then
				* (Attempt to Create a Key)
				lnError = CryptGenKey(lhProviderHandle,dnAT_KEYEXCHANGE,0,@lhUserKey)
				if lnError = 0 then
					this.nlastapierror = getlasterror()
					if this.lDisplayLowLevelApiErrors
						messagebox(dcCRYPTEXCGENKEY_ERR_LOC,MB_APPLMODAL+MB_ICONEXCLAMATION+MB_OK,dcError)
					endif
					this.apierror(program())
					this.CryptReleaseContext(lhProviderHandle)
					return .F.
				else
					this.nlastapierror = 0
				endif
			else
				this.nlastapierror = getlasterror()
				if this.lDisplayLowLevelApiErrors
					messagebox(dcCRYPTEXCGETKEY_ERR_LOC,MB_APPLMODAL+MB_ICONEXCLAMATION+MB_OK,dcError)
				endif
				this.apierror(program())
				this.CryptReleaseContext(lhProviderHandle)
				return .F.
			endif
		else
			this.nlastapierror = 0
		endif
		
		lnError = CryptDestroyKey(lhUserKey)
		
		this.CryptReleaseContext(lhProviderHandle)
		this.lIsInstalled = .T.
		return .T.
		
	ENDPROC

	HIDDEN PROCEDURE cryptacquirecontext		&& See Crypto API documentation.
		Lparameter pihProvhandle, picContainer, picProvider, pinProvType, pinFlags
		
		*** pihProvHandle - Variable passed by reference and defnied as REPLICATE(CHR(0),4)
		*** picContainer - CHR(0) terminated String Name of the Key Container
		***                null means a default key container will be used
		***                A container is where the keys are stored
		***			 	   Depending on the Crypt Provider
		***                it could be stored internally,
		***                In the registry, on the hard drive,
		***				   or in a special hardware device.
		*** picProvider -  CHR(0) terminated String Name of the Crypt Provider
		***		 	 	   Null means the user default provider is used
		***				   The user default provider is identified in the Registry
		***				   HKEY_LOCAL_MACHINE\Software\Microsoft\;
		***				   cryptography\defaults\provider types\typexx\name
		***				   Windows supports multiple providers
		***                The provider is the program that does all 
		***                of the work. It's conforms to the Windows API
		***                calls that interface with it.
		*** pinProvType -  Identifies the Crypt Provider Type
		***				   Defined in WinCrypt.h
		***				   i.e. PROV_RSA_FULL
		*** pinFlags    -  Normally 0
		***				   Defined in WinCrypt.h
		***				   Used to carry out specific functions
		*** Return - Handle to the Crypt Provider in pihProvHandle
		
		*** Creates a Crypt Key Container handle for Use in Most Crypt Functions
		
		Local lnError
		
		lnError = CryptAcquireContext( ;
			@pihProvhandle, ;
			picContainer, ;
			picProvider, ;
			pinProvType, ;
			pinFlags)
		
		if lnError = 0 then
			this.nlastapierror = getlasterror()
			this.apierror(program())
		else
			this.nlastapierror = 0
		endif
		
		Return
		
	ENDPROC

	HIDDEN PROCEDURE cryptcreatehash		&& See Crypto API documentation.
		Lparameter pihProvHandle, pinALG_ID, pihKeyHandle, pinFlags, pihCryptHashHandle
		
		*** pihProvHandle - Crypto Service Provider Handle,
		***				    Returned by CryptAcquireContext() 
		*** pinALG_ID	  - Algorith Identifier (defined in wincrypt.h) for hashing
		*** pihKeyHandle  - If Keyed Hash, Handle of the Key
		***					Returned by CryptDeriveKey()
		***	 			    or CryptGenKey(), else 0
		*** pinFlags	  - Must be 0, reserved for future use
		*** pihCryptHashHandle - Reference to Pointer to HashHandle
		*** Return		  - Handle of the Hash Object in pihCryptHashHandle,
		***				    Used by CryptHashKey() or
		***				    CryptHashSessionKey()
		
		*** Create a Hash Object Handle for se in Hashing Functions
		
		Local lnError
		
		lnError = CryptCreateHash( ;
			pihProvHandle, ;
			pinALG_ID, ;
			pihKeyHandle, ;
			pinFlags, ;
			@pihCryptHashHandle)
		
		if lnError = 0 then
			this.nlastapierror = getlasterror()
			this.apierror(program())
		else
			this.nlastapierror = 0
		endif
		
		Return
		
	ENDPROC

	HIDDEN PROCEDURE cryptdecrypt		&& See Crypto API documentation.
		Lparameter pihKeyHandle, pihHashKeyHandle, pinFinal, ;
				   pinFlags, ptcData, ptcDataLen
		
		*** pihKeyHandle	 - Handle of Key Objcet,
		***					   Returned by CryptGenKey() or CryptImportKey()
		*** pihHashKeyHandle - 0 if no hash is to be done, else 
		***                	   Handle of Hash Object Returned by CryptCreateHash()
		*** pinFinal		 - -1 (True) if last block,
		***					   0 (False) if not the last block to decrypt
		*** pinFlags		 - Optional: CRYPT_OAEP when Enhanced and RSA Decryption
		***				   	   for PKCS #1 version 2 formatting
		*** ptcData		 	 - in: Data String to be Decrypted; out: decrypted data
		*** ptcDataLen	 	 - in: Length of pcData to decrypt; out: length of decrypted data
		***                    Encoded as a 4 character string (use - BinToStr(n,4) to create
		***                                                     use - StrToBin(c) to read)
		*** Return		 	 - Decrypted Data via Left(pcData,lnDataLenLen)
		
		*** Used to Decrypt and Simultaneously Hash (Optional:pnHashKey) the Decrypted Data to Verify it's
		*** signature
		
		Local lnError
		
		lnError = CryptDecrypt( ;
			pihKeyHandle, ;
			pihHashKeyHandle, ;
			pinFinal, ;
			pinFlags, ;
			@ptcData, ;
			@ptcDataLen)
		
		if lnError = 0 then
			this.nlastapierror = getlasterror()
			this.apierror(program())
		else
			this.nlastapierror = 0
		endif
		
		Return left(ptcData,this.StrToBin(ptcDataLen))
	ENDPROC

	HIDDEN PROCEDURE cryptderivekey		&& See Crypto API documentation.
		Lparameter pihProvHandle, pinALG_ID, pihBaseDataHandle, pinFlags, pihCryptKeyHandle
		
		*** pihProvHandle	  - Handle Returned by CryptAcquireContext()
		*** pinALG_ID		  - Algorithm Identifier (defined in wincrypt.h), cypher to use
		***						--- Session Keys ---
		***	   				    	--- Microsoft Base CSP ---
		***							dnCALG_RC2   block
		***							dnCALG_RC4   stream
		***	   				    	--- Microsoft Enhamced CSP ---
		***							CALG_DES     DES block
		***							CALG_3DES	 Triple DES Block
		***							CALG_3DES_112 Triple DES 2 Key Block
		***							--- Diffie-Hellman CSP ---
		***							CALG_DH_EPHEM
		***							CALG_DH_SF
		***						--- Public/Private Key Pairs ---
		***						dnAT_KEYEXCHANGE
		***						dnAT_SIGNATURE
		*** pihBaseDataHandle - Handle of Hashed Key Returned by CryptHashData
		*** pinFlags		  - Upper 16 bits - The Size of the Session key to Generate
		***                                     0x0080???? = 128 bits
		***                                     0x0028???? = 40 bits
		***					    Lower 16 Bits: (Defined in wincrypt.h)
		***									  CRYPT_CREATE_SALT - value calculated
		***                                                       from unused session key bits
		***														  retrieved with CryptGetKeyParam()
		***					   				  dnCRYPT_EXPORTABLE    - Can Export Key with CryptExportKey()
		***					                  CRYPT_NO_SALT     - Do not Create a Salt Value
		***									  CRYPT_PREGEN      - Initial DSS Key Generation
		***					                  CRYPT_UPDATE_KEY  - If multiple hash vales are required
		***														  then use this flag to update the last
		***     												  key with this hash value. MicroSoft's
		***														  CSP does not support this functionality
		*** Returns			 - Handle of Crypt Key in pihCryptKeyHandle
		
		*** Used to Create a Key Handle for use in CryptEncrypt() and CryptDecrypt()
		
		Local lnError
		
		lnError = CryptDeriveKey( ;
			pihProvHandle, ;
			pinALG_ID, ;
			pihBaseDatahandle, ;
			pinFlags, ;
			@pihCryptKeyHandle)
		
		if lnError = 0 then
			this.nlastapierror = getlasterror()
			this.apierror(program())
		else
			this.nlastapierror = 0
		endif
		
		Return 
		
	ENDPROC

	HIDDEN PROCEDURE cryptdestroyhash		&& See Crypto API documentation.
		Lparameter pihHashKeyHandle
		
		*** pihHashKeyHandle - Handle of Hashed Key returned by CryptCreateHash()
		*** Return           - .T.
		
		*** Destroys the Hashed Key Pointer where the hashed crypt key was located
		*** This is suggested for Security Reasons
		*** Many CSP's also scrub the key before removing the handle. This function is 
		*** not required to scrub the container, just to destroy the pointer.
		
		
		Local lnError
		
		lnError = cryptdestroyhash(pihHashKeyHandle)
		
		if lnError = 0 then
			this.nlastapierror = getlasterror()
			this.apierror(program())
		else
			this.nlastapierror = 0
		endif
		
		return
	ENDPROC

	HIDDEN PROCEDURE cryptdestroykey		&& See Crypto API documentation.
		Lparameter pihKeyHandle
		
		*** pihKeyHandle - Handle of CSP Key returned by CryptAcquireContext()
		*** Return       - .T.
		
		*** Destroys the Key Container Pointer where the encrypt/decrypt key was located
		*** This is suggested for Security Reasons
		*** Many CSP's also scrub the key before removing the handle. This function is 
		*** not required to scrub the container, just to destroy the pointer.
		
		Local lnError
		
		lnError = cryptdestroykey(pihKeyHandle)
		
		if lnError = 0 then
			this.nlastapierror = getlasterror()
			this.apierror(program())
		else
			this.nlastapierror = 0
		endif
		
		return
	ENDPROC

	HIDDEN PROCEDURE cryptencrypt		&& See Crypto API documentation.
		Lparameter 	pihKeyHandle, pihHashKeyHandle, pinFinal, ;
					pinFlags, ptcData, ptcDataLen, pinMaxDataLen
		
		*** pihKeyHandle	 - Handle of Key Objcet,
		***					   Returned by CryptGenKey() or CryptImportKey()
		*** pihHashKeyHandle - 0 if no hash is to be done, else 
		***                	     Handle of Hash Object, Returned by CryptCreateHash()
		*** pinFinal		 - -1 (True) if last block, 0 (False) if not the last block to decrypt
		*** pinFlags		 - Optional: CRYPT_OAEP when Enhanced and RSA Encryption
		***				   	   for PKCS #1 version 2 formatting
		*** ptcData		 	 - in: Data String to be Encrypted; out: Encrypted data
		*** ptcDataLen	 	 - in: Length of pcData to Encrypt; out: length of Encrypted data
		***                    Encoded as a 4 character string (use - BinToStr(n,4) to create
		***                                                     use - StrToBin(c) to read)
		*** pinMaxDataLen	 - Length of pcData buffer (Block Encryption Requires extra buffer space
		***					   by as much as 1 Block Length
		*** Return		 	 - Decrypted Data via Left(pcData,lnDataLenLen)
		
		*** Used to Encrypt and Simultaneously Hash (Optional:pnHashKey) the Data
		*** for use by the CryptGetHashParam() or CryptSignHash() signature
		
		Local lnError
		lnError = CryptEncrypt( ;
			pihKeyHandle, ;
			pihHashKeyHandle, ;
			pinFinal, ;
			pinFlags, ;
			@ptcData, ;
			@ptcDataLen, ;
			pinMaxDataLen)
		
		if lnError = 0 then
			this.nlastapierror = getlasterror()
			this.apierror(program())
		else
			this.nlastapierror = 0
		endif
		
		Return left(ptcData,this.strtobin(ptcDataLen))
		
		
	ENDPROC

	HIDDEN PROCEDURE cryptexportkey		&& See Crypto API documentation.
		Lparameter pihKeyHandle, pihExpKeyHandle, pinBlobType, pinFlags, poKeyString
		
		*** pihKeyHandle    - Handle of the Key to Be Exported
		*** pihExpKeyHandle - Handle of a Crypt Key to use to encrypt this key
		***					  If Public Key is to be exported, then set to 0
		***				      Usually this is the public key of the destination Computer/User
		*** pinBlobType	    - (defined in wincrypt.h)
		***				   	  	OPAQUEKEYBLOB - Store an encrypted session key in the CSP
		***				     	dnPRIVATEKEYBLOB - Private/Public Key pair
		***						dnPUBLICKEYBLOB - Public Key
		***						dnSIMPLEBLOB - Session Key
		*** pinFlags	 	-	(defined in wincrypt.h)
		***						CRYPT_DESTROYKEY - destroy OPAQUEKEYBLOB key in CSP
		***						CRYPT_SSL2_FALLBACK - 
		***						CRYPT_OAEP -  when Enhanced and RSA Encryption
		***				   	    	          for PKCS #1 version 2 formatting
		*** poKeyString		-  Encrypted Key String
		*** Returns		    .T. success
		***					.F. Failure
		
		*** Exports a crypto key from a Crypto Service Provider in a Secure Manner.
		
		Local lcData, lnError
		Local lcLen, lcEmptyString
		
		lcLen = this.BinToStr(0,4)
		lcEmptyString = dcEmpty
		
		* Get the Len of the String First
		*	pihExpKeyHandle, ;
		
		    CryptExportKey( ;
			pihKeyHandle, ;
			pihExpKeyHandle, ;
			pinBlobType, ;
			pinFlags, ;
			@lcEmptyString, ;
			@lcLen)
		
		* Create the String and Stuff it with the BLOB
		lcData = space(this.StrToBin(lcLen))
		lnError = CryptExportKey( ;
			pihKeyHandle, ;
			pihExpKeyHandle, ;
			pinBlobType, ;
			pinFlags, ;
			@lcData, ;
			@lcLen)
		
		if lnError = 0 then
			this.nlastapierror = getlasterror()
			this.apierror(program())
			Return .F.
		else
			this.nlastapierror = 0
		endif
		
		poKeyString = lcData
		
		Return .T.
		
	ENDPROC

	HIDDEN PROCEDURE cryptgenkey		&& See Crypto API documentation.
		Lparameter pihProvHandle, pinALG_ID, pinFlags, pihCryptKeyHandle
		
		*** pihProvHandle	  - Handle Returned by CryptAcquireContext()
		*** pinALG_ID		  - Algorithm Identifier (defined in wincrypt.h), cypher to use
		***						--- Session Keys ---
		***	   				    	--- Microsoft Base CSP ---
		***							dnCALG_RC2   block
		***							dnCALG_RC4   stream
		***	   				    	--- Microsoft Enhamced CSP ---
		***							CALG_DES     DES block
		***							CALG_3DES	 Triple DES Block
		***							CALG_3DES_112 Triple DES 2 Key Block
		***							--- Diffie-Hellman CSP ---
		***							CALG_DH_EPHEM
		***							CALG_DH_SF
		***						--- Public/Private Key Pairs ---
		***						dnAT_KEYEXCHANGE
		***						dnAT_SIGNATURE
		*** pinFlags		  - Upper 16 bits - The Size of the key to Generate
		***                                     0x0800???? = 2048 bits
		***					    Lower 16 Bits: (Defined in wincrypt.h)
		***									  CRYPT_CREATE_SALT - value calculated
		***                                                       from unused session key bits
		***														  retrieved with CryptGetKeyParam()
		***					   				  dnCRYPT_EXPORTABLE  - Can Export Key with CryptExportKey()
		***					                  CRYPT_NO_SALT     - Do not Create a Salt Value
		***									  CRYPT_PREGEN      - Initial DSS Key Generation
		***									  CRYPT_USER_PROTECTED - Notify User via Dialog
		***                											 on certain access functions
		*** 														 of this key (IE4 or greater)
		*** pihCryptKeyHandle - Reference to CryptKeyHandle, Initialize as replicate(chr(0),4)
		*** Returns			 - Handle of Generated Crypt Key
		
		*** Used to Create a Random Key Handle for use in CryptEncrypt() and CryptDecrypt()
		
		
		Local lnError
		
		lnError = CryptGenKey( ;
			pihProvHandle, ;
			pinALG_ID, ;
			pinFlags, ;
			@pihCryptKeyHandle)
		
		if lnError = 0 then
			this.nlastapierror = getlasterror()
			this.apierror(program())
		else
			this.nlastapierror = 0
		endif
		
		Return 
		
	ENDPROC

	HIDDEN PROCEDURE cryptgetkeyparam		&& See Crypto API documentation.
		Lparameter 	pihKeyHandle, pinParam, ptcData, ;
			 		ptcDataLen, pinFlags
		
		*** pihKeyHandle	 - Handle of Key Objcet,
		***					   Returned by CryptGenKey() or CryptImportKey()
		*** pinParam		 - Parameter to Retrieve(defined in wincrypt.h)
		***                     --- All Keys Support ---
		***                     dnKP_IV Initialization vector
		***                     dnKP_SALT        Salt value
		***                     dnKP_PADDING     Padding values
		***                     dnKP_MODE        Mode of the cipher
		***                     dnKP_MODE_BITS   Number of bits to feedback
		***                     dnKP_PERMISSIONS Key permissions DWORD
		***                     dnKP_ALGID       Key algorithm
		***						dnKP_BLOCKLEN    Block size of the cipher
		***                     --- pihKeyHandle is DSS Key BLOB Pointer ---
		***					    dnKP_P			 Prime Modulus from DSS Key BLOB
		***					    dnKP_Q			 Prime Q from DSS Key BLOB
		***					    dnKP_G			 Generator from DSS Key BLOB
		***                     --- pihKeyHandle is Block Session Key Pointer ---
		***                     dnKP_IV          Initialization vector
		***                     dnKP_SALT        Salt value
		***                     dnKP_PADDING     Padding values
		***                     dnKP_MODE        Mode of the cipher
		***                     dnKP_MODE_BITS   Number of bits to feedback
		***                     dnKP_PERMISSIONS Key permissions DWORD
		***                     dnKP_ALGID       Key algorithm
		***                     dnKP_BLOCKLEN    Block size of the cipher
		*** ptcData		 	 - in: Buffer String; out:Parameter String 
		*** ptcDataLen	 	 - in: Length of ptcData Buffer;
		***                    out: length of Parameter String
		***                    Encoded as a 4 character string (use - BinToStr(n,4) to create
		***                                                     use - StrToBin(c) to read)
		*** Return		 	 - Requested Parameter as a String Value
		
		*** Used to return a Parameter from the CSP that pihKeyHandle points to
		
		Local lnError
		
		lnError = CryptGetKeyParam( ;
			pihKeyHandle, ;
			pinParam, ;
			@ptcData, ;
			@ptcDataLen, ;
			pinFlags)
		
		if lnError = 0 then
			this.nlastapierror = getlasterror()
			this.apierror(program())
		else
			this.nlastapierror = 0
		endif
		
		Return left(ptcData,this.StrToBin(ptcDataLen))
		
	ENDPROC

	HIDDEN PROCEDURE cryptgetprovparam		&& See Crypto API documentation.
		Lparameter 	pihKeyHandle, pinParam, ptcData, ;
					ptcDataLen, pinFlags
		
		*** pihKeyHandle	 - Handle of Key Objcet,
		***					   Returned by CryptGenKey() or CryptImportKey()
		*** pinParam		 - Parameter to Retrieve(defined in wincrypt.h)
		*** 					dnPP_ENUMALGS             
		*** 					dnPP_ENUMCONTAINERS       
		*** 					dnPP_IMPTYPE              
		*** 					dnPP_NAME                 
		*** 					dnPP_VERSION              
		*** 					dnPP_CONTAINER            
		***						PP_SIG_KEYSIZE_INC
		***						PP_KEYX_KEYSIZE_INC
		***						PP_ENUMALGS_EX 
		***					    PP_KEYSET_SEC_DESCR
		***						PP_UNIQUE_CONTAINER 
		***					    PP_PROVTYPE
		***                     PP_USE_HARDWARE_RNG
		*** ptcData		 	 - in: Buffer String; out:Parameter String 
		*** ptcDataLen	 	 - in: Length of ptcData Buffer;
		***                    out: length of Parameter String
		***                    Encoded as a 4 character string (use - BinToStr(n,4) to create
		***                                                     use - StrToBin(c) to read)
		*** Return		 	 - Requested Parameter as a String Value
		
		*** Used to return a Parameter from the CSP that pihKeyHandle points to
		
		Local lnError
		
		lnError = CryptGetProvParam( ;
			pihKeyHandle, ;
			pinParam, ;
			@ptcData, ;
			@ptcDataLen, ;
			pinFlags)
		
		if lnError = 0 then
			this.nlastapierror = getlasterror()
			this.apierror(program())
		else
			this.nlastapierror = 0
		endif
		
		Return left(ptcData,this.StrToBin(ptnDataLen))
		
	ENDPROC

	HIDDEN PROCEDURE cryptgetuserkey		&& See Crypto API documentation.
		Lparameter pihProvHandle, pinKeySpec, pohUserKeyHandle
		
		*** pihProvHandle	 - Handle of Service Provider
		***					   Returned by CryptGenKey() or CryptImportKey()
		*** pinKeySpec       - defined in WinCrypt.h
		***					   	dnAT_SIGNATURE
		***						dnAT_KEYEXCHANGE
		*** pohUserKeyHandle - Handle to User Key
		Local lnUserKey, lnError
		
		lnError = CryptGetUserKey( ;
			pihProvHandle, ;
			pinKeySpec, ;
			@pohUserKeyHandle)
		
		if lnError = 0 then
			this.nlastapierror = getlasterror()
			this.apierror(program())
			Return .F.
		else
			this.nlastapierror = 0
		endif
		
		Return .T.
		
	ENDPROC

	HIDDEN PROCEDURE crypthashdata		&& See Crypto API documentation.
		Lparameter pihHashKeyHandle, picData, pinDataLen, pinFlags
		
		*** pihHashKeyHandle - Handle of Hash Object, Returned by CryptCreateHash()
		*** picData		 	 - Data String to be added to Hash Key
		*** pinDataLen		 - Length of picData
		*** pinFlags		 - Length of pcData buffer (Block Encryption Requires extra buffer space
		***					   by as much as 1 Block Length
		*** Return		 	 - .T.
		
		*** Used to added data to the hash key pointed to by hash handle
		
		Local lnError
		
		lnError = CryptHashData( ;
			pihHashKeyHandle, ;
			@picData, ;
			pinDataLen, ;
			pinFlags)
		
		if lnError = 0 then
			this.nlastapierror = getlasterror()
			this.apierror(program())
		else
			this.nlastapierror = 0
		endif
		
		Return
		
	ENDPROC

	HIDDEN PROCEDURE cryptimportkey		&& See Crypto API documentation.
		Lparameter pihProviderHandle, picBlob, pinBlobLen, pihImpKeyHandle, pinFlags, pthKeyHandle
		
		*** pihProviderHandle - Handle of the CSP
		*** @picBlob	    -  Encrypted Blob
		*** pinBlobLen      - Length of Encrypted Blob
		*** pihImpKeyHandle - Handle of a Crypt Key to use to decrypt this key
		***				      Usually this is the private key of the this Computer
		*** pinFlags	 	-	(defined in wincrypt.h)
		***						CRYPT_DESTROYKEY - destroy OPAQUEKEYBLOB key in CSP
		***						CRYPT_SSL2_FALLBACK - 
		***						CRYPT_OAEP -  when Enhanced and RSA Encryption
		***				   	    	          for PKCS #1 version 2 formatting
		*** pthKeyHandle    - Handle of the Key to Be Exported
		
		*** Returns			-  Sesion Key Handle
		
		*** Imports a crypto key by Decrypting a Key Blob and converting it into a key Handle
		
		Local lnError
		Local lcKeyHandle
		
		lcKeyHandle = this.BinToStr(pthKeyHandle,4)
		lnError = CryptImportKey( ;
			pihProviderHandle, ;
			@picBlob, ;
			pinBlobLen, ;
			pihImpKeyHandle, ;
			pinFlags, ;
			@lcKeyHandle ;
			)
		
		pthKeyHandle = this.StrToBin(lcKeyHandle)
		
		if lnError = 0 then
			this.nlastapierror = getlasterror()
			this.apierror(program())
		else
			this.nlastapierror = 0
		endif
		
		Return 
		
	ENDPROC

	HIDDEN PROCEDURE cryptreleasecontext		&& See Crypto API documentation.
		LPARAMETER pihProviderHandle
		
		*** pihContextHandle - Handle of CSP to Release
		
		*** Release a CSP Handle and Frees up Memory Reserved by it
		
		CryptReleaseContext(pihProviderHandle,0)
		
		Return
	ENDPROC

	HIDDEN PROCEDURE cryptsignhash		&& Sign a Hash with a Private Key.
		Lparameter pihHashKeyHandle, pinKeyType, pinFlags
		
		*** pihHashKeyHandle - Handle of Hash Object, Returned by CryptCreateHash()
		*** pinKeyType 	 	 - Private Key to Sign with (usually AT_SIGNATURE)
		*** pinFlags		 - Flags (See Crypto API Documentation)
		***					   by as much as 1 Block Length
		*** Returned	 	 - Signed String in picSignature
		
		*** Used to Sign a Hash for storage as a signanture.
		
		Local lnError, lnSignatureLen
		Local lcDescription, lcSignature, lcSingatureLen
		
		*** lcDescription	 - No Longer used, set to NULL
		lcDescription = dcEmpty
		lcSignature = dcEmpty
		lcSignatureLen = this.BinToStr(0,4)
		* Get the Signature Length
		lnError = CryptSignHash( ;
			pihHashKeyHandle, ;
			pinKeyType, ;
			@lcDescription, ;
			pinFlags, ;
			@lcSignature, ;
			@lcSignatureLen ;
			)
		
		*** Do not check for error, since More Data Needed may result from 0 length
		lcSignature = space(this.StrToBin(lcSignatureLen))
		lnError = CryptSignHash( ;
			pihHashKeyHandle, ;
			pinKeyType, ;
			@lcDescription, ;
			pinFlags, ;
			@lcSignature, ;
			@lcSignatureLen ;
			)
		
		if lnError = 0 then
			this.nlastapierror = getlasterror()
			this.apierror(program())
		else
			this.nlastapierror = 0
		endif
		
		Return lcSignature
		
	ENDPROC

	HIDDEN PROCEDURE cryptverifysignature		&& Verify a Signed Hash
		Lparameter pihHashKeyHandle, picSignature, pihPublicKeyHandle, pinFlags
		
		*** pihHashKeyHandle - Handle of Hash Object, Returned by CryptCreateHash()
		*** picSignature	 - Signature String to Verify
		*** pihPublicKeyHandle - Handle of Public Signature Key
		*** pinFlags		 - Flags (See Crypto API Documentation)
		*** Returns		 	 - .T. if verified, .F. if not verified or a different error occured
		
		*** Used to Verify a Signature
		
		Local lnError, lnSignatureLen
		
		lnSignatureLen = len(picSignature)
		lnError = CryptVerifySignature( ;
			pihHashKeyHandle, ;
			@picSignature, ;
			lnSignatureLen, ;
			pihPublicKeyHandle, ;
			dcEmpty, ;
			pinFlags ;
			)
		
		if lnError = 0 then
			* Signature did not verify or a different error occured.
			* Error Number for NTE_BAD_SIGNATURE 0x80090006
			* getlasterror() returns a signed number and 0x??????? is unsigned,
			* getlasterror() and 0x???? cannot be compared with an = 
			*    compare with bitxor()
			this.nlastapierror = getlasterror()
			this.apierror(program())
			Return .F.
		else
			* Signature Verified
			this.nlastapierror = 0
			Return .T.
		endif
		
	ENDPROC

	PROCEDURE decryptsessionblockfile		&& Decrypt a File using a Session Block Key
		LPARAMETER pcEncryptedFileName, pcPassword, pcDecryptedFileName
		*** pcEncryptedFileName - File Path and Name of file with Encrypted Contents
		*** pcPassword - Password
		*** pcDecryptedFileName - File Path and Name of file to Create with Decrypted Contents
		
		*** Returns .T. - Successful
		***         .F. - Error
		
		LOCAL lhKeyHandle, lhExportKeyHandle, lhEncryptedFileHandle, lhDecryptedFileHandle
		LOCAL lnYN, lnBytesWritten, lnKeyLength, lnBlockReadSize, lnCryptBlockLen
		LOCAL lcEncryptedSessionKey, lcEncryptedText, lcTestLength
		
		this.lDoubleDecryptError = .F.
		
		if (empty(pcEncryptedFileName) or empty(pcEncryptedFileName) or empty(pcPassword)) and this.ldisplayhighlevelapierrors
			if this.ldisplayhighlevelapierrors then
				messagebox(dcDecryptSessionFileParameter_ERR_LOC)
			endif
			return .F.
		endif
		
		lhEncryptedFileHandle = fopen(alltrim(pcEncryptedFileName))
		if lhEncryptedFileHandle = -1 and this.ldisplayhighlevelapierrors then
			if this.ldisplayhighlevelapierrors then
				messagebox(dcDecryptSessionFileNoFile_ERR_LOC,MB_ICONEXCLAMATION + MB_APPLMODAL + MB_OK)
			endif
			return .F.
		endif
		
		if file(alltrim(pcDecryptedFileName))
			if this.ldisplayhighlevelapierrors then
				lnYN =messagebox(dcDecryptSessionFileExists_ERR_LOC, MB_APPLMODAL + MB_YESNO + MB_ICONQUESTION, dcFileExists) 
				if lnYN = IDNo then
					fclose(lhEncryptedFileHandle)
					return .F.
				endif
			endif
		endif
		
		lhDecryptedFileHandle = fcreate(alltrim(pcDecryptedFileName))
		if lhDecryptedFileHandle = -1 then
			if this.ldisplayhighlevelapierrors then
				messagebox(dcDecryptSessionFileCreate_ERR_LOC,MB_ICONEXCLAMATION + MB_APPLMODAL + MB_OK)
			endif
			fclose(lhEncryptedFileHandle)
			return .F.
		endif
		
		lhKeyHandle = 0
		lhExchangeKeyHandle = 0
		this.GetCryptSessionKeyHandle(this.hProviderHandle,@lhKeyHandle, dcB,rtrim(pcPassword))
		if lhKeyHandle <> 0 then
			*** Get Block Length for this Encryption Key
			lnCryptBlockLen = this.GetCryptBlockLength(lhKeyHandle)
			lnBlockReadSize = 1024 - mod(1024,lnCryptBlockLen)
			*** See what encryption Length would be for an ecrypted block of this size
			lcTestLength = space(lnBlockReadSize)
			lnBlockReadSize = len(this.EncryptStrBlock(lcTestLength, lhKeyHandle, .F.))
			fseek(lhEncryptedFileHandle,0,0)
			do while !feof(lhEncryptedFileHandle)
				lcEncryptedText = fread(lhEncryptedFileHandle,lnBlockReadSize)
				lnBytesWritten = fwrite(lhDecryptedFileHandle,this.DecryptStr(lcEncryptedText, lhKeyHandle, feof(lhEncryptedFileHandle)))
				if this.GetLastApiError() <> 0   or lnBytesWritten = 0 then
					if this.GetLastApiError() = this.DoubleDecryptError()
						this.lDoubleDecryptError = .T.
					else
						if this.ldisplayhighlevelapierrors then
							messagebox(dcDecryptSessionFileWrite_ERR_LOC)
						endif
						this.ReleaseCryptKeyHandle(lhKeyHandle)
					endif
					fclose(lhDecryptedFileHandle)
					fclose(lhEncryptedFileHandle)
					return .F.
				endif
			enddo
			if this.ldisplayhighlevelapierrors then
				messagebox(dcDecryptSessionFileComplete_LOC, MB_OK, dcCompleted)
			endif
			this.ReleaseCryptKeyHandle(lhKeyHandle)
		endif
		
		fclose(lhDecryptedFileHandle)
		fclose(lhEncryptedFileHandle)
		
		return .T.
	ENDPROC

	PROCEDURE decryptsessionblockstring		&& Decrypt a Strnig using a Block Session Key
		LPARAMETERS pcEncryptedString, pcPassword, pcDecryptedString
		*** pcEncryptedString - String to Decrypt
		*** pcPassword - Password
		*** pcDecryptedString - Decrypted String
		
		*** Returns .T. - Ok 
		***         .F. - Error
		
		LOCAL lhKeyHandle, lhExchangeKeyHandle
		LOCAL lcSaveText, lcReturn, llOk
		
		lhKeyHandle = 0
		lhExchangeKeyHandle = 0
		llOk = .F.
		this.GetCryptSessionKeyHandle(this.hProviderHandle,@lhKeyHandle,dcB,rtrim(pcPassword))
		if lhKeyHandle <> 0 then
			if len(pcEncryptedString) > 0 then
				lcSaveText = this.DecryptStr(pcEncryptedString, lhKeyHandle, .T.)
				if this.GetLastApiError() = 0 then
					pcDecryptedString = lcSaveText
					llOk = .T.
				else
					if this.GetLastApiError() = this.DoubleDecryptError()
						this.lDoubleDecryptError = .T.
					endif
				endif
			endif
			this.ReleaseCryptKeyHandle(lhKeyHandle)
		endif
		
		return llOk
		
	ENDPROC

	PROCEDURE decryptsessionstreamfile		&& Decrypt a File with a session stream key
		LParameter pcEncryptedFileName,  pcPassword, pcDecryptedFileName
		*** pcEncryptedFileName - File Path and Name of file to Decrypt
		*** pcPassword - Password
		*** pcDecryptedFileName - File Path and Name of file to Place Decrypted Contents Into
		
		*** Returns .T. - Successful
		***         .F. - Error
		
		LOCAL lhKeyHandle, lhExportKeyHandle, lhEncryptedFileHandle, lhDecryptedFileHandle
		LOCAL lnYN, lnBytesWritten, lnKeyLength
		LOCAL lcEncryptedSessionKey, lcEncryptedText
		
		if empty(pcEncryptedFileName) or empty(pcEncryptedFileName) or empty(pcPassword)
			if this.ldisplayhighlevelapierrors then
				messagebox(dcDecryptSessionFileParameter_ERR_LOC)
			endif
			return .F.
		endif
		
		lhEncryptedFileHandle = fopen(alltrim(pcEncryptedFileName))
		if lhEncryptedFileHandle = -1 then
			if this.ldisplayhighlevelapierrors then
				messagebox(dcDecryptSessionFileNoFile_ERR_LOC,MB_ICONEXCLAMATION + MB_APPLMODAL + MB_OK)
			endif
			return .F.
		endif
		
		if file(alltrim(pcDecryptedFileName))
			if this.ldisplayhighlevelapierrors then
				lnYN =messagebox(dcDecryptSessionFileExists_ERR_LOC, MB_APPLMODAL + MB_YESNO + MB_ICONQUESTION, dcFileExists) 
				if lnYN = IDNo then
					fclose(lhEncryptedFileHandle)
					return .F.
				endif
			endif
		endif
		
		lhDecryptedFileHandle = fcreate(alltrim(pcDecryptedFileName))
		if lhDecryptedFileHandle = -1 then
			if this.ldisplayhighlevelapierrors then
				messagebox(dcDecryptSessionFileCreate_ERR_LOC,MB_ICONEXCLAMATION + MB_APPLMODAL + MB_OK)
			endif
			fclose(lhEncryptedFileHandle)
			return .F.
		endif
		
		lhKeyHandle = 0
		lhExchangeKeyHandle = 0
		this.GetCryptSessionKeyHandle(this.hProviderHandle,@lhKeyHandle, dcS,rtrim(pcPassword))
		if lhKeyHandle <> 0 then
			fseek(lhEncryptedFileHandle,0,0)
			do while !feof(lhEncryptedFileHandle)
				lcEncryptedText = fread(lhEncryptedFileHandle,1024)
				lnBytesWritten = fwrite(lhDecryptedFileHandle,this.DecryptStr(lcEncryptedText, lhKeyHandle, feof(lhEncryptedFileHandle)))
				if this.GetLastApiError() <> 0  or lnBytesWritten = 0 then
					if this.ldisplayhighlevelapierrors then
						messagebox(dcDecryptSessionFileWrite_ERR_LOC)
					endif
					this.ReleaseCryptKeyHandle(lhKeyHandle)
					fclose(lhDecryptedFileHandle)
					fclose(lhEncryptedFileHandle)
					return .F.
				endif
			enddo
			if this.ldisplayhighlevelapierrors then
				messagebox(dcDecryptSessionFileComplete_LOC, MB_OK, dcCompleted)
			endif
			this.ReleaseCryptKeyHandle(lhKeyHandle)
		endif
		
		fclose(lhDecryptedFileHandle)
		fclose(lhEncryptedFileHandle)
		
		return .T.
	ENDPROC

	PROCEDURE decryptsessionstreamstring		&& Decrypt a String using a Session Stream Key
		LPARAMETERS pcEncryptedString, pcPassword, pcDecryptedString
		*** pcEncryptedString - String to Decrypt
		*** pcPassword - Password
		
		*** Returns != '' - Decrypton of pcEncryptedString
		***         == '' - Error
		
		LOCAL lhKeyHandle, lhExchangeKeyHandle
		
		lhKeyHandle = 0
		lhExchangeKeyHandle = 0
		this.GetCryptSessionKeyHandle(this.hProviderHandle,@lhKeyHandle, dcS,rtrim(pcPassword))
		if lhKeyHandle <> 0 then
			if len(pcEncryptedString) > 0 then
				lcSaveText = this.DecryptStr(pcEncryptedString, lhKeyHandle, .T.)
				if this.GetLastApiError() = 0 then
					pcDecryptedString = lcSaveText
				else
					pcDecryptedString = dcEmpty
					this.ReleaseCryptKeyHandle(lhKeyHandle)
					return .F.
				endif
			else
				pcDecryptedString = dcEmpty
				this.ReleaseCryptKeyHandle(lhKeyHandle)
				return .F.
			endif
			this.ReleaseCryptKeyHandle(lhKeyHandle)
		endif
		
		
		return .T.
	ENDPROC

	HIDDEN PROCEDURE decryptstr		&& Simple call that returns a decrypted string.
		Lparameter picData, pihKeyHandle, pilLastString
		
		*** picData		 - Data to be Decrypted
		*** pihKeyHandle - Handle to Decryption Key (Type determine Block or Stream)
		*** pilLastString - .T. when this is the last string to decrypt
		*** Returns		 - Decrypted String
		
		*** Wrapper to decrypt a string
		
		Local lcDataLen
		
		lcDataLen = this.BinToStr(len(picData),4)
		Return this.CryptDecrypt( ;
			pihKeyHandle, ;
			0, ;
			iif(pilLastString,-1,0), ;
			0, ;
			picData, ;
			lcDataLen)
			
	ENDPROC

	PROCEDURE deletekeycontainer		&& Delete a Cryptography Service Provider Named Key Container
		LPARAMETER pcContainer
		*** pcContainer - Container Name of the Key Container to Delete
		
		*** Deletes a Key Container and
		*** Releases the Provider Handle when the Container to Delete is the one currently in use
		
		LOCAL lhProviderHandle
		
		lhProviderHandle = 0
		
		if this.cContainerName = pcContainer then
			this.CryptReleaseContext(this.hProviderHandle)
			this.hProviderHandle = 0
		endif
		
		lnError = this.CryptAcquireContext(@lhProviderHandle,pcContainerName,this.cProviderName,dnPROV_RSA_FULL,dnCRYPT_DELETEKEYSET)
		if lnError = 0
			if this.lDisplayLowLevelApiErrors
				messagebox(dcCRYPTDELETEKEYCONTAINER_ERR_LOC,MB_APPLMODAL+MB_ICONEXCLAMATION+MB_OK,dcError)
			endif
			this.nlastapierror = getlasterror()
			this.apierror(program())
			return .F.
		else
			this.nlastapierror = 0
		endif
		
		return .T.
		
	ENDPROC

	HIDDEN PROCEDURE doubledecrypterror
		*** Convert 0x80090005 to two's complement
		return  -1 * ( bitxor(0x80090005,0xffffffff) + 1 )
	ENDPROC

	HIDDEN PROCEDURE doubleencrypterror		&& Calculation of Error Number returned by getlasterror() for Double Encryption/Decryption of a Block String
		*** Convert 0x80090012 to two's complement
		return  -1 * ( bitxor(0x80090012,0xffffffff) + 1 )
	ENDPROC

	PROCEDURE encryptsessionblockfile		&& Encrypt a File using a Session Block Key
		
		LPARAMETER pcDecryptedFileName, pcPassword, pcEncryptedFileName
		*** pcDecryptedFileName - File Path and Name of file with Decrypted Contents
		*** pcPassword - Password
		*** pcEncryptedFileName - File Path and Name of file to Create with Encrypted Contents
		
		*** Returns .T. - Successful
		***         .F. - Error
		
		LOCAL lhKeyHandle, lhExportKeyHandle, lhEncryptedFileHandle, lhDecryptedFileHandle
		LOCAL lnYN, lnBytesWritten, lnCryptBlockLen, lnBlockReadSize
		LOCAL lcEncryptedSessionKey, lcDecryptedText
		
		if empty(pcDecryptedFileName) or empty(pcEncryptedFileName) or empty(pcPassword)
			if this.ldisplayhighlevelapierrors then
				messagebox(dcEncryptSessionFileParameter_ERR_LOC)
			endif
			return .F.
		endif
		lhDecryptedFileHandle = fopen(alltrim(pcDecryptedFileName))
		if lhDecryptedFileHandle = -1 then
			if this.ldisplayhighlevelapierrors then
				messagebox(dcEncryptSessionFileNoFile_ERR_LOC,MB_ICONEXCLAMATION + MB_APPLMODAL + MB_OK)
			endif
			return .F.
		endif
		if file(alltrim(pcEncryptedFileName))
			if this.ldisplayhighlevelapierrors then
				lnYN =messagebox(dcEncryptSessionFileExists_ERR_LOC, MB_APPLMODAL + MB_YESNO + MB_ICONQUESTION, dcFileExists) 
				if lnYN = IDNo then
					fclose(lhDecryptedFileHandle)
					return .F.
				endif
			endif
		endif
		lhEncryptedFileHandle = fcreate(alltrim(pcEncryptedFileName))
		if lhEncryptedFileHandle = -1 then
			if this.ldisplayhighlevelapierrors then
				messagebox(dcEncryptSessionFileCreate_ERR_LOC,MB_ICONEXCLAMATION + MB_APPLMODAL + MB_OK)
			endif
			fclose(lhDecryptedFileHandle)
			return .F.
		endif
		
		lhKeyHandle = 0
		lhExchangeKeyHandle = 0
		lcEncryptedSessionKey = dcEmpty
		this.GetCryptSessionKeyHandle(this.hProviderHandle,@lhKeyHandle,dcB,rtrim(pcPassword))
		if lhKeyHandle <> 0 then
			*** Get Block Length for this Encryption Key
			lnCryptBlockLen = this.GetCryptBlockLength(lhKeyHandle)
			lnBlockReadSize = 1024 - mod(1024,lnCryptBlockLen)
			fseek(lhDecryptedFileHandle,0,0)
			do while !feof(lhDecryptedFileHandle)
				lcDecryptedText = fread(lhDecryptedFileHandle,lnBlockReadSize)
				lnBytesWritten = fwrite(lhEncryptedFileHandle,this.EncryptStrBlock(lcDecryptedText, lhKeyHandle, feof(lhDecryptedFileHandle)))
				if this.GetLastApiError() <> 0  or lnBytesWritten = 0 then
					if this.ldisplayhighlevelapierrors then
						messagebox(dcEncryptSessionFileWrite_ERR_LOC)
					endif
					this.ReleaseCryptKeyHandle(lhKeyHandle)
					fclose(lhDecryptedFileHandle)
					fclose(lhEncryptedFileHandle)
					return .F.
				endif
			enddo
			if this.ldisplayhighlevelapierrors then
				messagebox(dcEncryptSessionFileComplete_LOC, MB_OK, dcCompleted)
			endif
			this.ReleaseCryptKeyHandle(lhKeyHandle)
		endif
		
		fclose(lhDecryptedFileHandle)
		fclose(lhEncryptedFileHandle)
		
		return .T.
		
	ENDPROC

	PROCEDURE encryptsessionblockstring		&& Encrypt a Strnig Using a Session Block Key
		LPARAMETERS pcDecryptedString, pcPassword, pcEncryptedString
		*** pcDecryptedString - String to Encrypt
		*** pcEncryptedString - Reference to String to Hold Encrypted Value
		*** pcPassword - Password
		
		*** Returns != '' - Encryption of pcDecryptedString
		***         == '' - Error
		
		LOCAL lhKeyHandle, lhExchangeKeyHandle
		LOCAL llOk, lcSaveString
		
		lhKeyHandle = 0
		lhExchangeKeyHandle = 0
		llOk = .F.
		this.lDoubleEncryptError = .F.
		this.GetCryptSessionKeyHandle(this.hProviderHandle,@lhKeyHandle,dcB,rtrim(pcPassword))
		if lhKeyHandle <> 0 then
			if len(pcDecryptedString) > 0 then
				lcSaveString = this.EncryptStrBlock(pcDecryptedString, lhKeyHandle, .T.)
				if this.GetLastApiError() = 0 then
					pcEncryptedString = lcSaveString
					llOk = .T.
				else
					if this.GetLastApiError() = this.DoubleEncryptError()
						this.lDoubleEncryptError = .T.
					endif
				endif
			endif
			this.ReleaseCryptKeyHandle(lhKeyHandle)
		endif
		
		return llOk
		
	ENDPROC

	PROCEDURE encryptsessionstreamfile		&& Encrypt a File using a Session Stream Key
		LPARAMETER pcDecryptedFileName, pcPassword, pcEncryptedFileName
		*** pcDecryptedFileName - File Path and Name of file with Decrypted Contents
		*** pcPassword - Password
		*** pcEncryptedFileName - File Path and Name of file to Create with Encrypted Contents
		
		*** Returns .T. - Successful
		***         .F. - Error
		
		LOCAL lhKeyHandle, lhExportKeyHandle, lhEncryptedFileHandle, lhDecryptedFileHandle
		LOCAL lnYN, lnBytesWritten
		LOCAL lcEncryptedSessionKey, lcDecryptedText
		
		if empty(pcDecryptedFileName) or empty(pcEncryptedFileName) or empty(pcPassword)
			if this.ldisplayhighlevelapierrors then
				messagebox(dcEncryptSessionFileParameter_ERR_LOC)
			endif
			return .F.
		endif
		lhDecryptedFileHandle = fopen(alltrim(pcDecryptedFileName))
		if lhDecryptedFileHandle = -1 then
			if this.ldisplayhighlevelapierrors then
				messagebox(dcEncryptSessionFileNoFile_ERR_LOC,MB_ICONEXCLAMATION + MB_APPLMODAL + MB_OK)
			endif
			return .F.
		endif
		if file(alltrim(pcEncryptedFileName))
			if this.ldisplayhighlevelapierrors then
				lnYN =messagebox(dcEncryptSessionFileExists_ERR_LOC, MB_APPLMODAL + MB_YESNO + MB_ICONQUESTION, dcFileExists) 
				if lnYN = IDNo then
					fclose(lhDecryptedFileHandle)
					return .F.
				endif
			endif
		endif
		lhEncryptedFileHandle = fcreate(alltrim(pcEncryptedFileName))
		if lhEncryptedFileHandle = -1 then
			if this.ldisplayhighlevelapierrors then
				messagebox(dcEncryptSessionFileCreate_ERR_LOC,MB_ICONEXCLAMATION + MB_APPLMODAL + MB_OK)
			endif
			fclose(lhDecryptedFileHandle)
			return .F.
		endif
		
		lhKeyHandle = 0
		lhExchangeKeyHandle = 0
		lcEncryptedSessionKey = dcEmpty
		this.GetCryptSessionKeyHandle(this.hProviderHandle,@lhKeyHandle, dcS,rtrim(pcPassword))
		if lhKeyHandle <> 0 then
			fseek(lhDecryptedFileHandle,0,0)
			do while !feof(lhDecryptedFileHandle)
				lcDecryptedText = fread(lhDecryptedFileHandle,1024)
				lnBytesWritten = fwrite(lhEncryptedFileHandle,this.EncryptStrStream(lcDecryptedText, lhKeyHandle, feof(lhDecryptedFileHandle)))
				if this.GetLastApiError() <> 0  or lnBytesWritten = 0 then
					if this.ldisplayhighlevelapierrors then
						messagebox(dcEncryptSessionFileWrite_ERR_LOC)
					endif
					this.ReleaseCryptKeyHandle(lhKeyHandle)
					fclose(lhDecryptedFileHandle)
					fclose(lhEncryptedFileHandle)
					return .F.
				endif
			enddo
			if this.ldisplayhighlevelapierrors then
				messagebox(dcEncryptSessionFileComplete_LOC, MB_OK, dcCompleted)
			endif
			this.ReleaseCryptKeyHandle(lhKeyHandle)
		endif
		
		fclose(lhDecryptedFileHandle)
		fclose(lhEncryptedFileHandle)
		
		return .T.
	ENDPROC

	PROCEDURE encryptsessionstreamstring		&& Encrypt a Strnig using a SessionStream Key
		LPARAMETERS pcDecryptedString, pcPassword, pcEncryptedString
		*** pcDecryptedString - String to Encrypt
		*** pcPassword - Password
		*** pcEncryptedString - Refrence to a String to hold the Encrypted String Value
		
		*** Returns != '' - Encryption of pcDecryptedString
		***         == '' - Error
		
		LOCAL lhKeyHandle, lhExportKeyHandle
		LOCAL lcEncryptedSessionKey, llOk, lcSaveString
		
		
		lhKeyHandle = 0
		lhExchangeKeyHandle = 0
		lcEncryptedSessionKey = dcEmpty
		llOk = .F.
		this.GetCryptSessionKeyHandle(this.hProviderHandle,@lhKeyHandle,dcS,rtrim(pcPassword))
		if lhKeyHandle <> 0 then
			if len(pcDecryptedString) > 0 then
				lcSaveString = this.EncryptStrStream(pcDecryptedString, lhKeyHandle, .T.)
				if this.GetLastApiError() = 0 then
					pcEncryptedString = lcSaveString
					llOk = .T.
				endif
			endif
			this.ReleaseCryptKeyHandle(lhKeyHandle)
		endif
		
		return llOk
	ENDPROC

	HIDDEN PROCEDURE encryptstrblock
		Lparameter picData, pihKeyHandle, pilLastString
		
		*** picData		  - Data to be Encrypted
		*** pihKeyHandle  - Handle to Encryption Key (Type determines Block or Stream)
		*** pilLastString - Last String to Encrypt with this Key
		*** Returns		  - Encrypted String
		
		*** Wrapper to encrypt a string
		Local lnDataLen, lnMaxLen
		LOCAL lcDataLen, lcEmptySpace
		
		lnDataLen = len(picData)
		lcDataLen = this.BinToStr(lnDataLen,4)
		*** The following is needed, Just in case a stream key is passed
		*** When called with a Stream pihKeyHandle, this routine encrypts the
		*** EmptySpace string even though maxlen = 0
		*** Leaving this out would corrupt memory and result in a GPF
		lcEmptySpace = space(lnDataLen)
		CryptEncrypt( ;
			pihKeyHandle, ;
			0, ;
			-1, ;
			0, ;
			@lcEmptySpace, ;
			@lcDataLen, ;
			0)
		*** Do not check lnError since more data is available error will result from this call
		*** on a block, when the data length is shorter (Not a multiple of the block length)
		lnMaxLen = this.strtobin(lcDataLen)
		* ReSet lcDataLen, since last cryptencrypt call changed it
		lcDataLen = this.BinToStr(lnDataLen,4)
		picData = picData + space(lnMaxLen - lnDataLen)
		Return this.CryptEncrypt( ;
			pihKeyHandle, ;
			0, ;
			iif(pilLastString,-1,0), ;
			0, ;
			picData, ;
			lcDataLen, ;
			lnMaxLen)
			
		
	ENDPROC

	HIDDEN PROCEDURE encryptstrstream
		Lparameter picData, pihKeyHandle, pilLastString
		
		*** picData		  - Data to be Encrypted
		*** pihKeyHandle  - Handle to Encryption Key (Type determines Block or Stream)
		*** pilLastString - Last String to Encrypt with this Key
		*** Returns		  - Encrypted String
		
		*** Wrapper to encrypt a string
		Local lnDataLen
		LOCAL lcDataLen
		
		lnDataLen = len(picData)
		lcDataLen = this.BinToStr(lnDataLen,4)
		Return this.CryptEncrypt( ;
			pihKeyHandle, ;
			0, ;
			iif(pilLastString,-1,0), ;
			0, ;
			@picData, ;
			@lcDataLen, ;
			lnDataLen)
			
		
	ENDPROC

	HIDDEN PROCEDURE exportexchangepairkeys		&& Export the Exchange Key Pair
		LPARAMETER pcPassword, pcPairKey
		*** pcPassword - Password for Encryption of Exported Key
		*** pcPairKey - Reference String to pass Encrypted Key back to caller
		
		*** Return .T. - Success
		***        .F. - Failure
		
		LOCAL lcPairKey, lhHash, lhEncryptKey, lhExchangeKey, lhExchangeKey
		
		lhHash = 0
		lhExchangeKey = 0
		lhexchangeKey = 0
		lhEncryptKey = 0
		lcPairKey = dcEmpty
		
		if !this.cryptcreatehash(this.hProviderHandle, dnCALG_MD5, 0, 0, @lhHash)
			return .F.
		endif
		
		if !this.crypthashdata(lhHash, pcPassword, len(pcPassword), 0)
			return .F.
		endif
		
		if !this.cryptderivekey(this.hProviderHandle, dnCALG_RC2, lhHash, dnCRYPT_EXPORTABLE, @lhEncryptKey)
			return .F.
		endif
		
		if !this.cryptgetuserkey(this.hProviderHandle, dnAT_KEYEXCHANGE, @lhExchangeKey)
			return .F.
		endif
		
		if !this.cryptgetuserkey(this.hProviderHandle, dnAT_KEYEXCHANGE, @lhExchangeKey)
			return .F.
		endif
		
		if !this.cryptexportkey(lhExchangeKey ,lhEncryptKey, dnPRIVATEKEYBLOB, 0, @lcPairKey)
			return .F.
		endif
		
		pcPairKey = lcPairKey
		
		return .T.
		
	ENDPROC

	PROCEDURE exportexchangepublickey		&& Export an Exchange Key from a named key container
		LPARAMETER pcPublicKey
		
		LOCAL lcPublicKey, lhExchangeKey
		
		lhExchangeKey = 0
		lcPublicKey = dcEmpty
		
		if !this.cryptgetuserkey(this.hProviderHandle,dnAT_KEYEXCHANGE,@lhExchangeKey)
			return .F.
		endif
		
		if !this.cryptexportkey(lhExchangeKey,0,dnPUBLICKEYBLOB,0,@lcPublicKey)
			return .F.
		endif
		
		pcPublicKey = lcPublicKey
		
		return .T.
		
	ENDPROC

	PROCEDURE exportsessionkey		&& Export a Session Key Encrypted with an Exchange Key
		LPARAMETER pcPassword, pcSessionKey
		*** pcPassword - Password for Encryption of Exported Key
		*** pcSessionKey - Reference String to pass Encrypted Key back to caller
		
		*** Return .T. - Success
		***        .F. - Failure
		
		*** Exports a session key encrypted with the Exchange Private Key of the Current Key Container
		
		LOCAL lcPairKey, lhHash, lhEncryptKey, lhExchangeKey
		
		lhHash = 0
		lhExchangeKey = 0
		lhEncryptKey = 0
		lcPairKey = dcEmpty
		
		if !this.cryptcreatehash(this.hProviderHandle, dnCALG_MD5, 0, 0, @lhHash)
			return .F.
		endif
		
		if !this.crypthashdata(lhHash, pcPassword, len(pcPassword), 0)
			return .F.
		endif
		
		if !this.cryptderivekey(this.hProviderHandle, dnCALG_RC2, lhHash, dnCRYPT_EXPORTABLE, @lhEncryptKey)
			return .F.
		endif
		
		if !this.cryptgetuserkey(this.hProviderHandle, dnAT_KEYEXCHANGE, @lhExchangeKey)
			return .F.
		endif
		
		if !this.cryptexportkey(lhEncryptKey ,lhExchangeKey, dnSIMPLEBLOB, 0, @lcPairKey)
			return .F.
		endif
		
		pcSessionKey = lcPairKey
		
		return .T.
		
	ENDPROC

	HIDDEN PROCEDURE exportsignaturepairkeys		&& Export the Signature Key Pair
		LPARAMETER pcPassword, pcPairKey
		*** pcPassword - Password for Encryption of Exported Key
		*** pcPairKey - Reference String to pass Encrypted Key back to caller
		
		*** Return .T. - Success
		***        .F. - Failure
		
		LOCAL lcPairKey, lhHash, lhEncryptKey, lhExchangeKey, lhSignatureKey
		
		lhHash = 0
		lhExchangeKey = 0
		lhSignatureKey = 0
		lhEncryptKey = 0
		lcPairKey = dcEmpty
		
		if !this.cryptcreatehash(this.hProviderHandle, dnCALG_MD5, 0, 0, @lhHash)
			return .F.
		endif
		
		if !this.crypthashdata(lhHash, pcPassword, len(pcPassword), 0)
			return .F.
		endif
		
		if !this.cryptderivekey(this.hProviderHandle, dnCALG_RC2, lhHash, dnCRYPT_EXPORTABLE, @lhEncryptKey)
			return .F.
		endif
		
		if !this.cryptgetuserkey(this.hProviderHandle, dnAT_KEYEXCHANGE, @lhExchangeKey)
			return .F.
		endif
		
		if !this.cryptgetuserkey(this.hProviderHandle, dnAT_SIGNATURE, @lhSignatureKey)
			return .F.
		endif
		
		if !this.cryptexportkey(lhSignatureKey ,lhEncryptKey, dnPRIVATEKEYBLOB, 0, @lcPairKey)
			return .F.
		endif
		
		pcPairKey = lcPairKey
		
		return .T.
		
	ENDPROC

	PROCEDURE exportsignaturepublickey		&& Export a Signature Key from a named Container
		LPARAMETER pcPublicKey
		
		LOCAL lcPublicKey, lhSignatureKey
		
		lhSignatureKey = 0
		lcPublicKey = dcEmpty
		
		if !this.cryptgetuserkey(this.hProviderHandle,dnAT_SIGNATURE,@lhSignatureKey)
			return .F.
		endif
		
		if !this.cryptexportkey(lhSignatureKey,0,dnPUBLICKEYBLOB,0,@lcPublicKey)
			return .F.
		endif
		
		pcPublicKey = lcPublicKey
		
		return .T.
		
	ENDPROC

	HIDDEN PROCEDURE formatmessage		&& Formats a system error message into a string for display.
		Lparameter pinFlags, pinMessageNum
		
		*** pinFlags - Windows API defined flags for Format Message
		*** pinMessageNum - Windows API Message Number
		*** Returns - Formated Message String Associated
		***           with the Message Number that was input
		
		***
		*** Windows API call to FormatMessage
		*** Returns the Windows String Text Assocaited with 
		*** the Windows Message Number that a Windows API
		*** returns, formated based on the flags that were passed to it.
		*** currently does not support C like printf() ability
		***
		
		Local lcMessage, lcNull
		
		lcMessage = space(256)
		lcNull = dcEmpty
		lnMessageLen = FormatMessage( ;
			pinFlags, ;
			@lcNull, ;
			pinMessageNum, ;
			0, ;
			@lcMessage, ;
			256, ;
			@lcNull)
		Return left(lcMessage,lnMessageLen)
		
	ENDPROC

	HIDDEN PROCEDURE getcryptblocklength		&& Returns the Block length of a block key. This is need to calculate even block boundries during a block encryption of a large amount of text. To break it down into smaller chunks.
		LPARAMETER pihKeyHandle
		
		*** pihKeyHandle	 - Handle of Key Objcet,
		***					   Returned by CryptGenKey() or CryptImportKey()
		*** Return		 	 - Length of an encryption block for the current key
		
		*** Used to return a Parameter from a Crypt Key
		
		Local lnParamLen, lnReturn
		Local lcParam, lcParamLen
		
		lnReturn = 0
		lnParamLen = 4
		lcParam = space(lnParamLen)
		lcParamLen = this.BinToStr(lnParamLen,4)
		lcParam = this.CryptGetKeyParam( ;
			pihKeyHandle, ;
			dnKP_BLOCKLEN, ;
			lcParam, ;
			lcParamLen, ;
			0)
		
		return this.StrToBin(lcParam)
		
	ENDPROC

	HIDDEN PROCEDURE getcryptsessionkeyhandle		&& Simple call for returning a session key handle.
		LPARAMETER pihProviderHandle,pihCryptKeyHandle, picType, picPassword
		
		***
		*** pihProviderHandle - Handle of the CSP
		*** pihCryptKeyHandle - Handle to a cryptographic session key
		*** picPassword - Password to use as Encryption Key
		*** picType     - 'B' Use Block Cypher (Harder to Crack, but takes longer and results
		***                                in longer encrypted string than decryphered
		***                                by as much as one block length)
		***             - 'S' Use Stream Cyper (Easier to Crack, but runs faster and results
		***                                in same length encrypted string as decyphered string)
		***             - 'BR' Random, Use Block Cypher (Harder to Crack, but takes longer and results
		***                                in longer encrypted string than decryphered
		***                                by as much as one block length)
		***             - 'SR' Random, Use Stream Cyper (Easier to Crack, but runs faster and results
		***                                in same length encrypted string as decyphered string)
		*** Returns     - Handle to Session Crypt Key (Numberic) 
		***
		*** Uses Microsoft Windows Base Cryptographic Provider
		*** to Return a Handle to a cryptographic key that can be used to Encrypt/Decrypt Data
		***
		
		Local lhCryptHashHandle, lnSaveError
		
		If !(picType $ dcgetcryptsessionkeyhandleparam ) and this.ldisplayhighlevelapierrors
			if this.ldisplayhighlevelapierrors then
				Messagebox(program()+ ;
					dcgetcryptsessionkeyhandleERR_LOC)
			endif
			Return 0
		Endif
		
		lhCryptHashHandle = 0
		lnSaveError = 0
		Do case
			Case picType == dcB
				this.CryptCreateHash(pihProviderHandle,dnCALG_MD5,0,0,@lhCryptHashHandle)
			    if this.nlastapierror <> 0 then
				    lnSaveError = this.nlastapierror
				endif
				this.CryptHashData(lhCryptHashHandle, picPassword , len(picPassword),0)
			    if this.nlastapierror <> 0 then
				    lnSaveError = this.nlastapierror
				endif
				this.CryptDeriveKey(;
					pihProviderHandle, ;
					dnCALG_RC2, ;
					lhCryptHashHandle, ;
					dnCRYPT_EXPORTABLE, ;
					@pihCryptKeyHandle)
			    if this.nlastapierror <> 0 then
				    lnSaveError = this.nlastapierror
				endif
				this.CryptDestroyHash(lhCryptHashHandle)
			    if this.nlastapierror = 0 then
				    this.nlastapierror = lnSaveError
				endif
			Case picType == dcS
				this.CryptCreateHash(pihProviderHandle,dnCALG_MD5,0,0,@lhCryptHashHandle)
			    if this.nlastapierror <> 0 then
				    lnSaveError = this.nlastapierror
				endif
				This.CryptHashData(lhCryptHashHandle, picPassword, len(picPassword), 0)
			    if this.nlastapierror <> 0 then
				    lnSaveError = this.nlastapierror
				endif
				this.CryptDeriveKey(;
					pihProviderHandle, ;
					dnCALG_RC4, ;
					lhCryptHashHandle, ;
					dnCRYPT_EXPORTABLE, ;
					@pihCryptKeyHandle)
			    if this.nlastapierror <> 0 then
				    lnSaveError = this.nlastapierror
				endif
				this.CryptDestroyHash(lhCryptHashHandle)
			    if this.nlastapierror = 0 then
				    this.nlastapierror = lnSaveError
				endif
			Case picType == dcBR
				this.CryptGenKey( ;
					pihProviderHandle, ;
					dnCALG_RC2, ;
					dnCRYPT_EXPORTABLE, ;
				    @pihCryptKeyHandle)
			Case picType == dcSR
				this.CryptGenKey(;
					pihProviderHandle, ;
					dnCALG_RC4, ;
					dnCRYPT_EXPORTABLE, ;
				    @pihCryptKeyHandle)
		Endcase
		
		Return 
		
	ENDPROC

	HIDDEN PROCEDURE getcryptuserkeyhandle		&& Simple call for returning a user key. (Public Key part of a private.public key pair)
		LPARAMETER pihProviderHandle, pihUserKey, pinKeySpec
		
		*** pihProvHandle - Handle of CSP
		*** pinKeySpec - Type of a User Key to Generate
		
		*** Returns Handle to the User Key of Specified Type
		
		this.CryptGetUserKey( ;
		    pihProviderHandle, ;
		    pinKeySpec, ;
		 	@pihUserKey ;
			)
			
		Return
	ENDPROC

	PROCEDURE getdoubledecrypterror		&& Return Logical Error Value of Last Rnu of Block Decryption
		return this.lDoubleDecryptError
	ENDPROC

	PROCEDURE getdoubleencrypterror		&& Return Logical Error Value of Last Rnu of Block Encryption
		return this.lDoubleEncryptError
	ENDPROC

	PROCEDURE getisinstalled		&& Return the Flag value for the init check of the Crypto Service Provider Installation
		return this.lIsInstalled
	ENDPROC

	PROCEDURE getlastapierror		&& Returns the last error message trapped by this api. Each low level API call traps the error number returned in this parameter. This is needed for an error check from a form. By the time a form looks for the error number, another one may have occured.
		*** Returns the last error from the last crypto API call
		return this.nlastapierror
	ENDPROC

	HIDDEN PROCEDURE getlastapierrorcode		&& Returns the code from an error number (BITS 1-16)
		*** Returns the code of the last error from the last crypto API call
		
		return bitand(this.nlastapierror,0xFFFF)
	ENDPROC

	HIDDEN PROCEDURE getlastapierrorcustomercodeflag		&& Returns the Customer flag from a system error number (Bit 29)
		*** Returns the severity code of the last error from the last crypto API call
		***         00 - Windows Code
		***         01 - Customer Code
		
		return bitand(bitrshift(this.nlastapierror,29),1)
	ENDPROC

	HIDDEN PROCEDURE getlastapierrorfacility		&& Returns the facitily code of an error number. (Bits 17-28)
		*** Returns the facility code of the last error from the last crypto API call
		
		*** FACILITY_NULL                    0
		*** FACILITY_RPC                     1
		*** FACILITY_DISPATCH                2
		*** FACILITY_STORAGE                 3
		*** FACILITY_ITF                     4
		*** FACILITY_WIN32                   7
		*** FACILITY_WINDOWS                 8
		*** FACILITY_SSPI                    9
		*** FACILITY_CONTROL                 10
		*** FACILITY_CERT                    11
		*** FACILITY_INTERNET                12
		*** FACILITY_MEDIASERVER             13
		*** FACILITY_MSMQ                    14
		*** FACILITY_SETUPAPI                15
		
		return bitand(bitrshift(this.nlastapierror,16),0xFFF)
	ENDPROC

	HIDDEN PROCEDURE getlastapierrorseverity		&& Return the severity code of an error number (BITS 31-32)
		*** Returns the severity code of the last error from the last crypto API call
		***          00 - Success
		***         01 - Informational
		***         10 - Warning
		***         11 - Error
		
		return bitrshift(this.nlastapierror,30)
	ENDPROC

	PROCEDURE getlasterror		&& Return the last system error number.
		*** Call to the Windows API
		RETURN getlasterror()
		
	ENDPROC

	PROCEDURE importpublickey		&& Import a Public Key into a Key Handle Structure
		LPARAMETERS pcPublicKey, phPublicKeyHandle
		
		*** pcPublicKey - Public Key to Import
		*** phPublicKeyHandle - Reference to a Handle, in which the Public Key is Returned
		
		*** Returns - Public Key Handle in phPublicKeyHandle
		***			.T. - Success
		***			.F. - Failure
		
		LOCAL lhPublicKeyHandle, lnError
		
		lhPublicKeyHandle = 0
		
		if !this.CryptImportKey(this.hProviderHandle, pcPublicKey, len(pcPublicKey), 0, 0, @lhPublicKeyHandle)
			Return .F.
		endif
		
		phPublicKeyHandle = lhPublicKeyHandle
		
		Return .T.
	ENDPROC

	PROCEDURE Init
		* this.ldisplaylowlevelapierrors = .T.
		this.ApiDeclarations	&& Declare API Functions
		this.ApiSetup	&& Create CSP Handle for use with this class
	ENDPROC

	HIDDEN PROCEDURE releasecryptkeyhandle		&& Release handle and free memory allocated to it.
		LPARAMETER pihKeyHandle
		
		*** pihKeyHandle - Handle to the Key structure to destroy
		*** Returns      - .T. (Logical)
		
		*** Releases the memory where the key structure was stored.
		*** Most Cryptographic Service Providers Scramble the Structure Contents
		*** as well as freeing it up. This is done so that another program can't query
		*** looking for keys that are left laying around.
		
		this.cryptdestroykey(pihKeyHandle)
		
	ENDPROC

	PROCEDURE signfile		&& Create a Signature for a File.
		LPARAMETERS pcDecryptedFileName, pcSignature, pcSignaturePublicKey
		*** pcDecryptedFileName - File name to Create an Encrypted Signature for
		*** pcSignature - Reference to a Signature String
		*** pcSignaturePublicKey - Reference to a Signature Public Key String
		
		*** Return Signature in pcSignature
		***        Signature PublicKey in pcSignaturePublicKey
		*** .T. - Success
		*** .F. - Failure
		
		*** Create a Signature for the given file.
		
		Local lhHashHandle, lnError, lnYN, lhSignFileHandle, lhDecryptedFileHandle, lnBytesWritten, lhKey
		Local lcInput, lcSignature, lcDecrytedText
		
		if empty(pcDecryptedFileName)
			if this.ldisplayhighlevelapierrors then
				messagebox(dcSignFileParamter_ERR_LOC)
			endif
			return .F.
		endif
		lhDecryptedFileHandle = fopen(alltrim(pcDecryptedFileName))
		if lhDecryptedFileHandle = -1 then
			if this.ldisplayhighlevelapierrors then
				messagebox(dcSignFileDecryptedFile_ERR_LOC,MB_ICONEXCLAMATION + MB_APPLMODAL + MB_OK)
			endif
			return .F.
		endif
		lhHashHandle = 0
		this.CryptCreateHash(this.hProviderHandle,dnCALG_MD5,0,0,@lhHashHandle)
		if this.GetLastApiError() <> 0 then
			if this.ldisplayhighlevelapierrors then
				messagebox (dcSignFileHashObject_ERR_LOC)
			endif
			fclose(lhDecryptedFileHandle)
			return .F.
		endif
		do while !feof(lhDecryptedFileHandle)
			lcDecryptedText = fread(lhDecryptedFileHandle,1024)
			this.CryptHashData(lhHashHandle, lcDecryptedText, len(lcDecryptedText), 0)
			if this.GetLastApiError() <> 0 then
				if this.ldisplayhighlevelapierrors then
					messagebox (dcSignFileHashing_ERR_LOC)
				endif
				this.CryptDestroyHash(lhHashHandle)
				fclose(lhDecryptedFileHandle)
				return .F.
			endif
		enddo
		lcSignature = this.CryptSignHash(lhHashHandle, dnAT_SIGNATURE, 0)
		if this.GetLastApiError() <> 0
			if this.ldisplayhighlevelapierrors then
				messagebox (ErrorSigningData)
			endif
			this.CryptDestroyHash(lhHashHandle)
			fclose(lhDecryptedFileHandle)
			return .F.
		endif
		pcSignature = lcSignature
		
		this.CryptDestroyHash(lhHashHandle)
		
		this.ExportSignaturePublicKey(@pcSignaturePublicKey)
		
		fclose(lhDecryptedFileHandle)
		
		return .T.
		
	ENDPROC

	HIDDEN PROCEDURE strtobin		&& Convert a byte stream  with the  least significate byte first and the most significan last into a Number.
		LPARAMETER picInput
		
		*** picInput - Integer encoded into a character string
		***            Left most Character is least significant
		***            Right most character is most significant
		*** return   - Integer represented by character string
		
		*** Converts Integer encoded Character String into an Integer
		
		LOCAL lnreturn, lnCounter
		
		lnReturn = 0
		for lnCounter = 1 to len(picInput)
		   lnReturn = lnReturn + bitlshift(asc(substr(picInput,lnCounter,1)),bitlshift((lnCounter-1),3))
		endfor
		
		return lnReturn
	ENDPROC

	HIDDEN PROCEDURE systemmessage		&& Look an Error Number up in the system table and return the string message text.
		LPARAMETER pinError
		
		*** pinError - Windows API Error Number
		*** returns  - Formated Windows API Error Message String
		
		*** Sets flags and calls for Windows API Format Message which
		***      Returns the Windows Error Message associated
		***      with the Windows Error Number Input
		***
		
		return this.FormatMessage(BITOR(dnFORMAT_MESSAGE_FROM_SYSTEM, ; 
		                                dnFORMAT_MESSAGE_IGNORE_INSERTS) , ;
		                                pinError)
		
	ENDPROC

	PROCEDURE usekeycontanier		&& Make a Named or Default key container the one currently in use
		LParameter pcContainerName
		
		*** Change Key Container Currently in Use
		
		LOCAL lhProviderHandle
		
		this.cContainerName = pcContainerName
		
		this.CryptReleaseContext(this.hProviderHandle)
		
		lnError = this.CryptAcquireContext(@lhProviderHandle,pcContainerName,this.cProviderName,dnPROV_RSA_FULL,0)
		If lnError = 0
			this.hProviderHandle = 0
			if this.lDisplayLowLevelApiErrors
				messagebox(dcCRYPTUSEKEYCONTAINER_ERR_LOC,MB_APPLMODAL+MB_ICONEXCLAMATION+MB_OK,dcError)
			endif
			this.nlastapierror = getlasterror()
			this.apierror(program())
			return .F.
		else
			this.nlastapierror = 0
			this.hProviderHandle = lhProviderHandle
		endif
		
		return .T.
		
	ENDPROC

	PROCEDURE verifyfilesignature		&& Verify File Signature
		LPARAMETERS pcDecryptedFileName, pcSignature, pcSignaturePublicKey, plVerified
		*** pcDecryptedFileName - File name to Create an Encrypted Signature for
		*** pcSignature - Signature String
		*** pcSignaturePublicKey - Public Key String
		*** plVerified - Reference to Verification Logical
		
		*** Return Signature in pcSignature
		***        Signature PublicKey in pcSignaturePublicKey
		*** .T. - Success
		*** .F. - Failure
		
		*** Logical Variable to Return Verification Information
		
		Local lhHashHandle, lnError, lnYN, lhSignFileHandle, lhDecryptedFileHandle, lnBytesWritten, lhPublicKey
		Local lcInput, lcSignature, lcDecrytedText
		
		if empty(pcDecryptedFileName)
			if this.ldisplayhighlevelapierrors then
				messagebox(dcSignFileParamter_ERR_LOC)
			endif
			return .F.
		endif
		lhDecryptedFileHandle = fopen(alltrim(pcDecryptedFileName))
		if lhDecryptedFileHandle = -1 then
			if this.ldisplayhighlevelapierrors then
				messagebox(dcSignFileDecryptedFile_ERR_LOC,MB_ICONEXCLAMATION + MB_APPLMODAL + MB_OK)
			endif
			return .F.
		endif
		lhHashHandle = 0
		this.CryptCreateHash(this.hProviderHandle,dnCALG_MD5,0,0,@lhHashHandle)
		if this.GetLastApiError() <> 0 then
			if this.ldisplayhighlevelapierrors then
				messagebox (dcSignFileHashObject_ERR_LOC)
			endif
			fclose(lhDecryptedFileHandle)
			return .F.
		endif
		do while !feof(lhDecryptedFileHandle)
			lcDecryptedText = fread(lhDecryptedFileHandle,1024)
			this.CryptHashData(lhHashHandle, lcDecryptedText, len(lcDecryptedText), 0)
			if this.GetLastApiError() <> 0 then
				if this.ldisplayhighlevelapierrors then
					messagebox (dcSignFileHashing_ERR_LOC)
				endif
				this.CryptDestroyHash(lhHashHandle)
				fclose(lhDecryptedFileHandle)
				return .F.
			endif
		enddo
		
		lhPublicKey = 0
		this.ImportPublicKey(pcSignaturePublicKey, @lhPublicKey)
		
		if this.CryptVerifySignature(lhHashHandle, pcSignature, lhPublicKey, 0)
			this.CryptDestroyHash(lhHashHandle)
			fclose(lhDecryptedFileHandle)
			plVerified = .T.
		else
			this.CryptDestroyHash(lhHashHandle)
			fclose(lhDecryptedFileHandle)
			return .F.
		endif
		
		return .T.
		
	ENDPROC

ENDDEFINE
