作者:Jack Ryan
作者试图使用 prg 重新实现 VFPENCRYPTION.FLL 以便于平替该 FLL。按照作者说明,还是有一些问题。仅供学习。
*---This is intended to be a drop in replacement for vfpencryption.fll that has been a wonderful resource,
*---but is no longer supported by its donor and was built with superseded VC++ for 32-bit only.
*---This replacement should work without extra dependencies on x86 and x64 Vista and later because it uses Windows bcrypt.dll.
*---this code relies heavily on Christof Wollenhaupt's excellent foxcryptong.prg whose code is replicated and edited for a few reasons:
*---to match VFPencryption better, especially padding, and (for example) because foxcryptong does a STRCONV() on hashes but VFPEncryption.fll does not,
*---also to allow cipher specification like the fll.
*---this code also ensures that expensive DECLARE DLLs only occur when actually needed.
*---To use: SET PROC TO vfpencryptionfll.prg rather than SET LIBRARY TO vfpencryption.fll.
#Define _FLLCOMPATIBILITY .F.
*---While the formal AES spec says block length is always 16 bytes, VFPEncryption.fll's ENCRYPT()/DECRYPT() appears to use 32 bytes by default.
*---The plan is that if fll compatibility is set, the default AES 16-byte blocksize is quietly reset to 32 bytes for a drop-in replacement.
*---note: not working, as bcrypt seems not to allow any blocklength except 16. See below.
*---If your existing code includes a 16-byte blocksize parameter or you want standard AES by default, you don't need this flag.
#Define _STRIPPADDING .T.
*---This DECRYPT() does a better job of stripping padding than the fll that sometimes leaves spaces or chr(0).
*---If this is an issue (e.g. you have code that expects padding still there) then turn off _STRIPPADDING.
Function HASH(tcData,nHashType) &&HASH(cStringtohash,nHashType)
*---replicates VFPEncryption Hash function.
*---NOTE: nHashtype 6 and 7 not implemented at this time
*!* nHashType ?The type of hash function to generate.
*!* 1 = SHA1 (a.k.a SHA160)
*!* 2 = SHA256
*!* 3 = SHA384
*!* 4 = SHA512 *Default
*!* 5 = MD5
*!* 6 = RIPEMD128
*!* 7 = RIPEMD160
Local tcAlgorithm
tcAlgorithm=Getwordnum("SHA160 SHA256 SHA384 SHA512 MD5",Iif(Vartype(m.nHashType)="N" And Between(m.nHashType,1,5),m.nHashType,4))
*--this is derived from the excellent foxcryptong
*--class not used directly because (for example) it does strconv on hash values that VFPEncryption does not,
*--also some extra functionality in VFP Encryption
*--------------------------------------------------------------------------------------
* Stop when we encounter a failure
*--------------------------------------------------------------------------------------
Local llOK,lnAlg
llOK = .T.
*--------------------------------------------------------------------------------------
* Get a handle to the hashing algorithm provider
*--------------------------------------------------------------------------------------
lnAlg = 0
*If m.llOK
llOK = BCryptOpenAlgorithmProvider( ;
@lnAlg, Strconv(m.tcAlgorithm+Chr(0),5), Null, 0 ) == 0
*EndIf
*--------------------------------------------------------------------------------------
* Determine how many bytes we need to store the hash object.
*--------------------------------------------------------------------------------------
If m.llOK
Local lnSizeObj, lnData
lnSizeObj = 0
lnData = 0
llOK = BCryptGetProperty( m.lnAlg, ;
Strconv("ObjectLength"+Chr(0),5), @lnSizeObj, ;
4, @lnData, 0 ) == 0
Endif
*--------------------------------------------------------------------------------------
* Determine length of hash value
* JR: Actually could avoid this call since we can easily compute hash length. Oh well
*--------------------------------------------------------------------------------------
If m.llOK
Local lnSizeHash
lnSizeHash = 0
llOK = BCryptGetProperty( m.lnAlg, ;
Strconv("HashDigestLength"+Chr(0),5), ;
@lnSizeHash, 4, @lnData, 0 ) == 0
Endif
*--------------------------------------------------------------------------------------
* Allocate memory for the hash object
*--------------------------------------------------------------------------------------
Local lnHashObj
If m.llOK
lnHashObj = HeapAlloc (GetProcessHeap (), 0, m.lnSizeObj)
llOK = m.lnHashObj <> 0
Endif
*--------------------------------------------------------------------------------------
* Create the hash object
*--------------------------------------------------------------------------------------
Local lnHash
lnHash = 0
If m.llOK
llOK = BCryptCreateHash( m.lnAlg, @lnHash, ;
lnHashObj, m.lnSizeObj, Null, 0, 0 ) == 0
Endif
*--------------------------------------------------------------------------------------
* To create the hash value we add data to the hash object. You can repeat this step
* as often as needed.
*--------------------------------------------------------------------------------------
If m.llOK
llOK = BCryptHashData (m.lnHash, m.tcData, Len(m.tcData), 0) == 0
Endif
*--------------------------------------------------------------------------------------
* Signal the hash object that we are done. The algorithm then calculates the hash value
* and returns it.
*--------------------------------------------------------------------------------------
Local lcHash
If m.llOK
lcHash = Space(m.lnSizeHash)
llOK = BCryptFinishHash (m.lnHash, @lcHash, m.lnSizeHash, 0) == 0
Endif
*---JR vfpencryption doesn't strconv it...
*--------------------------------------------------------------------------------------
* Hashes are commonly viewed in the hex representation rather than the original
* binary form. As the final step we now convert the hash value into a hex string. Use
* STRCONV() if you do need a binary value, instead.
*--------------------------------------------------------------------------------------
*If m.llOK
* lcHash = Strconv (m.lcHash, 15)
*EndIf
*--------------------------------------------------------------------------------------
* Cleanup
*--------------------------------------------------------------------------------------
If m.lnAlg != 0
BCryptCloseAlgorithmProvider (m.lnAlg, 0)
Endif
If m.lnHash != 0
BCryptDestroyHash (m.lnHash)
Endif
If Not Empty (m.lnHashObj)
HeapFree (GetProcessHeap (), 0, m.lnHashObj)
Endif
If Not m.llOK
lcHash = ""
Endif
Return m.lcHash
**************************************************************************************************************************************************************
**************************************************************************************************************************************************************
#Define BCRYPT_BLOCK_PADDING 0x00000001
#Define BCRYPT_BLOCK_NO_PADDING 0
#Define BCRYPT_PAD_NONE 0x00000001
#Define BCRYPT_PAD_PKCS1 0x00000002
#Define BCRYPT_PAD_OAEP 0x00000004
#Define BCRYPT_PAD_PSS 0x00000008
#Define BCRYPT_PAD_PKCS1_OPTIONAL_HASH_OID 0x00000010
**************************************************************************************************************************************************************
Function Encrypt(tcData,tcKey,tnEncryptionType,tnEncryptionmode,tnPaddingtype,tnKeysize,tnBlocksize,tcIV)
**************************************************************************************************************************************************************
*---Departures:
*---No Blowfish or TEA
*---No OFB Encryption mode
**VFPEncryption:
*!* 0 = Rijndael\AES 128 (requires a 16 character Key)
*!* 1 = Rijndael\AES 192 (requires a 24 character Key)
*!* 2 = Rijndael\AES 256 (requires a 32 character Key) *Default
*!* 4 = Blowfish (key between 1 and 56 characters)
*!* 8 = TEA (requires a 16 character Key)
*!* 1024 = RC4 (Key can be any length)
Local tcAlgorithm,liBlockLength,liKeylen
Do Case
Case Vartype(m.tnEncryptionType) !="N" &&apply default
tcAlgorithm="AES"
liKeylen=32
#If _FLLCOMPATIBILITY
liBlockLength=32 &&the dll uses 32-byte blocks
#Else
liBlockLength=16
#Endif
Case Between(m.tnEncryptionType,0,2) &&AES
tcAlgorithm="AES"
liKeylen=Icase(m.tnEncryptionType=0,16,m.tnEncryptionType=1,24,32)
#If _FLLCOMPATIBILITY
liBlockLength=32 &&the dll uses 32-byte blocks
#Else
liBlockLength=16
#Endif
*CASE m.tnEncryptionType=4
*---Windows BCrypt doesn't process Blowfish
*CASE m.tnEncryptionType=8
*---Windows BCrypt doesn't process TEA
Case m.tnEncryptionType=1024
*---included for completeness, but RC4 is insecure. Use AES.
tcAlgorithm="RC4"
liKeylen=0 &&key can be any length
liBlockLength=0
Otherwise
tcAlgorithm="AES"
liKeylen=32
#If _FLLCOMPATIBILITY
liBlockLength=32 &&the dll uses 32-byte blocks for AES
#Else
liBlockLength=16
#Endif
Endcase
*---Get the keylen correct- as bcrypt uses it to determine encryption level
*---from experimentation it appears that VFPEncryption replicates a short password as required
*---to reach correct key length.
Local liActualKeyLen
liActualKeyLen=Len(m.tcKey)
If Empty(m.tnKeysize)
Else
liKeylen=m.tnKeysize
Endif
If Empty(m.liKeylen) Or m.liActualKeyLen=m.liKeylen
Else
tcKey=Left(Iif(liActualKeyLen>m.liKeylen,m.tcKey,Replicate(m.tcKey,Ceiling(m.liKeylen/m.liActualKeyLen))),m.liKeylen)
Endif
*--------------------------------------------------------------------------------------
* Stop when we encounter a failure
*--------------------------------------------------------------------------------------
Local llOK
llOK = .T.
*--------------------------------------------------------------------------------------
* Get a handle to the algorithm provider
*--------------------------------------------------------------------------------------
Local lnAlg
lnAlg = 0
If m.llOK
llOK = BCryptOpenAlgorithmProvider( ;
@lnAlg, Strconv(m.tcAlgorithm+Chr(0),5), Null, 0 ) == 0
Endif
******************************************************************************************************
*---VFPEncryption:
*!* nEncryptionMode ?There are three different modes available for the each of the encryption types listed above. They include: Electronic Code Book (ECB), Cipher Block Chaining (CBC), Cipher Feedback Block (CFB), and Output Feedback Block. The nEncryptionMode parameter does not apply to RC4 encryption (nEncryptionType = 1024).
*!* 0 = ECB *Default
*!* 1 = CBC
*!* 2 = CFB
*!* 3 = OFB
*---chainingmode can be set in alg or key.
If m.llOK
Local lcChainingMode
Do Case
Case m.tcAlgorithm !="AES"
*---only need chaining mode for chained encryption
Case Vartype(m.tnEncryptionmode) !="N" Or Empty(m.tnEncryptionmode)
lcChainingMode="ChainingModeECB"
Case m.tnEncryptionmode=1
lcChainingMode="ChainingModeCBC"
Case m.tnEncryptionmode=2
lcChainingMode="ChainingModeCFB"
*---OFB appears not to be an option in bcrypt
*CASE m.tnEncryptionmode=3
* lcChainingMode="ChainingModeOFB"
Otherwise
lcChainingMode="ChainingModeECB"
Endcase
If Empty(m.lcChainingMode)
Else
*MS Learn: When setting the value for the property BCRYPT_CHAINING_MODE, the pbInput parameter is unbounded by cbInput. The caller needs to ensure a valid null-terminated Unicode string is provided.
llOK = BCryptSetProperty_String(m.lnAlg,Strconv("ChainingMode"+Chr(0),5),Strconv(m.lcChainingMode+Chr(0),5),0,0)=0
*!* Confirm setting
*!* lcVal=SPACE(200)
*!* lndata=0
*!* llOK = BCryptGetProperty2( m.lnalg, ;
*!* Strconv("ChainingMode"+Chr(0),5), @lcVal, ;
*!* 200, @lnData, 0 ) == 0
*!* lcVal=STRCONV(m.lcval,6)
*!* ? LEFT(m.lcVal,ATC(CHR(0),m.lcval))
*!* *ChainingModeECB
Endif
Endif
*--------------------------------------------------------------------------------------
* Turn the key into a symmetric key object that we can pass to the encryption funtion.
*--------------------------------------------------------------------------------------
Local lnKey
lnKey = 0
If m.llOK
llOK = BCryptGenerateSymmetricKey ( ;
m.lnAlg, @lnKey, Null, 0, @tcKey, Len (m.tcKey), 0) == 0
Endif
*!* Confirm chainingmode
*!* lcVal=Space(200)
*!* lnData=0
*!* llOK = BCryptGetProperty2( m.lnKey, ;
*!* Strconv("ChainingMode"+Chr(0),5), @lcVal, ;
*!* 200, @lnData, 0 ) == 0
*!* lcVal=Strconv(m.lcVal,6)
*!* ? Left(m.lcVal,Atc(Chr(0),m.lcVal))
*!* *ChainingModeECB
***************************************************************************************************************
* JR THIS THROWS AN ERROR TRYING TO SET BLOCKSIZE via integer or charttobin- can somebody fix it, or is it a BCRYPT limitation?
***************************************************************************************************************
*---set blocksize...
If m.llOK And m.liBlockLength>0
If Vartype(m.tnBlocksize) ="N" And m.liBlockLength != m.tnBlocksize
liBlockLength=m.tnBlocksize
Endif
*!* *--------------------------------------------------------------------------------------
*!* * Tried this too: Allocate memory for the setting pointer
*!* *--------------------------------------------------------------------------------------
*!* Local lnHashObj
*!* If m.llOK
*!* lnHashObj = HeapAlloc (GetProcessHeap (), 0, 4)
*!* llOK = m.lnHashObj <> 0
*!* EndIf
*!*
*!* IF m.llOK
Local lcBintoc
lcBintoc=BinToC(m.liBlockLength,4)
* SYS(2600,m.lnhashobj,4,m.lcBintoc)
* llOK = BCryptSetProperty_string(lnKey,Strconv("BlockLength"+Chr(0),5),m.lcBintoc,4,0)=0
*!* endif
Endif
*---Block length alwsys 16 for AES, but easy to check at this point if needed...
*!* If m.llOK
*!* local lnData
*!* liBlockLength = 0
*!* lnData = 0
*!* llOK = BCryptGetProperty( m.lnAlg, ;
*!* Strconv("BlockLength"+Chr(0),5), @liBlockLength, ;
*!* 4, @lnData, 0 ) == 0
*!* ENDIF
*---Padding:
******************************************************************************************************
*!* VFPEncryption:
*!* nPaddingMode ?For Block Ciphers the cStringtoEncrypt is padded to a multiple of the block size for the algorithm. Setting this parameter allows you to specify how this padding is done.
*!* 0 = Zeroes (NULLs) *Default
*!* 1 = Spaces (blanks)
*!* 2 = PKCS7
*!* 3 = ANSI X.923
*!* 4 = ISO 10126
*---bcrypt theoretically allows some padding definitions via a passed structure-
*---but bcrypt doesn't have the same or all the options in VFPEncryption and structures are no fun in VFP. This will do:
If m.llOK And m.liBlockLength>0
*---to match, this code needs to as well...
liPad=m.liBlockLength-Len(m.tcData)%m.liBlockLength
Do Case
Case Empty(m.tnPaddingtype)
tcData=m.tcData+Replicate(Chr(0),m.liPad)
Case m.tnPaddingtype=1
tcData=m.tcData+Space(m.liPad)
Case m.tnPaddingtype=2
*---need to add at least 1 char padding...
IF m.lipad=0
m.lipad=m.liBlocklength
ENDIF
Local lcChar
lcChar=Chr(m.liPad)
tcData=m.tcData+Replicate(m.lcChar,m.liPad)
Case m.tnPaddingtype=3
*In ANSI X.923 bytes filled with zeros are padded and the last byte defines the padding boundaries or the number of padded bytes.
*---need to add at least 1 char padding...
If m.liPad=0
m.liPad=m.liBlockLength
Endif
tcData=m.tcData+Replicate(Chr(0),m.liPad-1)+Chr(m.liPad)
Case m.tnPaddingtype=4
*ISO 10126 specifies that the padding should be done at the end of that last block with random bytes, and the padding boundary should be specified by the last byte.
*---need to add at least 1 char padding...
Local licounter,liRandoms,lcRandom
If m.liPad=0
liRandoms=m.liBlockLength-1
liPad=m.liBlockLength
Else
m.liRandoms=m.liPad-1
Endif
lcRandom=""
If m.liRandoms>0
For licounter=1 To m.liRandoms
lcRandom=m.lcRandom+Chr(Rand()*255)
Endfor
Endif
tcData=m.tcData+m.lcRandom+Chr(m.liPad)
Otherwise
tcData=m.tcData+Replicate(Chr(0),m.liPad)
Endcase
Endif
*--------------------------------------------------------------------------------------
* We handle a block ciphers. The size of encrypted data is a multiple of the block size
* which is based on the key length. We let the algorithm provider determine the actual
* length.
*--------------------------------------------------------------------------------------
Local lnSize
Local lcIV
If m.llOK
lnSize = 0
If Pcount() > 7 &&was 3, but VFPEncryption has more parameters!
m.lcIV = m.tcIV
llOK = BCryptEncrypt ( ;
m.lnKey, m.tcData, Len(m.tcData), Null, @m.lcIV, Len(m.lcIV), Null, 0, ;
@lnSize,BCRYPT_BLOCK_NO_PADDING) == 0
Else
llOK = BCryptEncrypt ( ;
m.lnKey, m.tcData, Len(m.tcData), Null, Null, 0, Null, 0, ;
@lnSize,BCRYPT_BLOCK_NO_PADDING) == 0
Endif
Endif
*--------------------------------------------------------------------------------------
* Now we can finally encrypt data
*--------------------------------------------------------------------------------------
Local lcEncrypted
If m.llOK
lcEncrypted = Space (m.lnSize)
If Pcount() > 7
m.lcIV = m.tcIV
llOK = BCryptEncrypt ( ;
m.lnKey, m.tcData, Len(m.tcData), Null, @m.lcIV, Len(m.lcIV), @lcEncrypted, ;
Len(m.lcEncrypted), @lnSize,BCRYPT_BLOCK_NO_PADDING) == 0
Else
llOK = BCryptEncrypt ( ;
m.lnKey, m.tcData, Len(m.tcData), Null, Null, 0, @lcEncrypted, ;
Len(m.lcEncrypted), @lnSize,BCRYPT_BLOCK_NO_PADDING) == 0
Endif
Endif
*--------------------------------------------------------------------------------------
* Properly close any open handle. We return an empty varbinary value if any error
* occurred.
*--------------------------------------------------------------------------------------
If m.lnKey != 0
BCryptDestroyKey (m.lnKey)
Endif
If m.lnAlg != 0
BCryptCloseAlgorithmProvider (m.lnAlg, 0)
Endif
If Not m.llOK
lcEncrypted = ""
Endif
Return m.lcEncrypted
***************************************************************************************************************************************************************************
Function DECRYPT(tcData,tcKey,tnDecryptionType,tnDecryptionMode,tnPaddingtype,tnKeysize,tnBlocksize,tcIV)
*---vfpencryption specifies encryption level, but
*---bcrypt uses key length
*---Departures:
*---No Blowfish or TEA
*---No OFB Encryption mode
**VFPEncryption:
*!* 0 = Rijndael\AES 128 (requires a 16 character Key)
*!* 1 = Rijndael\AES 192 (requires a 24 character Key)
*!* 2 = Rijndael\AES 256 (requires a 32 character Key) *Default
*!* 4 = Blowfish (key between 1 and 56 characters)
*!* 8 = TEA (requires a 16 character Key)
*!* 1024 = RC4 (Key can be any length)
Local tcAlgorithm,liBlockLength,liKeylen
Do Case
Case Vartype(m.tnDecryptionType) !="N" &&apply default
tcAlgorithm="AES"
liKeylen=32
#If _FLLCOMPATIBILITY
liBlockLength=32 &&the dll uses 32-byte blocks
#Else
liBlockLength=16
#Endif
Case Between(m.tnDecryptionType,0,2) &&AES
tcAlgorithm="AES"
liKeylen=Icase(m.tnDecryptionType=0,16,m.tnDecryptionType=1,24,32)
#If _FLLCOMPATIBILITY
liBlockLength=32 &&the dll uses 32-byte blocks
#Else
liBlockLength=16
#Endif
*CASE m.tnDecryptionType=4
*---Windows BCrypt doesn't process Blowfish
*CASE m.tnDecryptionType=8
*---Windows BCrypt doesn't process TEA
Case m.tnDencryptionType=1024
*---included for completeness, but RC4 is insecure. Use AES.
tcAlgorithm="RC4"
liKeylen=0 &&key can be any length
liBlockLength=0
Otherwise
tcAlgorithm="AES"
liKeylen=32
#If _FLLCOMPATIBILITY
liBlockLength=32 &&the dll uses 32-byte blocks
#Else
liBlockLength=16
#Endif
Endcase
*---Get the keylen correct- as bcrypt uses it to determine encryption level
*---from experimentation it appears that VFPEncryption repeats a short password as required
*---to reach correct key length.
Local liActualKeyLen
liActualKeyLen=Len(m.tcKey)
If Empty(m.tnKeysize)
Else
liKeylen=m.tnKeysize
Endif
If Empty(m.liKeylen) Or m.liActualKeyLen=m.liKeylen
Else
tcKey=Left(Iif(liActualKeyLen>m.liKeylen,m.tcKey,Replicate(m.tcKey,Ceiling(m.liKeylen/m.liActualKeyLen))),m.liKeylen)
Endif
*========================================================================================
* Decrypts data with a symmetric block based algorithm.
*========================================================================================
*Procedure Decrypt_SymmetricBlock (tcAlgorithm, tcData, tcKey, tcIV)
*--------------------------------------------------------------------------------------
* Stop when we encounter a failure
*--------------------------------------------------------------------------------------
Local llOK
llOK = .T.
*--------------------------------------------------------------------------------------
* Get a handle to the requested algorithm provider
*--------------------------------------------------------------------------------------
Local lnAlg
lnAlg = 0
If m.llOK
llOK = BCryptOpenAlgorithmProvider( ;
@lnAlg, Strconv(m.tcAlgorithm+Chr(0),5), Null, 0 ) == 0
Endif
******************************************************************************************************
*---VFPEncryption:
*!* nEncryptionMode ?There are three different modes available for the each of the encryption types listed above. They include: Electronic Code Book (ECB), Cipher Block Chaining (CBC), Cipher Feedback Block (CFB), and Output Feedback Block. The nEncryptionMode parameter does not apply to RC4 encryption (nEncryptionType = 1024).
*!* 0 = ECB *Default
*!* 1 = CBC
*!* 2 = CFB
*!* 3 = OFB
*---chainingmode can be set in alg or key.
If m.llOK
Local lcChainingMode
Do Case
Case m.tcAlgorithm !="AES"
*---only need chaining mode for chained encryption
Case Vartype(m.tnEncryptionmode) !="N"
lcChainingMode="ChainingModeECB"
Case m.tnEncryptionmode=1
lcChainingMode="ChainingModeCBC"
Case m.tnEncryptionmode=2
lcChainingMode="ChainingModeCFB"
*---OFB appears not to be an option in bcrypt
*CASE m.tnEncryptionmode=3
* lcChainingMode="ChainingModeOFB"
Otherwise
lcChainingMode="ChainingModeECB"
Endcase
If Empty(m.lcChainingMode)
Else
*MS Learn: When setting the value for the property BCRYPT_CHAINING_MODE, the pbInput parameter is unbounded by cbInput. The caller needs to ensure a valid null-terminated Unicode string is provided.
llOK = BCryptSetProperty_String(m.lnAlg,Strconv("ChainingMode"+Chr(0),5),Strconv(m.lcChainingMode+Chr(0),5),0,0)=0
*!* Confirm setting
*!* lcVal=SPACE(200)
*!* lndata=0
*!* llOK = BCryptGetProperty2( m.lnalg, ;
*!* Strconv("ChainingMode"+Chr(0),5), @lcVal, ;
*!* 200, @lnData, 0 ) == 0
*!* lcVal=STRCONV(m.lcval,6)
*!* ? LEFT(m.lcVal,ATC(CHR(0),m.lcval))
*!* *ChainingModeECB
Endif
Endif
*--------------------------------------------------------------------------------------
* Turn the key into a symmetric key object that we can pass to the encryption funtion.
*--------------------------------------------------------------------------------------
Local lnKey
lnKey = 0
If m.llOK
llOK = BCryptGenerateSymmetricKey ( ;
m.lnAlg, @lnKey, Null, 0, @tcKey, Len (m.tcKey), 0) == 0
Endif
***************************************************************************************************************
* JR THIS THROWS AN ERROR TRYING TO SET BLOCKSIZE via integer or charttobin- can somebody fix it, or is it a BCRYPT limitation?
***************************************************************************************************************
*---set blocksize...
If m.llOK And m.liBlockLength>0
If Vartype(m.tnBlocksize) ="N" And m.liBlockLength != m.tnBlocksize
liBlockLength=m.tnBlocksize
Endif
*!* *--------------------------------------------------------------------------------------
*!* * Tried this too: Allocate memory for the setting pointer
*!* *--------------------------------------------------------------------------------------
*!* Local lnHashObj
*!* If m.llOK
*!* lnHashObj = HeapAlloc (GetProcessHeap (), 0, 4)
*!* llOK = m.lnHashObj <> 0
*!* EndIf
*!*
*!* IF m.llOK
Local lcBintoc
lcBintoc=BinToC(m.liBlockLength,4)
* SYS(2600,m.lnhashobj,4,m.lcBintoc)
* llOK = BCryptSetProperty_string(lnKey,Strconv("BlockLength"+Chr(0),5),m.lcBintoc,4,0)=0
*!* endif
Endif
*---Block length alwsys 16 for AES, but easy to check at this point if needed...
*!* If m.llOK
*!* local lnData
*!* liBlockLength = 0
*!* lnData = 0
*!* llOK = BCryptGetProperty( m.lnAlg, ;
*!* Strconv("BlockLength"+Chr(0),5), @liBlockLength, ;
*!* 4, @lnData, 0 ) == 0
*!* ENDIF
*--------------------------------------------------------------------------------------
* We ask the algorithm provider for the length of our data.
*--------------------------------------------------------------------------------------
Local lnSize
Local lcIV
If m.llOK
lnSize = 0
If Pcount() > 7
m.lcIV = m.tcIV
llOK = BCryptDecrypt ( ;
m.lnKey, m.tcData, Len(m.tcData), Null, @m.lcIV, Len(m.lcIV), Null, 0, ;
@lnSize, BCRYPT_BLOCK_PADDING) == 0
Else
llOK = BCryptDecrypt ( ;
m.lnKey, m.tcData, Len(m.tcData), Null, Null, 0, Null, 0, ;
@lnSize, BCRYPT_BLOCK_PADDING) == 0
Endif
Endif
*--------------------------------------------------------------------------------------
* Now we can finally decrypt data.
*--------------------------------------------------------------------------------------
Local lcDecrypted
If m.llOK
lcDecrypted = Space (m.lnSize)
If Pcount() > 7
m.lcIV = m.tcIV
llOK = BCryptDecrypt ( ;
m.lnKey, m.tcData, Len(m.tcData), Null, @m.lcIV, Len(m.lcIV), @lcDecrypted, ;
Len(m.lcDecrypted), @lnSize,BCRYPT_BLOCK_NO_PADDING) == 0
Else
llOK = BCryptDecrypt ( ;
m.lnKey, m.tcData, Len(m.tcData), Null, Null, 0, @lcDecrypted, ;
Len(m.lcDecrypted), @lnSize,BCRYPT_BLOCK_NO_PADDING) == 0
Endif
Endif
*--------------------------------------------------------------------------------------
* Properly close any open handle. We return an empty varbinary value if any error
* occurred.
*--------------------------------------------------------------------------------------
If m.lnKey != 0
BCryptDestroyKey (m.lnKey)
Endif
If m.lnAlg != 0
BCryptCloseAlgorithmProvider (m.lnAlg, 0)
Endif
If Not m.llOK
lcDecrypted = ""
Endif
*---padding...
#If _STRIPPADDING
Do Case
Case Empty(m.tnPaddingtype)
lcDecrypted =Rtrim(m.lcDecrypted,Chr(0))
Case m.tnPaddingtype=1
lcDecrypted=Rtrim(m.lcDecrypted)
Case Between(m.tnPaddingtype,2,4)
*---last byte provides the padding length...
Local liPad
liPad=Asc(Right(m.lcDecrypted,1))
If Empty(m.liPad)
liPad=m.liBlockLength
Endif
m.lcDecrypted=Left(m.lcDecrypted,Len(m.lcDecrypted)-m.liPad)
Otherwise
m.lcDecrypted=Rtrim(m.lcDecrypted,Chr(0))
Endcase
#Endif
Return m.lcDecrypted
*--------------------Declares done this way to only use as required
Function BCryptOpenAlgorithmProvider(tnphAlgorithm,tcpszAlgId,tcpszImplementation,tndwFlags)
*---they all start with this, so define all API to create and destroy the cryptography objects
Declare Long BCryptOpenAlgorithmProvider ;
in BCrypt.Dll ;
Long @phAlgorithm, ;
String pszAlgId, ;
String pszImplementation, ;
Long dwFlags
Declare Long BCryptGetProperty In BCrypt.Dll ;
Long hObject, ;
String pszProperty, ;
Long @pbOutput, ;
Long cbOutput, ;
Long @pcbResult, ;
Long dwFlags
*!* Declare Long BCryptSetProperty In BCrypt.Dll ;
*!* long hObject,;
*!* string pszProperty,;
*!* long @pbInput,;
*!* long cbInput,;
*!* long dwFlags
Declare Long BCryptSetProperty In BCrypt.Dll As BCryptSetProperty_String ;
long hObject,;
string pszProperty,;
string @pbInput,;
long cbInput,;
long dwFlags
Declare Long BCryptCloseAlgorithmProvider ;
in BCrypt.Dll ;
Long hAlgorithm, ;
Long dwFlags
Return BCryptOpenAlgorithmProvider(@tnphAlgorithm,m.tcpszAlgId,m.tcpszImplementation,m.tndwFlags)
Function BCryptCreateHash(tnhAlgorithm,tnphHash,tnpbHashObject,tncbHashObject,tcpbSecret,tncbSecret,tndwFlags)
*---hashing: declare other API to create and process hash, as these are always needed
Declare Long BCryptCreateHash In BCrypt.Dll ;
Long hAlgorithm, ;
Long @phHash, ;
Long pbHashObject, ;
Long cbHashObject, ;
String pbSecret, ;
Long cbSecret, ;
Long dwFlags
Declare Long BCryptHashData In BCrypt.Dll ;
Long hHash, ;
String pbInput, ;
Long cbInput, ;
Long dwFlags
Declare Long BCryptFinishHash In BCrypt.Dll ;
Long hHash, ;
String @pbOutput, ;
Long cbOutput, ;
Long dwFlags
Declare Long BCryptDestroyHash In BCrypt.Dll ;
Long hHash
*--------------------------------------------------------------------------------------
* Generic Windows memory management functions for Hash
*--------------------------------------------------------------------------------------
Declare Long HeapAlloc In win32api ;
Long hHeap, ;
Long dwFlags, ;
Long dwBytes
Declare Long GetProcessHeap In win32api
Declare Long HeapFree In win32api ;
Long hHeap, ;
Long dwFlags, ;
Long lpMem
Return BCryptCreateHash(m.tnhAlgorithm,@tnphHash,m.tnpbHashObject,m.tncbHashObject,m.tcpbSecret,m.tncbSecret,m.tndwFlags)
Function BCryptGenerateSymmetricKey(tnhAlgorithm,tnphkey,tcpbKeyObject,tncbKeyObject,tcpbSecret,tncbSecret,tndwFlags)
Declare Long BCryptGenerateSymmetricKey In BCrypt.Dll ;
Long hAlgorithm, ;
Long @phKey, ;
String pbKeyObject, ;
Long cbKeyObject, ;
String pbSecret, ;
Long cbSecret, ;
Long dwFlags
Declare Long BCryptDestroyKey In BCrypt.Dll ;
Long hKey
Return BCryptGenerateSymmetricKey(tnhAlgorithm,@tnphkey,m.tcpbKeyObject,m.tncbKeyObject,@tcpbSecret,m.tncbSecret,m.tndwFlags)
Function BCryptEncrypt(tnhkey,tcpbInput,tncbInput,tcpPaddingInfo,tcpbIV,tncbIV,tcpbOutput,tncbOutput,tnpcbResult,tndwFlags)
Declare Long BCryptEncrypt In BCrypt.Dll ;
Long hKey, ;
String pbInput, ;
Long cbInput, ;
String pPaddingInfo, ;
String @pbIV, ;
Long cbIV, ;
String @pbOutput, ;
Long cbOutput, ;
Long @pcbResult, ;
Long dwFlags
Return BCryptEncrypt(m.tnhkey,m.tcpbInput,m.tncbInput,m.tcpPaddingInfo,@tcpbIV,m.tncbIV,@tcpbOutput,m.tncbOutput,@tnpcbResult,m.tndwFlags)
Function BCryptDecrypt(tnhkey,tcpbInput,tncbInput,tcpPaddingInfo,tcpbIV,tncbIV,tcpbOutput,tncbOutput,tnpcbResult,tndwFlags)
Declare Long BCryptDecrypt In BCrypt.Dll ;
Long hKey, ;
String pbInput, ;
Long cbInput, ;
String pPaddingInfo, ;
String @pbIV, ;
Long cbIV, ;
String @pbOutput, ;
Long cbOutput, ;
Long @pcbResult, ;
Long dwFlags
Return BCryptDecrypt(m.tnhkey,m.tcpbInput,m.tncbInput,m.tcpPaddingInfo,@tcpbIV,m.tncbIV,@tcpbOutput,m.tncbOutput,@tnpcbResult,m.tndwFlags)