CryptoAPI 1.0 is provided through Microsoft Windows NT 4.0 and Microsoft Internet Explorer 3.0 and later. CryptoAPI 1.0 will also ship with the Windows 95 update.
Microsoft provides a separate COM object to make it easy to exploit this API from VBScript or Powerbuilder. But you need to installed the COM object before using it. This How-to will show you how to call directly the Crypto DLL.
The n_cst_crypto object can encrypt/decrypt a string based on a given key. This can be used to encrypt user/password entries in INI file for example.
Based on this Visual Basic example, the PB7 PBL containing the n_cst_crypto object can be download from here.
Many thanks to Martyn Bannister for VB to PB development.
To encrypt a string
n_cst_crypto lnv_crypt
string ls_encrypted
lnv_crypt = CREATE n_cst_crypto
ls_encrypted = lnv_crypt.EncryptData("my sensitive data" , "SecretKey")
DESTROY lnv_crypt
To decrypt a string
n_cst_crypto lnv_crypt string ls_decrypted lnv_crypt = CREATE n_cst_crypto ls_decrypted = lnv_crypt.DecryptData(is_crypted , "SecretKey") DESTROY lnv_crypt
Check this How-to for a powerscript-only.
I tried to use your "PB7 PBL containing the n_cst_crypto object" to encrypt a string of 59 numeric digits, using the MD5 algorithm, but everytime I run it, using different values, I get strings of different lengths and I was expecting always a string of 32 bytes.
The original VB algorithm is making a great deal to make sure that there is no tab/cr/lf characters in the result string and do encryption (with a counter) again if there are present. I suspect this is why the length is varying.
/*
External Function Definitions
FUNCTION Boolean CryptAcquireContextA (ref ulong hProv, &
ref string pszContainer, &
ref string pszProvider, ulong dwProvType, &
ulong dwFlags) &
LIBRARY "advapi32.dll"
FUNCTION Boolean CryptReleaseContext (ulong hProv, ulong dwFlags) &
LIBRARY "advapi32.dll"
FUNCTION Boolean CryptCreateHash (ulong hProv, uint Algid, ulong hKey, &
ulong dwFlags, ref ulong phHash) &
LIBRARY "advapi32.dll"
FUNCTION Boolean CryptHashData (ulong hHash, ref string pbData, &
ulong dwDataLen, ulong dwFlags) &
LIBRARY "advapi32.dll"
FUNCTION Boolean CryptDestroyHash (ulong hHash) &
LIBRARY "advapi32.dll"
FUNCTION Boolean CryptGetHashParam (ulong hHash, ulong dwParam, &
ref blob pbData, &
ref ulong pdwDataLen, ulong dwFlags) &
LIBRARY "advapi32.dll"
FUNCTION Ulong GetLastError () Library "kernel32.dll"
*/
// Constants
CONSTANT ULONG PROV_RSA_FULL = 1
CONSTANT ULONG CRYPT_VERIFYCONTEXT = 4026531840 // 0xF0000000
CONSTANT ULONG CALG_MD5 = 32771 // 4<<13 | 0 | 3
CONSTANT ULONG HP_HASHVAL = 2 // 0x0002
public function string of_md5 (string as_text);
// Calculate the MD5 message digest hash of a string
// Using the Windows Crypto API
ulong MD5LEN = 16
ulong hProv // provider handle
ulong hHash // hash object handle
ulong err_number
String s_result, s_null
Integer i, l, r, b
Blob{16} bl_hash
Blob{1} bl_byte
SetNull (s_null)
ulong cbHash = 0
CHAR HexDigits[0 TO 15] = &
{'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}
//Get handle to the crypto provider
IF NOT CryptAcquireContextA&
(hProv, s_null, s_null, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) &
THEN
err_number = GetLastError()
return 'acquire context failed ' + String (err_number)
END IF
// Create the hash object
IF NOT CryptCreateHash(hProv, CALG_MD5, 0, 0, hHash) THEN
err_number = GetLastError()
CryptReleaseContext(hProv, 0)
return 'create hash failed ' + String (err_number)
END IF
// Add the input to the hash
IF NOT CryptHashData(hHash, as_text, Len(as_text), 0) THEN
err_number = GetLastError()
CryptDestroyHash(hHash)
CryptReleaseContext(hProv, 0)
return 'hashdata failed ' + String (err_number)
END IF
// Get the hash value and convert it to readable characters
cbHash = MD5LEN
IF (CryptGetHashParam(hHash, HP_HASHVAL, bl_hash, cbHash, 0)) THEN
FOR i = 1 TO 16
bl_byte = BlobMid (bl_hash, i, 1)
b = Asc (String(bl_byte))
r = Mod (b, 16) // right 4 bits
l = b / 16 // left 4 bits
s_result += HexDigits [l] + HexDigits [r]
NEXT
ELSE
err_number = GetLastError()
return 'gethashparam failed ' + String (err_number)
END IF
// clean up and return
CryptDestroyHash(hHash)
CryptReleaseContext(hProv, 0)
return s_result
NOTE: Since PB10 is Unicode, you need to specify to the String() function to use ANSI.
[PB7/8/9]
b = Asc (String(bl_byte))
[PB10]
b = AscA(String(bl_byte,EncodingANSI!))
I took your code to encode password by MD5 in a powerbuilder 10.5 application, but I saw the result was different than what I obtained with others tools (Oracle, Javascript example,...), if I encoded more than one character. I searched a lot, and finally found a solution: you must pass your text as a blob, and not as a string, to the CryptHashData function. You got to change the prototype and your powerscript must be changed like this:
... // Add the input to the hash Blob bl_text bl_text = Blob(as_text, EncodingANSI!) IF NOT CryptHashData(hHash, bl_text, Len(bl_text), 0) THEN ...
For Oracle 10g, it's something like :
SELECT DBMS_CRYPTO.HASH (utl_raw.cast_to_raw('Tester12'), :sh1) FROM dual;
Written and compiled by Réal Gagnon ©1998-2010
[ home ]