Use Microsoft Crypto APITag(s): WinAPI/Registry
With almost all Windows installation, the Microsoft Crypto API is available.
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.
J.C. de Souza Ribeiro wrote :
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
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!))
Another fix for PB10.5 from Thomas Mathys.
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 ...
A complete Powerbuilder object is available here : http://www.topwizprogramming.com/freecode_crypto.html
If you want to generate SHA1 hash then your DBMS may help you.
For Oracle 10g, it's something like :
SELECT DBMS_CRYPTO.HASH (utl_raw.cast_to_raw('Tester12'), :sh1) FROM dual;