This article appeared in the March-April 2002 issue of CoDe Magazine

 

Add security to your data with the Crypto API

By Alex Feldstein

 

We all know the importance of securing your data. But how do you add industrial strength security to your program? The answer is simple: use the Windows Crypto API.

 

 

Most of us that write programs that deal with data have written, or “borrowed” simple encryption routines that are all based in some scheme involving XOR, bit shifting or some kind of data transposition. This may be fine to stop the casual observer but with most data being exposed to the Internet nowadays and the increasing threat of hackers or industrial spies getting to your data, it is very important to protect your customer’s business. It could be that you only want to encrypt passwords kept in a users table, or employee’s salaries or credit card numbers; they are all excellent candidates to apply good cryptography.

 

First, I’d like to cover the basics of what data security and cryptography are. Don’t worry; you do not need a PhD in math to follow as we will not cover all the difficult algorithms. Next I’ll show you some sample code to create a component that accesses the functionality Microsoft provided for us in the Windows Crypto API. If you look at its user manual, you will feel intimidated as it is a very complex subject and all the provided examples are in VC++. You do not have to know any C++ as we will use a “wrapper” class in a COM object that simplifies all this work for us.

 

What is Cryptography?

 

A message or string is called plaintext (sometimes called cleartext). The process of converting that message in such a way to hide its contents is encryption. An encrypted message is ciphertext. The process of turning the ciphertext back into plaintext is called decryption. The art and science of keeping messages secure is known as cryptography. The people that practice this art are cryptographers. Cryptanalysis is the art and science of breaking ciphertext. The practitioners of cryptanalysis are called cryptanalysts. Lastly the branch of mathematics encompassing both cryptography and cryptanalysis is cryptology.

 

A few concepts

 

Before implementing cryptographic functions, it is a good idea to define what we want to accomplish. Don’t necessarily assume that you need to have 1024-byte keys as it might seriously degrade your performance. There is a tradeoff between security and usability. In other words, the security requirements may not be the same for a website in a company’s intranet than for one exposed to the public internet.

 

v     Privacy/confidentiality: Do we want everybody to see our data?  Do we want the government to be able to freely check on us? Do we allow competitors to see our secrets?

v     Integrity: sometimes confused with Authentication. It is not concerned with the origin of the data but with its validity. Has this data been tampered with?

v     Availability: the property of being accessible and usable upon demand by an authorized entity.

v     Access control: who is allowed to see our data? Who is allowed to change it?

We want to insure that authorized people are able to do what they are authorized to do and everyone else is not.

v     Authentication: who signed this check? Who wrote this message?

v     Identification: Who are you? Can you prove it?

 

I am not going to deal here with the types of attacks that can be unleashed on a computer system. I’ll leave that for a future article as there are varied and many. We will concern ourselves here with the concepts of Identification, Authentication and Access Control.

 

Types of Cryptography

 

For our purposes we have a few basic types of Cryptography:

 

v     Symmetric Cryptography

v     Hash Functions

v     Public-Key Cryptography

v     Digital Signatures

 

Symmetric Cryptography (a.k.a. Secret-key Cryptography): The same key is used for both encryption and decryption. The most common secret-key system used today is the Data Encryption Standard (DES) and its variants.

 

Figure 1

 

Hash Functions. These are typically encrypted in such a way that they cannot be easily decrypted. They are used to encrypt a set of passwords in a database, for example, and when a user wants to be authenticated, a hash is done on his entered plaintext password and the two hashes are then compared. The hash is commonly used to create a key from a plaintext password (or passphrase). That way the client program could only send a hash and not the plaintext password through the wire.

 

In cases where a thin-client is used, such as a browser, the passwords are not encrypted at the client by the application, but an encrypted communication takes place by using SSL (HTTPS protocol). This is the way it is commonly done nowadays for electronic purchases through the Internet while entering such information as your credit card number. A Certification Authority, such as Verisign, issues a Certificate to the server that talks to the client component (browser) to do the encryption and decryption transparently to the user.

 

