VERSION 1.0 CLASS BEGIN MultiUse = -1 'True Persistable = 0 'NotPersistable DataBindingBehavior = 0 'vbNone DataSourceBehavior = 0 'vbNone MTSTransactionMode = 0 'NotAnMTSObject END Attribute VB_Name = "cCrypt" Attribute VB_GlobalNameSpace = False Attribute VB_Creatable = True Attribute VB_PredeclaredId = False Attribute VB_Exposed = False Option Explicit '============================================================================================================= ' ' cCrypt Class Module ' ------------------- ' ' Created By : Kevin Wilson ' http://www.TheVBZone.com ( The VB Zone ) ' http://www.TheVBZone.net ( The VB Zone .net ) ' ' Created On : May 01, 2001 ' Last Update : January 23, 2007 ' ' VB Versions : 6.0 ' ' Requires : Windows 95 OSR2 or later (or Windows 95 with Internet Explorer 3.02 or later) ' ' Description : This class module was created to easily encrypt and decrypt strings using Hash encryption ' via the Windows API. ' '============================================================================================================= ' ' LEGAL: ' ' You are free to use this code as long as you keep the above heading information intact and unchanged. Credit ' given where credit is due. Also, it is not required, but it would be appreciated if you would mention ' somewhere in your compiled program that that your program makes use of code written and distributed by ' Kevin Wilson (www.TheVBZone.com). Feel free to link to this code via your web site or articles. ' ' You may NOT take this code and pass it off as your own. You may NOT distribute this code on your own server ' or web site. You may NOT take code created by Kevin Wilson (www.TheVBZone.com) and use it to create products, ' utilities, or applications that directly compete with products, utilities, and applications created by Kevin ' Wilson, TheVBZone.com, or Wilson Media. You may NOT take this code and sell it for profit without first ' obtaining the written consent of the author Kevin Wilson. ' ' These conditions are subject to change at the discretion of the owner Kevin Wilson at any time without ' warning or notice. Copyright© by Kevin Wilson. All rights reserved. ' '============================================================================================================= Public Enum EncryptReturnType ert_String = 0 ert_HEX = 1 ert_Numeric = 3 End Enum ' Constants - CryptAcquireContext.dwProvType Private Const PROV_RSA_FULL = 1 ' The PROV_RSA_FULL provider type supports both digital signatures and data encryption. It is considered a general purpose CSP. The RSA public-key algorithm is used for all public-key operations. Private Const PROV_RSA_SIG = 2 ' The PROV_RSA_SIG provider type is a subset of PROV_RSA_FULL. It supports only those functions and algorithms required for hashes and digital signatures. Private Const PROV_RSA_SCHANNEL = 12 ' The PROV_RSA_SCHANNEL provider type supports both RSA and Schannel protocols. Private Const PROV_DSS = 3 ' The PROV_DSS provider type, like PROV_RSA_SIG, only supports hashes and digital signatures. The signature algorithm specified by the PROV_DSS provider type is the Digital Signature Algorithm (DSA). Private Const PROV_DSS_DH = 13 ' The PROV_DSS_DH provider is a superset of the PROV_DSS provider type. Private Const PROV_DH_SCHANNEL = 18 ' The PROV_DH_SCHANNEL provider type supports both Diffie-Hellman and Schannel protocols Private Const PROV_FORTEZZA = 4 ' The PROV_FORTEZZA provider type contains a set of cryptographic protocols and algorithms owned by the National Institute of Standards and Technology (NIST). Private Const PROV_MS_EXCHANGE = 5 ' The PROV_MS_EXCHANGE provider type is designed for the cryptographic needs of the Microsoft Exchange mail application and other applications compatible with Microsoft Mail. This provider type is preliminary. Private Const PROV_SSL = 6 ' The PROV_SSL provider type supports the Secure Sockets Layer (SSL) protocol. ' Constants - CryptAcquireContext.pszProvider ' (The following Cryptographic Service Provider (CSP) names are defined in the Win32 API) Private Const MS_DEF_PROV As String = "Microsoft Base Cryptographic Provider v1.0" & vbNullChar Private Const MS_ENHANCED_PROV As String = "Microsoft Enhanced Cryptographic Provider" & vbNullChar Private Const MS_STRONG_PROV As String = "Microsoft Strong Cryptographic Provider" & vbNullChar Private Const MS_DEF_RSA_SIG_PROV As String = "Microsoft RSA Signature Cryptographic Provider" & vbNullChar Private Const MS_DEF_RSA_SCHANNEL_PROV As String = "Microsoft RSA SChannel Cryptographic Provider" & vbNullChar Private Const MS_DEF_DSS_PROV As String = "Microsoft Base DSS Cryptographic Provider" & vbNullChar Private Const MS_DEF_DSS_DH_PROV As String = "Microsoft Base DSS and Diffie-Hellman Cryptographic Provider" & vbNullChar Private Const MS_ENH_DSS_DH_PROV As String = "Microsoft Enhanced DSS and Diffie-Hellman Cryptographic Provider" & vbNullChar Private Const MS_DEF_DH_SCHANNEL_PROV As String = "Microsoft DH SChannel Cryptographic Provider" & vbNullChar Private Const MS_SCARD_PROV As String = "Microsoft Base Smart Card Cryptographic Provider" & vbNullChar ' Algorithm Classes Private Const ALG_CLASS_ANY = 0 Private Const ALG_CLASS_SIGNATURE = 8192 '(1 << 13) Private Const ALG_CLASS_MSG_ENCRYPT = 16384 '(2 << 13) Private Const ALG_CLASS_DATA_ENCRYPT = 24576 '(3 << 13) Private Const ALG_CLASS_HASH = 32768 '(4 << 13) Private Const ALG_CLASS_KEY_EXCHANGE = 40960 '(5 << 13) Private Const ALG_CLASS_ALL = 57344 '(7 << 13) ' Algorithm Types Private Const ALG_TYPE_ANY = 0 Private Const ALG_TYPE_DSS = 512 '(1 << 9) Private Const ALG_TYPE_RSA = 1024 '(2 << 9) Private Const ALG_TYPE_BLOCK = 1536 '(3 << 9) Private Const ALG_TYPE_STREAM = 2048 '(4 << 9) Private Const ALG_TYPE_DH = 2560 '(5 << 9) Private Const ALG_TYPE_SECURECHANNEL = 3072 '(6 << 9) ' Sub-IDs (Windows Compatible) Private Const ALG_SID_ANY = 0 Private Const ALG_SID_MD2 = 1 Private Const ALG_SID_RC2 = 2 Private Const ALG_SID_MD5 = 3 Private Const ALG_SID_SHA = 4 Private Const ALG_SID_SHA1 = 4 Private Const ALG_SID_MAC = 5 Private Const ALG_SID_SSL3SHAMD5 = 8 Private Const ALG_SID_HMAC = 9 ' Stream Cipher Sub-IDs Private Const ALG_SID_RC4 = 1 Private Const ALG_SID_SEAL = 2 ' Constants - CryptAcquireContext.dwFlags Private Const CRYPT_VERIFYCONTEXT = &HF0000000 ' The application has no access to the private keys, and the pszContainer parameter must be set to NULL. This option is intended for applications that do not use private keys. When CryptAcquireContext is called, many CSPs require input from the owning user before granting access to the private keys in the key container. For example, the private keys can be encrypted, requiring a password from the user before they can be used. However, if the CRYPT_VERIFYCONTEXT flag is specified, access to the private keys is not required and the user interface can be bypassed. Private Const CRYPT_NEWKEYSET = &H8 ' A new key container is created with the name specified by pszContainer. If pszContainer is NULL, a key container with the default name is created. Private Const CRYPT_MACHINE_KEYSET = &H20 ' By default, keys and key containers are stored as user keys. For Base Providers, this means that user key containers are stored in the user's profile. The CRYPT_MACHINE_KEYSET flag can be combined with all of the other flags to indicate that the key container of interest is a machine key container and the CSP treats it as such. For Base Providers, this means that the keys are stored locally on the computer that created the key container. If a key container is to be a machine container, the CRYPT_MACHINE_KEYSET flag must be used with all calls to CryptAcquireContext that reference the machine container. The CRYPT_MACHINE_KEYSET flag is useful when the user is accessing from a service or user account that did not log on interactively When key containers are created, most CSPs do not automatically create any public/private key pairs. These keys must be created as a separate step with the CryptGenKey function. Private Const CRYPT_DELETEKEYSET = &H10 ' The key container specified by pszContainer is deleted. If pszContainer is NULL, the key container with the default name is deleted. All key pairs in the key container are also destroyed. When this flag is set, the value returned in phProv is undefined, and thus, the CryptReleaseContext function need not be called afterwards. Private Const CRYPT_SILENT = &H40 ' The application requests that the CSP not display any user interface (UI) for this context. If the CSP must display the UI to operate, the call fails and the NTE_SILENT_CONTEXT error code is set as the last error. In addition, if calls are made to CryptGenKey with the CRYPT_USER_PROTECTED flag with a context that has been acquired with the CRYPT_SILENT flag, the calls fail and the CSP sets NTE_SILENT_CONTEXT. CRYPT_SILENT is intended for use with applications for which the UI cannot be displayed by the CSP. This flag is supported with Microsoft® Windows® 2000 or later. It is not supported in Windows 98 or Microsoft® Internet Explorer version 5.0. ' Constants - CryptHashData.dwFlags Private Const CRYPT_USERDATA = 1 'All Microsoft Cryptographic Providers ignore this parameter. For any CSP that does not ignore this parameter, if this flag is set, the CSP prompts the user to input data directly. This data is added to the hash. The application is not allowed access to the data. This flag can be used to allow the user to enter a PIN into the system. ' Constants - CryptDeriveKey.Algid Private Const CALG_RC2 = (ALG_CLASS_DATA_ENCRYPT Or ALG_TYPE_BLOCK Or ALG_SID_RC2) ' RC2 block cipher Private Const CALG_RC4 = (ALG_CLASS_DATA_ENCRYPT Or ALG_TYPE_STREAM Or ALG_SID_RC4) 'RC4 stream cipher ' Constants - CryptDecrypt.dwFlags Private Const CRYPT_OAEP = &H40 ' When set with the MS Enhanced Provider and RSA encryption/decryption causes PKCS #1 version 2 formatting to be used. ' Constants - CryptCreateHash.Algid Private Const CALG_HMAC = (ALG_CLASS_HASH Or ALG_TYPE_ANY Or ALG_SID_HMAC) ' HMAC, a keyed hash algorithm Private Const CALG_MAC = (ALG_CLASS_HASH Or ALG_TYPE_ANY Or ALG_SID_MAC) ' MAC Message Authentication Code Private Const CALG_MD2 = (ALG_CLASS_HASH Or ALG_TYPE_ANY Or ALG_SID_MD2) ' MD2 hashing algorithm Private Const CALG_MD5 = (ALG_CLASS_HASH Or ALG_TYPE_ANY Or ALG_SID_MD5) ' MD5 hashing algorithm Private Const CALG_SHA = (ALG_CLASS_HASH Or ALG_TYPE_ANY Or ALG_SID_SHA) ' US DSA Secure Hash Algorithm Private Const CALG_SHA1 = (ALG_CLASS_HASH Or ALG_TYPE_ANY Or ALG_SID_SHA1) ' Same as CALG_SHA Private Const CALG_SSL3_SHAMD5 = (ALG_CLASS_HASH Or ALG_TYPE_ANY Or ALG_SID_SSL3SHAMD5) ' SSL3 client authentication ' Error Constants Private Const ERROR_INVALID_HANDLE = 6& ' One of the parameters specifies an invalid handle. Private Const ERROR_INVALID_PARAMETER = 87 ' One of the parameters contains an invalid value. This is most often an illegal pointer. Private Const ERROR_NOT_ENOUGH_MEMORY = 8 ' The operating system ran out of memory during the operation. Private Const ERROR_BUSY = 170& ' The hash object specified by hHash is currently being used by another process. Private Const NTE_BAD_ALGID = &H80090008 ' The Algid parameter specifies an algorithm that this CSP does not support. Private Const NTE_BAD_DATA = &H80090005 ' The data to be encrypted is invalid. For example, when a block cipher is used and the Final flag is FALSE, the value specified by pdwDataLen must be a multiple of the block size. Private Const NTE_BAD_FLAGS = &H80090009 ' The dwFlags parameter has an illegal value. Private Const NTE_BAD_HASH = &H80090002 ' The hash object specified by the hHash parameter is invalid. Private Const NTE_BAD_HASH_STATE = &H8009000C ' An attempt was made to add data to a hash object that is already marked "finished". Private Const NTE_BAD_KEY = &H80090003 ' A keyed hash algorithm (such as CALG_MAC) is specified by Algid and the hKey parameter is either zero or it specifies an invalid key handle. This error code will also be returned if the key is to a stream cipher, or if the cipher mode is anything other than CBC. Private Const NTE_BAD_KEYSET = &H80090016 ' The Registry entry for the key container could not be opened and may not exist. Private Const NTE_BAD_KEYSET_PARAM = &H8009001F ' The pszContainer or pszProvider parameter is set to an illegal value. Private Const NTE_BAD_LEN = &H80090004 ' The CRYPT_USERDATA flag is set and the dwDataLen parameter has a nonzero value. Private Const NTE_BAD_PROV_TYPE = &H80090014 ' The value of the dwProvType parameter is out of range. All provider types must be from 1 to 999, inclusive. Private Const NTE_BAD_SIGNATURE = &H80090006 ' The provider DLL signature did not verify correctly. Either the DLL or the digital signature has been tampered with. Private Const NTE_BAD_UID = &H80090001 ' The CSP context that was specified when the hash object was created cannot be found. Private Const NTE_DOUBLE_ENCRYPT = &H80090012 ' The application attempted to encrypt the same data twice. Private Const NTE_EXISTS = &H8009000F ' The dwFlags parameter is CRYPT_NEWKEYSET, but the key container already exists. Private Const NTE_FAIL = &H80090020 ' The function failed in some unexpected way. Private Const NTE_KEYSET_ENTRY_BAD = &H8009001A ' The Registry entry for the pszContainer key container was found (in the HKEY_CURRENT_USER window), but is corrupt. See the section System Administration for details about CryptoAPI’s Registry usage. Private Const NTE_KEYSET_NOT_DEF = &H80090019 ' No Registry entry exists in the HKEY_CURRENT_USER window for the key container specified by pszContainer. Private Const NTE_NO_MEMORY = &H8009000E ' The CSP ran out of memory during the operation. Private Const NTE_PROV_DLL_NOT_FOUND = &H8009001E ' The provider DLL file does not exist or is not on the current path. Private Const NTE_PROV_TYPE_ENTRY_BAD = &H80090018 ' The Registry entry for the provider type specified by dwProvType is corrupt. This error may relate to either the user default CSP list or the machine default CSP list. See the section System Administration for details about CryptoAPI’s Registry usage. Private Const NTE_PROV_TYPE_NO_MATCH = &H8009001B ' The provider type specified by dwProvType does not match the provider type found in the Registry. Note that this error can only occur when pszProvider specifies an actual CSP name. Private Const NTE_PROV_TYPE_NOT_DEF = &H80090017 ' No Registry entry exists for the provider type specified by dwProvType. Private Const NTE_PROVIDER_DLL_FAIL = &H8009001D ' The provider DLL file could not be loaded, and may not exist. If it exists, then the file is not a valid DLL. Private Const NTE_SIGNATURE_FILE_BAD = &H8009001C ' An error occurred while loading the DLL file image, prior to verifying its signature. ' Property Variables Private p_Password As String Private p_CSP_String As String Private p_CSP_Type As Long ' Win32 API Declarations - General Private Declare Function GetLastError Lib "KERNEL32" () As Long ' Win32 API Declarations - Encryption Private Declare Function CryptAcquireContext Lib "advapi32.dll" Alias "CryptAcquireContextA" (ByRef phProv As Long, ByVal pszContainer As Long, ByVal pszProvider As String, ByVal dwProvType As Long, ByVal dwFlags As Long) As Long Private Declare Function CryptCreateHash Lib "advapi32.dll" (ByVal hProv As Long, ByVal Algid As Long, ByVal hKey As Long, ByVal dwFlags As Long, ByRef phHash As Long) As Long Private Declare Function CryptHashData Lib "advapi32.dll" (ByVal hHash As Long, ByVal pbData As String, ByVal dwDataLen As Long, ByVal dwFlags As Long) As Long Private Declare Function CryptDeriveKey Lib "advapi32.dll" (ByVal hProv As Long, ByVal Algid As Long, ByVal hBaseData As Long, ByVal dwFlags As Long, ByRef phKey As Long) As Long Private Declare Function CryptDestroyHash Lib "advapi32.dll" (ByVal hHash As Long) As Long Private Declare Function CryptDestroyKey Lib "advapi32.dll" (ByVal hKey As Long) As Long Private Declare Function CryptEncrypt Lib "advapi32.dll" (ByVal hKey As Long, ByVal hHash As Long, ByVal Final As Long, ByVal dwFlags As Long, ByVal pbData As String, ByRef pdwDataLen As Long, ByVal dwBufLen As Long) As Long Private Declare Function CryptDecrypt Lib "advapi32.dll" (ByVal hKey As Long, ByVal hHash As Long, ByVal Final As Long, ByVal dwFlags As Long, ByVal pbData As String, ByRef pdwDataLen As Long) As Long Private Declare Function CryptReleaseContext Lib "advapi32.dll" (ByVal hProv As Long, ByVal dwFlags As Long) As Long 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Private Sub Class_Initialize() p_Password = "password" p_CSP_String = MS_STRONG_PROV 'MS_DEF_PROV p_CSP_Type = PROV_RSA_FULL End Sub 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Public Property Get Password() As String Password = p_Password End Property Public Property Let Password(ByVal NewValue As String) p_Password = NewValue End Property 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ' This procedure is the one that actually does the work of decrypting the data Public Function Decrypt_String(ByVal StringToDecrypt As String, _ ByRef Return_String As String, _ Optional ByVal ConvertFromFormat As EncryptReturnType = ert_HEX, _ Optional ByRef Return_ErrNum As Long = 0, _ Optional ByRef Return_ErrDesc As String = "") As Boolean On Error GoTo ErrorTrap Dim lngHash As Long Dim lngKey As Long Dim lngCryptProv As Long Dim strCryptBuffer As String Dim lngCryptBuffLen As Long ' Set default values Return_String = "" Return_ErrNum = 0 Return_ErrDesc = "" ' Make sure the user has specified a password If p_Password = "" Then Return_ErrNum = -1: Return_ErrDesc = "No password has been defined to decrypt with" Exit Function ' Make sure decrypt string is valid ElseIf StringToDecrypt = "" Then Return_ErrNum = -1: Return_ErrDesc = "No string specified to decrypt" Exit Function ' Make sure the convertion type is vaild ElseIf ConvertFromFormat <> ert_String And ConvertFromFormat <> ert_Numeric And ConvertFromFormat <> ert_HEX Then Return_ErrNum = -1: Return_ErrDesc = "Convert type is invalid" Exit Function End If Select Case ConvertFromFormat Case ert_Numeric ' Strip out any "white space" characters" StringToDecrypt = Replace(StringToDecrypt, " ", "") StringToDecrypt = Replace(StringToDecrypt, vbTab, "") StringToDecrypt = Replace(StringToDecrypt, vbCr, "") StringToDecrypt = Replace(StringToDecrypt, vbLf, "") ' If the user is converting from a number, it has to be numeric If ContainsNonNumeric(StringToDecrypt) = True Then Return_ErrNum = -1: Return_ErrDesc = "Invalid decimal string specified to convert. Conversion string must only contain numeric characters." Exit Function End If ' Convert the numbers to string StringToDecrypt = Convert_NUMtoSTR(StringToDecrypt) Case ert_HEX ' Strip out any "white space" characters" StringToDecrypt = Replace(StringToDecrypt, " ", "") StringToDecrypt = Replace(StringToDecrypt, vbTab, "") StringToDecrypt = Replace(StringToDecrypt, vbCr, "") StringToDecrypt = Replace(StringToDecrypt, vbLf, "") ' Convert the HEX to string StringToDecrypt = Convert_HEXtoSTR(StringToDecrypt) End Select ' Get handle to the default CSP If CryptAcquireContext(lngCryptProv, 0, p_CSP_String, p_CSP_Type, CRYPT_MACHINE_KEYSET) = 0 Then ' Bad provider name or API error CheckGetLastError Err.LastDllError, Return_ErrNum, Return_ErrDesc, "CryptAcquireContext", False Exit Function End If ' Create a hash object If CryptCreateHash(lngCryptProv, CALG_MD5, 0, 0, lngHash) = 0 Then ' Error creating encrypt object or API error CheckGetLastError Err.LastDllError, Return_ErrNum, Return_ErrDesc, "CryptCreateHash", False GoTo CleanUp End If ' Hash in the password text If CryptHashData(lngHash, p_Password, Len(p_Password), 0) = 0 Then ' Error passing key or API error CheckGetLastError Err.LastDllError, Return_ErrNum, Return_ErrDesc, "CryptHashData", False GoTo CleanUp End If ' Create a session key from the hash object If CryptDeriveKey(lngCryptProv, CALG_RC4, lngHash, 0, lngKey) = 0 Then ' Error creating a session key or API error CheckGetLastError Err.LastDllError, Return_ErrNum, Return_ErrDesc, "CryptDeriveKey", False GoTo CleanUp End If ' Destroy the hash object. CryptDestroyHash lngHash lngHash = 0 ' Prepare strCryptBuffer for CryptDecrypt lngCryptBuffLen = Len(StringToDecrypt) * 2 strCryptBuffer = String(lngCryptBuffLen, vbNullChar) 'LSet strCryptBuffer = StringToDecrypt Mid(strCryptBuffer, 1) = StringToDecrypt ' Decrypt data If CryptDecrypt(lngKey, 0, 1, 0, strCryptBuffer, lngCryptBuffLen) = 0 Then If CheckGetLastError(GetLastError, , , "CryptDecrypt", True) = False Then Err.Raise -1, "CryptDecrypt", "Error decrypting string or API error" GoTo CleanUp End If ' Setup output buffer with just decrypted data Return_String = Mid(strCryptBuffer, 1, lngCryptBuffLen / 2) ' Success! Decrypt_String = True CleanUp: ' Destroy session key If lngKey <> 0 Then CryptDestroyKey lngKey ' Destroy hash object If lngHash <> 0 Then CryptDestroyHash lngHash ' Release Context provider handle If lngCryptProv <> 0 Then CryptReleaseContext lngCryptProv, 0 Exit Function ErrorTrap: Return_ErrNum = Err.Number Return_ErrDesc = Err.Description Err.Clear GoTo CleanUp End Function ' This method is the method that actually does the work of encrypting the data Public Function Encrypt_String(ByVal StringToEncrypt As String, _ ByRef Return_String As String, _ Optional ByVal ConvertToFormat As EncryptReturnType = ert_HEX, _ Optional ByRef Return_ErrNum As Long = 0, _ Optional ByRef Return_ErrDesc As String = "") As Boolean On Error GoTo ErrorTrap Dim lngHash As Long Dim lngKey As Long Dim lngCryptProv As Long Dim lngCryptLen As Long Dim strCryptBuffer As String Dim lngCryptBuffLen As Long ' Set default values Return_String = "" Return_ErrNum = 0 Return_ErrDesc = "" ' Make sure the user has specified a password If p_Password = "" Then Return_ErrNum = -1: Return_ErrDesc = "No password has been defined to encrypt with" Exit Function ' Make sure encrypt string is valid ElseIf StringToEncrypt = "" Then Return_ErrNum = -1: Return_ErrDesc = "No string specified to encrypt" Exit Function ' Make sure the convertion type is vaild ElseIf ConvertToFormat <> ert_String And ConvertToFormat <> ert_Numeric And ConvertToFormat <> ert_HEX Then Return_ErrNum = -1: Return_ErrDesc = "Convert type is invalid" Exit Function End If ' Get handle to the default CSP If CryptAcquireContext(lngCryptProv, 0, p_CSP_String, p_CSP_Type, CRYPT_MACHINE_KEYSET) = 0 Then ' If there is no default key container then create one using Flags field CheckGetLastError Err.LastDllError, Return_ErrNum, Return_ErrDesc, "CryptAcquireContext", False If Return_ErrNum = -2146893802 Then Return_ErrNum = 0 Return_ErrDesc = "" If CryptAcquireContext(lngCryptProv, 0, p_CSP_String, p_CSP_Type, CRYPT_NEWKEYSET Or CRYPT_MACHINE_KEYSET) = 0 Then CheckGetLastError Err.LastDllError, Return_ErrNum, Return_ErrDesc, "CryptAcquireContext", False Exit Function End If Else Exit Function End If End If ' Create a hash object If CryptCreateHash(lngCryptProv, CALG_MD5, 0, 0, lngHash) = 0 Then ' Error creating encrypt object or API error CheckGetLastError Err.LastDllError, Return_ErrNum, Return_ErrDesc, "CryptCreateHash", False GoTo CleanUp End If ' Hash in the password text If CryptHashData(lngHash, p_Password, Len(p_Password), 0) = 0 Then ' Error passing key or API error CheckGetLastError Err.LastDllError, Return_ErrNum, Return_ErrDesc, "CryptHashData", False GoTo CleanUp End If ' Create a session key from the hash object. If CryptDeriveKey(lngCryptProv, CALG_RC4, lngHash, 0, lngKey) = 0 Then ' Error creating session key or API error CheckGetLastError Err.LastDllError, Return_ErrNum, Return_ErrDesc, "CryptDeriveKey", False GoTo CleanUp End If ' Destroy the hash object. CryptDestroyHash lngHash lngHash = 0 ' Create a buffer for the CryptEncrypt function lngCryptLen = Len(StringToEncrypt) lngCryptBuffLen = lngCryptLen * 2 strCryptBuffer = String(lngCryptBuffLen, vbNullChar) 'LSet strCryptBuffer = StringToEncrypt Mid(strCryptBuffer, 1) = StringToEncrypt ' Encrypt the text data If CryptEncrypt(lngKey, 0, 1, 0, strCryptBuffer, lngCryptLen, lngCryptBuffLen) = 0 Then ' Error encrypting the data or API error CheckGetLastError Err.LastDllError, Return_ErrNum, Return_ErrDesc, "CryptEncrypt", False GoTo CleanUp End If ' Return the results Return_String = Mid(strCryptBuffer, 1, lngCryptLen) Select Case ConvertToFormat Case ert_Numeric: Return_String = Convert_STRtoNUM(Return_String) Case ert_HEX: Return_String = Convert_STRtoHEX(Return_String) End Select ' Success! Encrypt_String = True CleanUp: ' Destroy session key. If lngKey <> 0 Then CryptDestroyKey lngKey ' Destroy hash object If lngHash <> 0 Then CryptDestroyHash lngHash ' Release Context provider handle If lngCryptProv <> 0 Then CryptReleaseContext lngCryptProv, 0 Exit Function ErrorTrap: Return_ErrNum = Err.Number Return_ErrDesc = Err.Description Err.Clear GoTo CleanUp End Function 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ' Function that takes a string and takes it letter by letter and converts it ' the ASCII numerical equivelent... and then returns a string of numbers Private Function Convert_STRtoNUM(ByVal StringToConvert As String) As String On Error Resume Next Dim lngCounter As Long ' Set default values Err.Clear Convert_STRtoNUM = "" ' Loop through the string and convert it to character numbers 1 character at a time For lngCounter = 1 To Len(StringToConvert) Convert_STRtoNUM = Convert_STRtoNUM & Right("00" & CStr(Asc(Mid(StringToConvert, lngCounter, 1))), 3) Next End Function ' Function that takes a string and takes it letter by letter and converts it ' the string equivelent... and then returns a string of characters Private Function Convert_NUMtoSTR(ByVal NumbersToConvert As String, _ Optional ByVal blnContinueOnError As Boolean = True, _ Optional ByRef Return_ErrorOccured As Boolean = False) As String On Error GoTo ErrorTrap Dim lngCounter As Long ' Set default values Err.Clear Convert_NUMtoSTR = "" Return_ErrorOccured = False ' Make sure the string has the right number of characters (devisible by 3 evenly) If Len(NumbersToConvert) Mod 3 <> 0 Then Return_ErrorOccured = True If blnContinueOnError = False Then Exit Function End If ' Loop through the string 3 characters at a time and convert the character values to string For lngCounter = 1 To Len(NumbersToConvert) Step 3 Convert_NUMtoSTR = Convert_NUMtoSTR & Chr(CLng(Mid(NumbersToConvert, lngCounter, 3))) Next Exit Function ErrorTrap: Err.Clear Return_ErrorOccured = True If blnContinueOnError = True Then Resume Next Else Convert_NUMtoSTR = "" End If End Function ' Function that takes a string and takes it letter by letter and converts it ' the HEXIDECIMAL equivelent... and then returns a string of HEX values Private Function Convert_STRtoHEX(ByVal StringToConvert As String) As String On Error Resume Next Dim lngCounter As Long ' Set default values Err.Clear Convert_STRtoHEX = "" ' Loop through the string and convert it to HEX 1 character at a time For lngCounter = 1 To Len(StringToConvert) Convert_STRtoHEX = Convert_STRtoHEX & Right("0" & CStr(Hex(Asc(Mid(StringToConvert, lngCounter, 1)))), 2) Next End Function ' Function that takes a string and takes it letter by letter and converts it ' the string value equivelent... and then returns the string of characters Private Function Convert_HEXtoSTR(ByVal HexToConvert As String, _ Optional ByVal blnContinueOnError As Boolean = True, _ Optional ByRef Return_ErrorOccured As Boolean = False) As String On Error GoTo ErrorTrap Dim lngCounter As Long ' Set default values Err.Clear Convert_HEXtoSTR = "" Return_ErrorOccured = False ' Make sure the string has the right number of characters (devisible by 2 evenly) If Len(HexToConvert) Mod 2 <> 0 Then Return_ErrorOccured = True If blnContinueOnError = False Then Exit Function End If ' Loop through the string 2 characters at a time and convert the HEX to string For lngCounter = 1 To Len(HexToConvert) Step 2 Convert_HEXtoSTR = Convert_HEXtoSTR & Chr(Val("&H" & Mid(HexToConvert, lngCounter, 2))) Next Exit Function ErrorTrap: Err.Clear Return_ErrorOccured = True If blnContinueOnError = True Then Resume Next Else Convert_HEXtoSTR = "" End If End Function ' Generates a random password that is used to encrypt the data Public Function GeneratePassword(ByVal PasswordLength As Integer) As String On Error GoTo ErrorTrap Dim INVALID_CHARS As String Dim lngCounter As Long Dim lngChar As Long ' Set default values Err.Clear GeneratePassword = "" ' Specify which characters are invalid INVALID_CHARS = Chr(34) & "%'*,./\:;<>=?&`" ' Restrict maximum password length to 256 If PasswordLength > 256 Then PasswordLength = 256 ' Generate random password For lngCounter = 1 To PasswordLength lngChar = 0 Do Do Randomize Timer lngChar = CLng((122 - 33 + 1) * Rnd + 33) Loop While (lngChar < 33) And (lngChar > 122) Loop While InStr(1, INVALID_CHARS, Chr(lngChar), vbBinaryCompare) <> 0 GeneratePassword = GeneratePassword & Chr(lngChar) Next Exit Function ErrorTrap: If Err.Number = 0 Then ' No Error Resume Next ElseIf Err.Number = 20 Then ' Resume Without Error Resume Next Else ' Other Error MsgBox Err.Source & " caused the following error:" & Chr(13) & Chr(13) & "Error Number = " & CStr(Err.Number) & Chr(13) & "Error Description = " & Err.Description, vbOKOnly + vbExclamation, " Error - " & Err.Description Err.Clear End If End Function ' Function that checks if an error occured in the last crypt related API ' called, and if there was... an error message is displayed Private Function CheckGetLastError(ByVal ErrorNumber As Long, _ Optional ByRef Return_ErrNum As Long, _ Optional ByRef Return_ErrDesc As String, _ Optional ByVal NameOfLastAPICalled As String = "last", _ Optional ByVal ShowErrorMsg As Boolean = True) As Boolean On Error Resume Next ' Set the default return values Return_ErrNum = 0 Return_ErrDesc = "" CheckGetLastError = False ' Check if an error number was passed. If none was, check for an error occurance. If ErrorNumber = 0 Then ErrorNumber = GetLastError If ErrorNumber = 0 Then Err.Clear Exit Function End If End If ' An Error Occured CheckGetLastError = True Return_ErrNum = ErrorNumber Err.Clear ' Get the error text Select Case ErrorNumber Case 0: Exit Function Case ERROR_INVALID_HANDLE: Return_ErrDesc = "One of the parameters specifies an invalid handle." Case ERROR_INVALID_PARAMETER: Return_ErrDesc = "One of the parameters contains an invalid value. This is most often an illegal pointer." Case ERROR_NOT_ENOUGH_MEMORY: Return_ErrDesc = "The operating system ran out of memory during the operation." Case ERROR_BUSY: Return_ErrDesc = "The hash object specified by hHash is currently being used by another process." Case NTE_BAD_ALGID: Return_ErrDesc = "The Algid parameter specifies an algorithm that this CSP does not support." Case NTE_BAD_DATA: Return_ErrDesc = "The data to be encrypted is invalid. For example, when a block cipher is used and the Final flag is FALSE, the value specified by pdwDataLen must be a multiple of the block size." Case NTE_BAD_FLAGS: Return_ErrDesc = "The dwFlags parameter has an illegal value." Case NTE_BAD_HASH: Return_ErrDesc = "The hash object specified by the hHash parameter is invalid." Case NTE_BAD_HASH_STATE: Return_ErrDesc = "An attempt was made to add data to a hash object that is already marked 'finished'." Case NTE_BAD_KEY: Return_ErrDesc = "A keyed hash algorithm (such as CALG_MAC) is specified by Algid and the hKey parameter is either zero or it specifies an invalid key handle. This error code will also be returned if the key is to a stream cipher, or if the cipher mode is anything other than CBC." Case NTE_BAD_KEYSET: Return_ErrDesc = "The Registry entry for the key container could not be opened and may not exist." Case NTE_BAD_KEYSET_PARAM: Return_ErrDesc = "The pszContainer or pszProvider parameter is set to an illegal value." Case NTE_BAD_LEN: Return_ErrDesc = "The CRYPT_USERDATA flag is set and the dwDataLen parameter has a nonzero value." Case NTE_BAD_PROV_TYPE: Return_ErrDesc = "The value of the dwProvType parameter is out of range. All provider types must be from 1 to 999, inclusive." Case NTE_BAD_SIGNATURE: Return_ErrDesc = "The provider DLL signature did not verify correctly. Either the DLL or the digital signature has been tampered with." Case NTE_BAD_UID: Return_ErrDesc = "The CSP context that was specified when the hash object was created cannot be found." Case NTE_DOUBLE_ENCRYPT: Return_ErrDesc = "The application attempted to encrypt the same data twice." Case NTE_EXISTS: Return_ErrDesc = "The dwFlags parameter is CRYPT_NEWKEYSET, but the key container already exists." Case NTE_FAIL: Return_ErrDesc = "The function failed in some unexpected way." Case NTE_KEYSET_ENTRY_BAD: Return_ErrDesc = "The Registry entry for the pszContainer key container was found (in the HKEY_CURRENT_USER window), but is corrupt. See the section System Administration for details about CryptoAPI’s Registry usage." Case NTE_KEYSET_NOT_DEF: Return_ErrDesc = "No Registry entry exists in the HKEY_CURRENT_USER window for the key container specified by pszContainer." Case NTE_NO_MEMORY: Return_ErrDesc = "The CSP ran out of memory during the operation." Case NTE_PROV_DLL_NOT_FOUND: Return_ErrDesc = "The provider DLL file does not exist or is not on the current path." Case NTE_PROV_TYPE_ENTRY_BAD: Return_ErrDesc = "The Registry entry for the provider type specified by dwProvType is corrupt. This error may relate to either the user default CSP list or the machine default CSP list. See the section System Administration for details about CryptoAPI’s Registry usage." Case NTE_PROV_TYPE_NO_MATCH: Return_ErrDesc = "The provider type specified by dwProvType does not match the provider type found in the Registry. Note that this error can only occur when pszProvider specifies an actual CSP name." Case NTE_PROV_TYPE_NOT_DEF: Return_ErrDesc = "No Registry entry exists for the provider type specified by dwProvType." Case NTE_PROVIDER_DLL_FAIL: Return_ErrDesc = "The provider DLL file could not be loaded, and may not exist. If it exists, then the file is not a valid DLL." Case NTE_SIGNATURE_FILE_BAD: Return_ErrDesc = "An error occurred while loading the DLL file image, prior to verifying its signature." Case Else: Return_ErrDesc = "Unknown Error" End Select ' Display the error If ShowErrorMsg = True Then MsgBox "The " & NameOfLastAPICalled & " Windows API caused the following error:" & Chr(13) & Chr(13) & "Error Number = " & CStr(ErrorNumber) & Chr(13) & "Error Description = " & Return_ErrDesc, vbOKOnly + vbExclamation, " Windows API Error" End If End Function Private Function ContainsNonNumeric(ByVal StringToCheck As String) As Boolean Dim lngCounter As Long For lngCounter = 1 To Len(StringToCheck) Step 10 If IsNumeric(Mid(StringToCheck, lngCounter, 10)) = False Then ContainsNonNumeric = True Exit For End If Next End Function