Invoking the CryptoAPI


The CryptoAPI is a Windows CE API for performing common cryptographic functions such as computing hashes and encrypting or decrypting data. The .NET Compact Framework has no support for cryptographic functions that are accessible to the outside user . Thus, .NET Compact Framework developers must invoke the native CryptoAPI from their managed applications in order to perform cryptographic functions.

The CryptoAPI is a brittle API that will cause confusion for developers who don't understand some basic principles behind its use. The following sections review those basics before the rest of the chapter jumps into using the CryptoAPI.

Using Handles to Interact with CryptoAPI

Like many other functional areas in the Windows operating system, the CryptoAPI is driven by the concept of a handle. For example, encrypting data requires a handle to the cryptographic provider and a handle to the specific encryption key to be used. Programming against the CryptoAPI is really just the process of acquiring the correct handles from some functions and passing them in as arguments to other functions to achieve the desired results. However, the rules for using the handles correctly are very specific, and function calls fail if the handles are used incorrectly.

Understanding the CryptoAPI Context

The CryptoAPI architecture provides a standard interface for calling into cryptography functions, regardless of what the underlying algorithms are. Groups of algorithms are bundled together into packages called cryptographic service providers, or CSPs. The CSP used in the ManagedCryptoAPI wrapper class is the PROV_RSA_FULL provider. PROV_RSA_FULL provides encryption and hashing algorithms that are patented by the RSA and provided by Microsoft under license. It is a good general-purpose provider, and it is ubiquitous on Windows CE devices.

Other commonly used CSPs are shown in Table 14.1. Additionally, developers can write their own CSPs, and then anyone can access their algorithms through CryptoAPI.

Not all of the CSPs shown in Table 14.1 are included by default with Windows CE and Pocket PC devices. It is because the PROV_RSA_FULL provider is so common that we use it exclusively in the ManagedCryptoAPI wrapper.

Table 14.1. Cryptographic Service Providers Commonly Used with CryptoAPI

PROV_RSA_FULL

PROV_RSA_SIG

PROV_DSS

PROV_DSS_DH

PROV_SSL

PROV_EC_ECDSA_SIG

PROV_EC_ECNRA_SIG

PROV_EC_ECDSA_FULL

PROV_SPYRUS_LYNKS

PROV_FORTEZZA

PROV_MSEXCHANGE

PROV_RSA_CHANNEL

To perform any cryptographic function with the CryptoAPI, you must first acquire a context by calling CryptAcquireContext . Acquiring a context serves two purposes. First, it communicates to the CryptoAPI which CSP you want to use. Second, it tells the CryptoAPI which key container to use. A key container is a location where encryption keys are internally stored by CryptoAPI. As a developer, you usually interact with a key through its handle, and you let the CryptoAPI store the bytes of the key internally.

The DllImport definition for CryptAcquireContext in ManagedCryptoAPI looks like this:

 
 C# [DllImport("coredll.dll")] private static extern bool CryptAcquireContext(ref IntPtr phProv,          string pszContainer, string pszProvider, Int32 dwProvType,          uint dwFlags); VB Declare Function CryptAcquireContext Lib "coredll.dll" (ByRef phProv As IntPtr,          ByVal pszContainer As String, ByVal pszProvider As String, ByVal          dwProvType As UInt32, ByVal dwFlags As UInt32) As Boolean 

When acquiring a context, you may choose to use the default key container, or you may pass in a string name for a key container. It is strongly recommended that you pass in a name for the key container because other software on your device could already be using the default key container and you could inadvertently clobber the keys used by the other software. Specifically, the Pocket PC driver software for several brands of wireless network cards uses the default key container. If you also use the default container, you risk clobbering the keys that the driver software uses to encrypt wireless traffic, which would cause your wireless card to stop working suddenly.

ManagedCryptoAPI has two methods for acquiring a context. AcquireDefaultContext returns an IntPtr , which holds the handle to the default key container for the PROV _ RSA _ FULL provider. AcquireNamedContext returns an IntPtr , which holds the handle to a named key container that you pass in as a string. Programs retain the returned handle and pass it in to other methods that are discussed later in this chapter. The code for AcquireDefaultContext is shown in Listing 14.1.