Of course, there are weak and strong hash functions. Many of us have heard of, or used a checksum or a Cyclical Redundancy Check (CRC) to check for data integrity of a file. But these can be reverse-engineered and a file can be modified to generate the same checksum. Time ago we may have even used file size as a simple way to compare two files to see if they are equal or even the same. That may be an extreme example of a weak checksum! Using cryptography, an algorithm is used that creates an almost unbreakable key that can be used to verify the validity and integrity of a file.

 

A good example of this is how network admins are able to change users'
passwords but NOT view them. In a typical scenario, when a user forgets his
password, the admin sets it to something temporary and then, once the user
regains access to the system can change it to a private password again.
This increases trust on the part of users.

 

Fast Facts

Using cryptography, an algorithm is used that creates an almost unbreakable key that can be used to verify the validity and integrity of a file.

 

Public-key Cryptography (a.k.a. Asymmetric Encryption, Public-Key Infrastructure or PKI) uses a different key to encrypt and decrypt a message. A public key is published for all to see, generally in specialized servers available through the Internet. A private key must be used along with the public key to decrypt these messages. Encryption is performed with the public key while decryption is done with the private key.

 

It allows you to send secret messages to people you haven’t met and with whom you have not agreed on a secret key. It allows two people to engage in a public visible data exchange and at the end of that exchange read a shared secret that someone listening in on the conversation can’t learn. As Bruce Schneier puts it in his book “Secrets & Lies” (see Bibliography at the end of the article), “it allows you and a friend to shout numbers at each other across a crowded coffeehouse filled with mathematicians so that when you are done, both you and your friend know the same random number, and everyone else in the coffeehouse is completely clueless”.

 

The most well know systems for Public-Key Cryptography are Diffie-Hellman (named for its inventors, Whitfield Diffie and Martin Hellman -1976) and the systems that implement it such as RSA, PGP and Entrust.

 

Figure 2

 

 

 

Digital Signatures. A Digital Signature, unlike what the layperson might think, is not a digitized copy of your handwritten signature but an encryption scheme. They provide a level of authentication for messages. In many cases, authentication is more important than secrecy. Like Public-Key Encryption, Digital Signatures use a pair of keys, a public key and a private key. You cannot derive one from the other. Programs like Pretty Good Privacy (PGP) that are widely available to the public can do digital signing of documents besides allowing you to maintain secrecy through the use of PKI. The most commonly used commercial program is RSA and the US Government uses a Digital Signature Algorithm (DSA) used in the US Digital Signature Standard (DSS).

 

 

Where can we incorporate cryptography in our software development process?

 

We could use a hash to encrypt passwords in a database. Most of the programs we create keep configuration information in a file somewhere. It could be a simple text file, like an INI or an XML file. It could be kept in the Windows Registry, or in a database table somewhere. There are advantages and disadvantages to each of these methods. We could keep our text file encrypted at all times and decrypt on the fly as needed by our program, insuring access only through our GUI front end provided. Suppose we are interested in keeping this file in plaintext so it can be viewed. But suppose that we do not want it to be modified from the outside of our GUI (same issue applies to the Registry entry).

 

To accomplish this, we could have the program calculate a hash value when writing this information to disk. That is called our baseline. Then, whenever an authorized user wants to change the configuration, the program has to read it from disk. It then calculates a new hash of the contents and compares with the baseline to detect tampering. The problem here is where do we keep the baseline? This is not an easy problem. Generally we would save it in a “secure” place; for example in another folder, deep in the bowels of the restricted admin area of the system. Or on another secure computer that this program has access to. Is this more secure? Yes. Is it really secure? No.

 

Your levels of security depend on your needs. Difficulty, functionality, efficiency and cost have to be considered. But there is only so much we, as programmers, can do. There are many weaknesses to consider. Management has to understand that there are several levels of responsibility and many of these fall outside of our area as software developers.

 

Most of the time when we as consultants or advisors tell management or a client that our program is secure, the image they get may not be the same as we intended. Many security weaknesses may exist in their organization.

 

Issues to consider are:

 

v     Company security policies.

v     Security requirements (where they voiced openly? where they considered and written along with the functional requirements document?)

v     Network security and access control

v     User carelessness or plain stupidity

 

We can write very secure applications, using strong encryption algorithms but a weak password or a user going to lunch and leaving his terminal logged-in can easily compromise them.

 

 

How do we use cryptography in the applications we write?

 

