Go back to main cluster
Computer science
Programs
Miscellaneous things to download
Programming
My adventures with Delphi
How to get in touch with me
Miscellaneous things to downloadPrograms
Wersja polska  
Passwords encrypting with CryptoAPI 2.0

With IE 3.02, Microsoft added to its standard libraries the encrypting mechanism called CryptoAPI. Owing to complex interface one may, in an easy way, perform things like: passwords encrypting, encrypting data sent over the net, digital data signature etc.
I had the opportunity to use some CryptoAPI functions when a necessity of keeping passwords in the registry occured.
The encrypting (decrypting) algorithm looks like this:
  1. Openning a connection with cryptographic provider
  2. Creation of a hashing object
  3. Hashing our secret text by means of the object above
  4. Cryptographic key creation by means of our hashed object
  5. Our password or other message encrypting, decrypting
Openning a connection with cryptographic provider
CryptoAPI 2.0 version contains several standard providers (CSP - Cryptographic Service Providers). The most standard among them is The Microsoft Base Cryptographic Provider and this is the one we will use. Current providers list can be found in the registry with the key: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Defaults\Provider. Every provider belongs to one type. There is also a possiblity to check in the registry to what type our provider belongs. All the information can of course be obtained by means of certain CryptoAPI functions that won't be mentioned at all in here :). Anyway, our provider belongs to PROV_RSA_FULL type.
After that short 'theoretical' introduction it is time for practice. We need now to get our provider's handle. To do so we use CryptAcquireContext function:
var
  hProv    : HCRYPTPROV;
begin	
  if not CryptAcquireContext(@hProv, nil, nil, PROV_RSA_FULL, 0) then Exit;
It may happen that CryptAcquireContext function will fail and NTE_KEYSET_NOT_DEF error will be returned. Then one can call this function again with CRYPT_NEWKEYSET flag.
var
  hProv    : HCRYPTPROV;
begin  
  if not CryptAcquireContext(@hProv, nil, nil, PROV_RSA_FULL, 0) then
     begin
       if GetLastError <> NTE_KEYSET_NOT_DEF then Exit;
       if not CryptAcquireContext(@hProv, nil, nil, PROV_RSA_FULL, CRYPT_NEWKEYSET) 
          then Exit;
     end;
  


Creation of a hashing object
Our provider consists of the following hashing algorithms: MD2, MD5, SHA and MAC. I only used MD5, but there is probably no obstacle to use others. To create a hashing object one needs to use CryptCreateHash function. The source code could look like this:
var
  hHash    : HCRYPTHASH;
begin	
  {...}
  if not CryptCreateHash(hProv, CALG_MD5, 0, 0, @hHash) then Exit;
The handle - hHash - points at our hashing object, which uses MD5 algorithm.

Hashing our secret text by means of the object above
Our key will be secret and there will be only one such key, always the same, and it won't be stored anywhere. Because of this the application must have the possibility to evaluate the key any time there is a need to encrypt or decrypt some information. That's why we created the hashing object, so that later on the key can be genereted from it. However we need to hash first. In general it looks like this, we have a secret password (secret text), we hash it and create the key from it. The algorithm when being given the same input generates always the same key (output). Note that changing a single input bit changes the output key completely. Well, let's do some hashing. We will use CryptHashData function. And here is some source code:
var
  dwLength : DWORD;
  Key      : String;
begin
  {...}
  dwLength := Length(Key);
  if not CryptHashData(hHash, PByte(Key), dwLength, 0) then Exit;
This way we have a hashed bit sequence, which will be used to create the key.

Cryptographic key creation by means of our hashed object
Now there is nothing more than to create the key. The algorithm must be specified now. We have the following at disposal: RC2 and RC4. It's not much, but these are all the block ciphers our provider provides us with. Based on the hashed password key creation function is called CryptDeriveKey . The code should look like this:
var
  hKey : HCRYPTKEY;
begin	
  {...}
  if not CryptDeriveKey(hProv, CALG_RC2, hHash, 0, @hKey) then Exit;
In hKey there is the handle to RC2 key.

Our password or other message encrypting, decrypting
It is high time we took the last step, the most complicated one, which doesn't mean difficult :). Using CryptEncrypt / CryptDecrypt function we need to encrypt/decrypt a password or some other message. Encrypting source code fragment could look this:
var
  dwLength : DWORD;
  pbKeyBlob: PByte;
  dwBlobLen: Integer;
  s        : String;
  Password : String;
begin
  {...}
  dwBlobLen := Length(Password);
  CryptEncrypt(hKey, 0, True, 0, nil, @dwBlobLen, 0);

  dwLength  := Length(Password);
  GetMem(pbKeyBlob, dwBlobLen);
  try
    Move(Password[1], pbKeyBlob^, dwLength);
    if not CryptEncrypt(hKey, 0, True, 0, pbKeyBlob, @dwLength, dwBlobLen) then Exit;
    SetLength(s, dwBlobLen);
    Move(pbKeyBlob^, s[1], dwBlobLen);
  finally
    FreeMem(pbKeyBlob);
  end;
I don't present decrypting source code because it is even simpler. At the end one must of course free all the handles. The following are the functions to do so: CryptDestroyHash, CryptDestroyKey and CryptReleaseContext.
If anyone would like to see how it looks in my sources then I share here two modules. One is the wincrypt.h translation to Pascal, indespensible to do anything described above, the other contains to functions to encrypt and decrypt passwords.

That's all. Have a nice encrypting.

Michał B±kowski




Warning: gzopen(): cannot open a zlib stream for reading and writing at the same time! in /home/michalek/html/english/common/counter.php3 on line 11

Warning: gzwrite(): supplied argument is not a valid stream resource in /home/michalek/html/english/common/counter.php3 on line 31

Warning: gzclose(): supplied argument is not a valid stream resource in /home/michalek/html/english/common/counter.php3 on line 32
This is the no. 47161 visit since March 14, 2001

© Copyright 1999-2005, Michał B±kowski