Listing 14.1 AcquireDefaultContext
 C# public IntPtr AcquireDefaultContext() {    IntPtr hProvider = IntPtr.Zero;    if (!CryptAcquireContext(ref hProvider, null, "Microsoft Base Cryptographic             Provider v1.0", PROV_RSA_FULL, 0))    {       // We might have to create a new keyset...       if (!CryptAcquireContext(ref hProvider, null, "Microsoft Base               Cryptographic Provider v1.0", PROV_RSA_FULL, CRYPT_NEWKEYSET))       {          // Big trouble, could not create a new          // keyset and could not acquire default keyset          throw new Exception("ManagedCryptoAPI cannot access default                   keyset or create new default keyset!");       }    }    return hProvider; } VB    Public Function AcquireDefaultContext() As IntPtr       Dim hProvider As IntPtr = IntPtr.Zero       If (CryptAcquireContext(hProvider, Nothing, "Microsoft Base Cryptographic                Provider v1.0", PROV_RSA_FULL, Convert.ToUInt32(0)) = False) Then       Dim l_Failure As String = TranslateErrorCode(Convert.ToInt64               (GetLastError()))       ' We might have to create a new keyset...       If (CryptAcquireContext(hProvider, Nothing, "Microsoft Base Cryptographic                Provider v1.0", PROV_RSA_FULL, CRYPT_NEWKEYSET) = False) Then          ' Big trouble, could not create a new keyset and could not acquire          ' default keyset          Throw New Exception("ManagedCryptoAPI cannot access default keyset or                   create new default keyset!" + TranslateErrorCode                   (Convert.ToInt64(GetLastError())))       End If    End If    Return hProvider End Function 

The code for AcquireNamedContext is in Listing 14.2.

Listing 14.2 AcquireNamedContext
 C# public IntPtr AcquireNamedContext(string in_ContainerName) {    IntPtr hProvider = IntPtr.Zero;    if (!CryptAcquireContext(ref hProvider, in_ContainerName,            "Microsoft Base Cryptographic Provider v1.0", PROV_RSA_FULL,            0))    {       if (!CryptAcquireContext(ref hProvider, in_ContainerName,               "Microsoft Base Cryptographic Provider v1.0", PROV_RSA_FULL,               CRYPT_NEWKEYSET))       {          throw new Exception("ManagedCryptoAPI cannot access default          keyset or create new default keyset!");       }    }    return hProvider; } VB Public Function AcquireNamedContext(ByVal in_ContainerName As String) As IntPtr    Dim hProvider As IntPtr = IntPtr.Zero    If (CryptAcquireContext(hProvider, in_ContainerName, "Microsoft Base            Cryptographic Provider v1.0", PROV_RSA_FULL,            Convert.ToUInt32(0)) = False) Then       Dim l_Failure As String = TranslateErrorCode(Convert.ToInt64               (GetLastError()))       ' We might have to create a new keyset...       If (CryptAcquireContext(hProvider, in_ContainerName, "Microsoft Base               Cryptographic Provider v1.0", PROV_RSA_FULL, CRYPT_NEWKEYSET) = False)               Then          ' Big trouble, could not create a new keyset and could not acquire          ' default keyset          Throw New Exception("ManagedCryptoAPI cannot access default keyset or                  create new default keyset!" + TranslateErrorCode(Convert.ToInt64                  (GetLastError())))       End If    End If    Return hProvider End Function 
Avoiding Pitfalls Associated with CryptAcquireContext

CryptAcquireContext returns a handle to a key container within a CSP. If the context for the key container that is asked for has never been acquired in the past, then the key container does not exist yet. In this case the key container must be created. AcquireDefaultContext and AcquireNamedContext both check for failure when calling CryptAcquireContext and try to create the key container if the first call fails. If the attempt to create the key container fails, then the methods throw an exception.

It is not a good practice to always attempt to create a new key container when calling CryptAcquireContext , because if the key container already exists, then the call to CryptAcquireContext will fail. Thus, it is very important to try to access the key container, assuming it does exist, and to try to create it only if necessary.



Microsoft.NET Compact Framework Kick Start
Microsoft .NET Compact Framework Kick Start
ISBN: 0672325705
EAN: 2147483647
Year: 2003
Pages: 206

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net