All this sounds difficult. And if you want to understand the algorithms and mathematical formulas involved, it is, unless you are a skilled mathematician. Fortunately, Microsoft has provided us with the Windows CryptoAPI. This is a set of DLLs that do the work for us. You do not have to understand the algorithms, just the underlying concepts and the interface to make use of it. The Win CryptoAPI is an integral part of Windows nowadays. Before, it was also available as the CryptoAPI SDK for Win NT 4 and even for Windows 95 OSR2. It provides an abstraction layer that isolates you from the algorithm used to protect the data. An application refers to context and keys and makes calls to special functions that drive the encryption servers installed on the machine. These servers are called Cryptographic Service Providers (CSP) and are the modules that do the dirty work of encoding and decoding data.

 

Figure 3

 

 

Figure 3 shows the three-tiered CryptoAPI programming model. An application makes calls to simplified cryptographic functions that delegate to base services. Neither the application nor the simplified functions should directly access any available CSPs.

 

Before adding cryptography to your applications, you must become familiar with terms such as context, session keys, exchange keys, and signature keys. Context is a session established between the CryptoAPI an the client application. So, to establish a context you must pass the name of a key container and the name of a provider to connect to. It returns a handle that you use for all subsequent calls to the API. To encrypt or decrypt data you need a session key. They are objects that have a very limited life. They never leave the CSP for reasons of security and privacy. You create, use and destroy them whenever you need to encrypt/decrypt. If you need to bring a session key out of the CSP for export purposes, you need to create a key blob. These are chunks of binary data that represent an encrypted version of your key.

 

The following is a sample of calls using VC++:

 

BOOL WINAPI CryptAcquireCertificatePrivateKey(

  PCCERT_CONTEXT pCert,

  DWORD dwFlags,

  void *pvReserved,

  HCRYPTPROV *phCryptProv,

  DWORD *pdwKeySpec,

  BOOL *pfCallerFreeProv

);

 

The handle returned as HCRYPTPROV is used throughout your communication with the CSP.

 

The documentation for the CryptoAPI is in MSDN (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/portalapi_3351.asp?frame=true). Most, if not all, the examples are in C. So if you are not well versed in the C language you may have some trouble. Fortunately, there are other ways to get at it, as the call declarations are published and can be used from other languages such as VB or Visual FoxPro.

 

Fast Facts

The newest release of Visual FoxPro 7.0 comes with an object-oriented class library that acts as a wrapper to the Windows CryptoAPI

 

The newest release of Visual FoxPro 7.0 comes with an object-oriented class library that acts as a wrapper to the Windows CryptoAPI. It makes the calls easy to use from any language that can consume COM objects as VFP can produce COM (and COM+) compliant objects.

 

I will illustrate a simple example of this.

 

Open VFP 7.0 and create a project with

CREATE PROJECT DoCryptoAPI

 

Add the VFP provided crypto API library found in

HOME(1) + “FFC\_crypt.vcx”

As shown in Figure 4.

 

Figure 4

 

 

Then add the code in Listing 1 to the project

Listing 1: Main program

*============================================

* Program: DOCRYPTO.PRG

* Purpose: simple wrapper around Visual

           FoxPro 7.0's FFC\_crypto.vcx

* Author:  Alex Feldstein

* Copyright:  Public Domain

* Last revision:  11/2/2001

* Parameters: depends on method called

* (generally string_to_encrypt, passphrase)

* Returns:  encrypted/decrypted string or an

*            error message as character

*

* Notes:   compiled as multi-threaded DLL to

*           be called from any COM compliant

*           client

*          passphrase is case-sensitive

* Usage:   From VFP:

*  x = CREATEOBJECT("docryptoapi.docrypto")

* cCipher = x.EncryptStream("This is easy", ;

*  "look Ma, no hands!")

*============================================

 

 

DEFINE CLASS docrypto AS Session OLEPUBLIC

 

PROTECTED oCrypto

oCrypto = ""

MinimumPasswordLength = 5

 

 

*********************************************

PROCEDURE Init

 

this.oCrypto = ;

  NEWOBJECT("_cryptapi", ;

  "c:\vfp7\ffc\_crypt.vcx")

 

IF VARTYPE(this.oCrypto) != "O"

  RETURN .f.

ENDIF

 

ENDPROC

 

 

 

*********************************************

PROCEDURE EncryptStream(tcString as ;

  Character, tcPassword as Character) as ;

  Character

 

IF PCOUNT() < 2

RETURN "Usage: EncryptStream(String,  ;

  Passphrase)"

ENDIF

 

LOCAL lcEncryptedStream

 

IF EMPTY(tcString)

  RETURN "Nothing to do!"

ENDIF

 

IF LEN(tcPassWord) < nMinimumPasswordLength

  RETURN "Passphrase must >= " + ;

  TRANSFORM(nMinimumPasswordLength) + ;

    "chars!"

ENDIF

 

IF ;

This.oCrypto.EncryptSessionStreamString( ;

  tcString, tcPassWord, @lcEncryptedStream)

  RETURN lcEncryptedStream

ELSE

  RETURN .F.

ENDIF

ENDPROC

 

 

 

 

*********************************************

PROCEDURE DecryptStream(tcEncryptedString ;

  as Character, ;

  tcPassWord as Character) as Character

IF PCOUNT() < 2

  RETURN "Usage: " + ;

    "DecryptStream(EncryptedString, " + ;

    "Passphrase)"

ENDIF

 

LOCAL lcDecryptedString

IF EMPTY(tcEncryptedString)

  RETURN "Nothing to do!"

ENDIF

 

IF LEN(tcPassWord) < nMinimumPasswordLength

  RETURN "Passphrase must >= " + ;

    TRANSFORM(nMinimumPasswordLength) + ;

    " chars!"

ENDIF

 

IF ;

  This.oCrypto.DecryptSessionStreamString( ;

  tcEncryptedString, tcPassWord, ;

  @lcDecryptedString)

    RETURN lcDecryptedString

ELSE

    RETURN .F.

ENDIF

ENDPROC

 

 

 

*********************************************

PROCEDURE Destroy

  this.oCrypto = .null.

ENDPROC

 

 

 

*********************************************

PROCEDURE Error(nError, cMethod, nLine)

RETURN MESSAGE() + " - (" + ;

  TRANSFORM(ERROR()) + ")"

ENDPROC

 

 

 

*********************************************

PROCEDURE Usage() as Character

* this will return a string with usage

* directions

RETURN [x = ;

  CREATEOBJECT("docryptoapi.docrypto")] + ;

  CHR(13) + CHR(10) + ;

  [cCipher = x.EncryptStream("This is easy",;

  "look Ma, no hands!")]

 

ENDPROC

 

ENDDEFINE

 

The parameters @lcEncryptedStream and @lcDecryptedString are passed by reference as indicated by the preceding @ sign.

 

The project will now look as Figure 5:

 

Figure 5

 

Then build the project as a Multi-threaded COM Server (dll)

 

Figure 6

 

This will compile and register the newly created DLL into your computer.

 

Now we can test this DLL with a simple table encryption routine as in listing 2:

 

Listing 2: Sample.prg

SET TALK OFF

CLOSE TABLES all

CLOSE DATABASES

LOCAL x, s, e, lcPassword

 

lcPassword = INPUTBOX("Enter passphrase "  +;

  "(>= 5 chars)", "Password")

 

IF LEN(lcPassword) < 5

  RETURN "Passphrase must be minimum 5 " + ;

    "characters!"

ENDIF

 

x = CREATEOBJECT("docryptoapi.docrypto")

IF VARTYPE(x) != "O"

  RETURN "Could not get to docryptoapi.dll"

ENDIF

 

USE HOME(2) + "\data\customer" EXCLUSIVE

 

s = SECONDS()

 

SCAN

  replace company WITH ;

    x.EncryptStream(ALLTRIM(company), ;

      lcPassword)

ENDSCAN

 

e = SECONDS()

 

CLEAR

IF RECCOUNT() > 0

  ? "Encrypt: " + TRANSFORM(RECCOUNT()) +;

    " records in " + ;

    ALLTRIM(TRANSFORM(e-s,"999,999")) +;

    " seconds (" + ;

    ALLTRIM(TRANSFORM(RECCOUNT() / ;

    (e-s),"999,999.99")) + ;

    " recs/sec)"

ENDIF

LOCATE

BROWSE

 

s = SECONDS()

 

SCAN

  replace company WITH ;

    x.DecryptStream(ALLTRIM(company), ;

      lcPassword)

ENDSCAN

 

e = SECONDS()

IF RECCOUNT() > 0

  ? "Decrypt: " + TRANSFORM(RECCOUNT()) +;

    " records in " + ;

    ALLTRIM(TRANSFORM(e-s,"999,999")) + ;

    " seconds (" + ;

    ALLTRIM(TRANSFORM(RECCOUNT() / ;

    (e-s),"999,999.99")) + ;

    " recs/sec)"

ENDIF

 

RELEASE x

 

LOCATE

BROWSE NOWAIT

LOCATE

SET TALK ON

RETURN .T.

 

This simple program will open the customer table in the sample data and proce3ed to ask you for a password or passphrase. It will traverse the table encrypting the company name in each record, by calling the encryption routine from our DLL. This encapsulates (and hides) the complexities of dealing with API declarations and other setup that are taken care of by the dll and the class library supplied.

 

After a quick check of the results, using a simple BROWSE command (LOCATE navigates to the top of the file) it will reverse the process, asking you for the password again, and decrypting the file.

 

Now, let’s try the sample dll from a different platform. We’ll use MS Excel and a little VBA to do the same we did in this sample.

 

While still in Visual FoxPro, and with the pointer at the top of the file, type the following in the Command Box:

 

COPY TO test.xls TYPE XLS NEXT 10

 

This will export the first 10 records to an XLS file.

 

Open MS Excel (any version from Excel 97 and up will do) and load the test.xls file created.

 

Add two simple buttons to the spreadsheet to trigger our sample code and change their captions as in Figure 7:

 

Figure 7

 

Double-click in the Encrypt button and the VBA Code Editor will open. Type the code in Listings 3 and 4 that will take care of Encryption and Decryption.

 

Listing 3:

Private Sub Decrypt_Click()

 

' get a reference to the encryption library

Dim cPassword As String

cPassword = _

  Application.InputBox( _

  Prompt:="Please enter Passphrase", _

  Title:="Password")

 

If Len(Trim(cPassword)) < 5 Then

  MsgBox ("Password must be >= 5 chars!")

  End

End If

 

Dim x As Object

Set x = CreateObject("docryptoapi.docrypto")

 

' select column

Dim oRow As Range

ActiveSheet.Range("B1").Select

For Each oRow In Range(Selection, Selection.End(xlDown))

  oRow.Value = _

  x.DecryptStream(Trim(oRow.Value), _

    cPassword)

Next

 

x = Null

 

End Sub

 

Listing 4:

Private Sub Encrypt_Click()

 

' get a reference to the encryption library

Dim cPassword As String

cPassword = _

  Application.InputBox( _

  Prompt:="Please enter Passphrase", _

  Title:="Password")

 

If Len(Trim(cPassword)) < 5 Then

  MsgBox ("Password must be >= 5 chars!")

  End

End If

 

Dim x As Object

Set x = CreateObject("docryptoapi.docrypto")

 

' select column

Dim oRow As Range

ActiveSheet.Range("B1").Select

For Each oRow In Range(Selection, Selection.End(xlDown))

  oRow.Value = _

  x.EncryptStream(Trim(oRow.Value), _

    cPassword)

Next

 

x = Null

 

End Sub

 

As before, the VBA code asks for a password or passphrase and then calls our dll to do the dirty work for every row.

 

With a little more work other functions could be added to the dll, such as digital signing or the algorithms used could be changed to others like DES, Triple-DES or RSA.

 

This should whet your appetite and show you how simple it can be and how little knowledge is needed to use world-class encryption in your programs.

 

Note: to unregister the sample component we created, do the following:

cd\windows\system
regsvr32 /u c:\crypto\docryptoapi.dll

(Assuming that the dll is in c:\crypto)

 

 

 

 

References:

 

Applied Cryptography by B.Schneier, JohnWiley&Sons, Inc.,1996.

Secrets & Lies by B.Schneier, JohnWiley&Sons, Inc., 2000.

RSA Laboratories – FAQ document – May 2000

FIPS Pub 140-2 Security Requirements for Cryptographic Modules, 2001 May 25

 

 

Click here to download the source code for this article.