Brought to you by the

Application Programmer's Guide

Microsoft CryptoAPI

Preliminary

Version 0.9
January 17, 1996

Microsoft Corporation


Note This documentation is an early release of the final product documentation and is only for limited distribution outside of Microsoft and not for redistribution. It is meant to accompany software still in development. Some of the information in the documentation may be inaccurate or may not be an accurate representation of the functionality in the final released product. Microsoft assumes no responsibility for any damages that might occur either directly or indirectly from these inaccuracies.

This is a preliminary document and may be changed substantially prior to final commercial release. This document is provided for informational purposes only and Microsoft Corporation makes no warranties, either express or implied, in this document. The entire risk of the use or the results of the use of this document remains with the user. Companies, names, and data used in examples herein are fictitious unless otherwise noted. No part of this document may be reproduced or transmitted in any form or by any means, electronic or mechanical, for any purpose, without the express written permission of Microsoft Corporation.

Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. The furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property.

© 1995 Microsoft Corporation. All rights reserved.

Microsoft, MS, MS-DOS, Visual Basic, Win32, and Windows are registered trademarks, and Visual C++ and Windows NT are trademarks of Microsoft Corporation in the U.S.A. and other countries.

TrueType is a registered trademark is a registered trademark of Apple Computer, Inc.

Unicode is a trademark of Unicode, Incorporated.

All other trademarks are the property of their respective owners.

Printed in the United States of America.

January 17, 1996

Contents

  • Chapter 0 Introduction 1Audience 1Document Overview 1Document Conventions 2Related Documentation 3Chapter 1 Overview of Cryptography 5Data Encryption 5Symmetric Versus Public-Key Encryption 6Symmetric Algorithms 6Public-Key Algorithms 6Digital Signatures 7Chapter 2 The CryptoAPI Programming Model 9System Architecture 9Cryptographic Service Providers (CSPs) 10Key Databases 11Session Keys 11Public/Private Key Pairs 12Using Cryptography in your Applications 12Chapter 3 Interfacing with a Cryptographic Service Provider (CSP) 13Different Types of CSPs 14Provider Types 14Predefined Provider Types 15PROV_RSA_FULL Provider Type 16PROV_RSA_SIG Provider Type 16PROV_DSS Provider Type 16PROV_FORTEZZA Provider Type 17PROV_MS_MAIL Provider Type 17PROV_SSL Provider Type 17The Microsoft RSA Base Provider 17Connecting to a Cryptographic Service Provider 17Chapter 4 Generating Cryptographic Keys 19Cryptographic Key Overview 19Using Keys With CryptoAPI 20Session Keys 20Public/Private Key Pairs 20Chapter 5 Exchanging Cryptographic Keys 23Storing Session Keys 23Alternatives to Storing Session Keys 24Exchanging Public Keys 25Certificates and Certification Authorities 25Exchanging Public Keys Manually 26Exchanging Session Keys 26Sending an Encrypted Session Key 27Key Blobs Explained 28Simple Key Blobs 29Public Key Blobs 29Sample Three-Phase Exchange Protocol 29Overview of the Sample Protocol 30Phase 1 31Phase 2 31Phase 3 32Protocol Conclusion 32Sender Code Example 32Receiver Code Example 36Chapter 6 Encrypting and Decrypting Data 41Introduction to Encryption Techniques 41Stream Ciphers 42Block Ciphers 42Padding 42Cipher Modes 43Initialization Vectors 45Salt Values 46Common Encryption Algorithms 47RC2 Block Cipher 47RC4 Stream Cipher 47RSA Public-Key Cipher 47Encrypting Files and Messages 48Encrypting Messages Using CryptoAPI 48Structure of an Encrypted File 49Encryption Example 49Decrypting Messages Using CryptoAPI 52Decryption Example 53Encrypting and Decrypting Simultaneously 55Chapter 7 Hashes and Digital Signatures 57How Digital Signatures Work 57Signing and Verifying Messages 58Signing Data 59Verifying Signatures 59Obtaining the Hash Value 59Hashing and Signature Algorithms 60MD2, MD4, and MD5 60Secure Hash Algorithm (SHA) 60Message Authentication Code (MAC) 60Chapter 8 System Administration 61Installing a New Provider 61Outline of CryptoAPI Registry Usage 61Chapter 9 Service Provider Functions 63CryptAcquireContext 63CryptGetProvParam 69CryptReleaseContext 75CryptSetProvider 76CryptSetProvParam 78Chapter 10 Key Generation and Exchange Functions 81CryptDeriveKey 81CryptDestroyKey 85CryptExportKey 86CryptGenKey 89CryptGenRandom 92CryptGetKeyParam 93CryptGetUserKey 97CryptImportKey 99CryptSetKeyParam 102Chapter 11 Data Encryption Functions 107CryptDecrypt 107CryptEncrypt 110Chapter 12 Hashing and Digital Signature Functions 113CryptCreateHash 113CryptDestroyHash 115CryptGetHashParam 116CryptHashData 120CryptHashSessionKey 121CryptSetHashParam 124CryptSignHash 126CryptVerifySignature 129Chapter 13 Data Types and Constants 133ALG_ID 133HCRYPTHASH 134HCRYPTKEY 134HCRYPTPROV 134MAXUIDLEN 135MS_DEF_PROV 135
  • CHAPTER 0

    Introduction

    The Microsoft Cryptographic API (CryptoAPI) provides services that enable application developers to add cryptography to their Win32 applications. Applications can use the functions in CryptoAPI without knowing anything about the underlying implementation, in much the same way that an application can use a graphics library without knowing anything about the particular graphics hardware configuration.

    Audience

    This document is intended to be used by developers familiar with the Microsoft Windows programming environment. Previous experience with cryptography or other security related subjects is helpful, but not absolutely necessary.

    Document Overview

    This guide presents general information about how to incorporate cryptography into applications and offers specific information about the function data types of the Microsoft Cryptographic API (CryptoAPI). Following the introduction, this guide is divided into the following sections:

    Chapter 1, Overview of Cryptography

    This explains the basics of cryptography and focuses on the techniques and functionality supported by CryptoAPI.

    Chapter 2, The CryptoAPI Programming Model

    This introduces each major functional area and provides general guidelines for writing a secure application.

    Chapter 3, Interfacing with a Cryptographic Service Provider (CSP)

    This explains how applications interface with a CSP. The capabilities of the Microsoft RSA Base Provider are also explained.

    Chapter 4, Generating Cryptographic Keys

    This explains how to create, configure, and destroy cryptographic keys.

    Chapter 5, Exchanging Cryptographic Keys

    This explains how to export and import cryptographic keys from the CSP. The authenticated key exchange protocol is also covered.

    Chapter 6, Encrypting and Decrypting Data

    This explains some of the more common encryption techniques and how to use CryptoAPI to perform encryption and decryption of data.

    Chapter 7, Hashes and Digital Signatures

    This explains how to use CryptoAPI to sign data and keys.

    Chapter 8, System Administration

    This outlines how different CSPs are installed onto the system.

    Chapter 9, Service Provider Functions

    This explains each of the functions used by applications to connect to a cryptographic service provider.

    Chapter 10, Key Generation and Exchange Functions

    This explains each of the functions used to generate and exchange cryptographic keys. The material in this section directly relates to the procedures discussed in Chapter 4 and Chapter 5.

    Chapter 11, Data Encryption Functions

    This explains each of the functions used to encrypt and decrypt data.

    Chapter 12, Hashing and Digital Signature Functions

    This explains each of the functions used to create digital signatures as well as the ones used to create message digests (hashes) from data.

    Chapter 13, Data Types and Constants

    This explains some of the data types that are unique to CryptoAPI.

    Document Conventions

    The type conventions used in this document are as follows:

    Bold               Bold letters or text indicate a         
                       specific term to use, as in functions   
                       (for example, CryptGenKey), and         
                       structure fields. Data types such as    
                       HCRYPTHASH are shown in both bold and   
                       uppercase. You must enter these terms   
                       exactly as shown.                       
    
    ALL CAPS           The names of constants such as          
                       CALG_RC2, CRYPT_EXPORTABLE, and NULL    
                       are given in all upper-case letters,    
                       not in boldface type. These terms must  
                       be entered exactly as shown.            
    
    Italic              In introductory and explanatory text,  
                       italicized words indicate that a key    
                       term or concept is being introduced.    
                       In describing functions and messages,   
                       words in italic indicate a place        
                       holder where you need to provide the    
                       actual value. For example, the          
                       following syntax for the                
                       CryptGenRandom function indicates that  
                       you must substitute values for the      
                       hProv, dwLen, and pbBuffer parameters:  
                                                               
                       CryptGenRandom(HCRYPTPROV hProv, DWORD  
                       dwLen, BYTE *pbBuffer)                  
    
    Monospaced text     Monospaced type is used to display     
                       code samples and data structure         
                       definitions.                            
    
    
    

    Related Documentation

    Additional documents that will help you understand cryptography and the associated security issues include:

    Bruce Schneier, Applied Cryptography, John Wiley & Sons, 1996.

    Microsoft Cryptographic Service Provider Programmer's Guide, Microsoft, 1995.

    D. R. Stinson, Cryptography: Theory and Practice, CRC Press, 1995.

    R. Anderson, "Why Cryptosystems Fail," Communications of the ACM, v. 37, n. 11, November 1994, pp. 32-40.

    RSA Laboratories, Public-Key Cryptography Standards, RSA Data Security, November 1993.

    Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, Introduction to Algorithms, MIT Press, 1990.

    D.W. Davies and W.L. Price, Security for Computer Networks, John Wiley & Sons, 1989.

    Dorothy E. Denning, Cryptography and Data Security, Addison-Wesley, 1982.

    CHAPTER 1

    Overview of Cryptography

    Cryptography provides a set of techniques for encoding data and messages such that the data and messages can be stored and transmitted securely. This section introduces the basic terminology of cryptography and explains some of the common methods used.

    Cryptography can be used to achieve secure communications, even when the transmission media (for example, the Internet) is untrustworthy. You can also use cryptography to encrypt your sensitive files, so that an intruder cannot understand them.

    Cryptography can be used to ensure data integrity as well as maintain secrecy.

    Using cryptography, it becomes possible to verify the origin of data and messages. This is done using digital signatures, which are explained a little later in this chapter.

    When using cryptographic methods, the only part that must remain secret is the cryptographic keys. The algorithms, the key sizes, and file formats can be made public without compromising security.

    Data Encryption

    In using data encryption, a plaintext message can be encoded so it appears like random gibberish and is very difficult to transform back to the original message, without a secret key. In this document, the term message is used to refer to any piece of data. This message can consist of ASCII text, a database file, or any data you want to store or transmit securely. Plaintext is used to refer to data that has not been encrypted, while ciphertext refers to data that has.

    Once a message has been encrypted, it can be stored on nonsecure media or transmitted on an nonsecure network, and still remain secret. Later, the message can be decrypted into its original form. This process is shown in the following illustration:

    Encryption/Decryption Process

    When a message is encrypted, an encryption key is used. This is analogous to the physical key that is used to lock a padlock. To decrypt the message, the corresponding decryption key must be used. It is very important to properly restrict access to the decryption key, because anyone who possesses it will be able to decrypt all messages that were encrypted with the matching encryption key. Note that the encryption and decryption keys are often the same key.

    This may come as a surprise, but data encryption/decryption is pretty straight-forward. The really difficult part is keeping the keys safe and transmitting them securely to other users. This is discussed further in Chapter 5.

    Symmetric Versus Public-Key Encryption

    There are two main classes of encryption algorithms: symmetric algorithms and public-key algorithms (also known as asymmetric algorithms). Systems that use symmetric algorithms are sometimes referred to as conventional.

    Symmetric Algorithms

    Symmetric algorithms are the most common type of encryption algorithm. They are known as symmetric because the same key is used for both encryption and decryption. Unlike the keys used with public-key algorithms, symmetric keys are frequently changed. For this reason, they are referred to here as session keys.

    Compared to public-key algorithms, symmetric algorithms are very fast and, thus, are preferred when encrypting large amounts of data. Some of the more common symmetric algorithms are RC2, RC4, and the Data Encryption Standard (DES).

    Public-Key Algorithms

    Public-key (asymmetric) algorithms use two different keys: the public key and the private key. The private key is kept private to the owner of the key pair, and the public key can be distributed to anyone who requests it. If one key is used to encrypt a message, then the other key is required to decrypt the message.

    Public-key algorithms are very slow, on the order of 1000 times slower than symmetric algorithms. Consequently, they are normally used only to encrypt session keys. They are also used to digitally sign messages, as discussed in the next section.

    One of the most common public-key algorithms is the RSA Public-Key Cipher.

    Digital Signatures

    Digital signatures can be used when you have a message that you plan to distribute in plaintext form, and you want the recipients to be able to verify that the message comes from you and that it hasn't been tampered with since it left your hands. Signing a message does not alter the message, it simply generates a digital signature string you can bundle with the message or transmit separately.

    Digital signatures are generated using public-key signature algorithms. A private key is used to generate the signature, and the corresponding public key is used to validate the signature. This process is shown in the following illustration:

    Signature Generation/Validation Process

    On a network, there is often a trusted application running on a secure computer that is known as the Certification Authority. This application knows the public key of each user. Certification Authorities dispense messages known as certificates, each of which contains the public key of one of its client users. Each certificate is signed with the private key of the Certification Authority. A certificate containing the public key of the signer is often bundled with a signed message to make it easier to verify the signature. (Certificates are described in more detail in Chapter 5.)

    CHAPTER 2

    The CryptoAPI Programming Model

    The Microsoft Cryptographic Application Program Interface (CryptoAPI) is a set of functions that allow applications to encrypt or digitally sign data in a flexible manner, while providing protection for the user's sensitive private key data.

    All cryptographic operations are performed by independent modules known as cryptographic service providers (CSPs). One CSP, the Microsoft RSA Base Provider, is bundled with the operating system.

    Each CSP provides a different implementation of the CryptoAPI. Some provide stronger cryptographic algorithms while others contain hardware components such as smartcards. In addition, some CSPs may occasionally communicate with users directly, such as when digital signatures are performed using the user's signature private key.

    The CryptoAPI programming model can be compared to the Windows GDI model in that the CSPs are analogous to graphics device drivers, and the cryptographic hardware (optional) is analogous to graphics hardware. Just as well-behaved applications are not allowed to communicate with graphics device drivers and hardware, well-behaved applications cannot directly access the CSPs and cryptographic hardware.

    System Architecture

    The Microsoft cryptographic system is composed of a number of different components, as shown in the following illustration. The three executable portions are the application itself, the operating system, and the CSP.

    Applications communicate with the operating system through a set of functions known as the cryptographic application program interface (CryptoAPI). The operating system, in turn, communicates with CSPs through a set of functions known as the cryptographic service provider interface (CryptoSPI).

    Cryptographic System Architecture

    Note that applications do not communicate with CSPs directly. Instead, all cryptographic function calls are routed through the operating system. A parameter in each CryptoAPI function indicates to the operating system which CSP to use to perform the actual cryptographic operation.

    Cryptographic Service Providers (CSPs)

    As mentioned above, CSPs are independent modules that perform the real cryptographic work. Ideally, they are written to be completely independent of any particular application, so that any given application will run with a variety of CSPs. In reality however, some applications may have very specific requirements that require a custom CSP.

    The physical manifestation of a CSP consists of, at a minimum, a dynamic-link library (DLL) and a signature file. The signature file is necessary to ensure that the operating system recognizes the CSP. The operating system validates this signature periodically to ensure that the CSP has not been tampered with.

    Some CSPs may implement a fraction of their functionality either in an address separated service called through local RPC, or in hardware called through a system device driver. Isolating global key state and central cryptographic operations in hardware or in a service keeps keys and operations safe from tampering within the application data space.

    Applications should not take advantage of attributes particular to a specific CSP. For example, the Microsoft RSA Base Provider currently uses 40-bit session keys and 512-bit public keys. When applications manipulate these, they should be careful not to make assumptions about the amount of memory needed to store them. Otherwise, the application is likely to fail when the user loads a different CSP onto the system. You should take care to write applications that are as well-behaved and flexible as possible.

    Key Databases

    Each CSP has a key database in which it stores its persistent cryptographic keys. Each key database contains one or more key containers, each of which contain all the key pairs belonging to a specific user (or CryptoAPI client). Each key container is given a unique name, which applications provide to the CryptAcquireContext function when acquiring a handle to the key container. Following is an illustration of the contents of a key database:

    Contents of a Key Database

    The CSP stores each key container from session to session, including all the public/private key pairs it contains. However, session keys are not preserved from session to session.

    Generally, a default key container is created for each user. This key container takes the user's logon name as its own name which is then used by any number of applications. It is also possible for an application to create its own key container (and key pairs) which it usually names after itself.

    Session Keys

    Session keys are used when encrypting and decrypting data. They are created by applications using either the CryptGenKey or the CryptDeriveKey function. These keys are kept internal to the CSP for safekeeping.

    Unlike the key pairs, session keys are volatile. Applications can save these keys for later use or transmission to other users by exporting them from the CSP into application space in the form of an encrypted "key blob" using the CryptExportKey function. (This procedure is discussed in Chapter 5.)

    Public/Private Key Pairs

    Each user generally has two public/private key pairs. One key pair is used to encrypt session keys and the other to create digital signatures. These are known as the key exchange key pair and the signature key pair, respectively. (These keys pairs are discussed later in detail.)

    Note that the while key containers created by most CSPs will contain two key pairs, this is not required. Some CSPs do not store any key pairs while others store additional ones.

    Using Cryptography in your Applications

    The Microsoft Cryptographic Application Program Interface (CryptoAPI) specifies functions in a number of different areas:

    Context Functions

    These functions are used by applications to connect to a CSP. These functions enable applications to choose a specific CSP by name, or get one with a needed class of functionality. (See Chapter 3 and Chapter 9.)

    Key Generation Functions

    These functions allow applications to generate and customize cryptographic keys. Full support is included for changing chaining modes, initialization vectors, and other encryption features. (See Chapter 4 and Chapter 10.)

    Key Exchange Functions

    These functions allow applications to exchange or transmit keys. These functions can also be used to implement fully authenticated three-leg key exchange. (See Chapter 5 and Chapter 10.)

    Data Encryption Functions

    These functions allow applications to encrypt or decrypt data. Support is also included for simultaneously encrypting and hashing data. (See Chapter 6 and Chapter 11.)

    Hashing and Signature Functions

    These functions allow applications to compute cryptographically secure digests of data and also enable digital signing of data. (See Chapter 7 and Chapter 12.)

    CHAPTER 3

    Interfacing with a Cryptographic Service Provider (CSP)

    The CSP architecture provides a safe way for multiple applications to access cryptographic and signature services. Instead of being passive sets of encryption routines, CSPs are independently functioning cryptographic modules capable of authenticating the user and checking for user assent to actions.

    For example, some CSPs will require a PIN to be entered before a digital signature is generated, while some require a smart card, and still others have no authentication at all. The quality of protection for keys within the system is a design parameter of the CSP itself and not the system as a whole. This lets the same applications run in a variety of security contexts without modification.

    The amount of access that applications have to the cryptographic internals has been carefully restricted. This was done to facilitate writing applications that are both secure and portable. The following three design rules apply:

    Applications cannot directly access keying material. Because all keying material is generated within the CSP and used by the application through opaque handles, there is no risk of an application or its associated DLLs either divulging keying material or choosing keying material from poor random sources.

    Applications cannot specify the details of cryptographic operations. The CSP interface only allows applications to specify broad actions to take (for example, encrypt data using algorithm X and sign data). The actual implementation of the cryptographic operations is the responsibility of the CSP. This limits the scope of the API because esoteric protocols require application intervention, but make a basic set of operations readily available to all applications.

    Applications do not handle user authentication data. User authentication is done by the CSP. In this way, CSPs that have better authentication capabilities (for example, biometric inputs and data keys) will function without needing to change the application's authentication model. It also prevents applications from divulging user secrets.

    Different Types of CSPs

    Each provider has both a name and a type. For example, the name of the CSP currently shipped with the operating system is "Microsoft Base Cryptographic Provider v1.0," and its type is PROV_RSA_FULL. The name of each provider is unique; the provider type is most definitely not.

    Provider Types

    The field of cryptography is very large. There are dozens of different "standard" data formats and protocols. These are generally organized into groups or "families," each of which has its own set of data formats and way of doing things. Even if they use the same algorithm (for example, the RC2 block cipher), two families will often use a different padding scheme, different key lengths, and different default modes. CryptoAPI has been designed so each CSP type represents a particular family.

    When an application connects to a CSP of a particular type, each of the CryptoAPI functions will, by default, operate in a way prescribed by the "family" that corresponds to the CSP type. Among other things, an application's choice of provider type specifies the following items:

    Key exchange algorithm - Each provider type specifies one and only one key exchange algorithm. Every CSP of a particular type must implement this algorithm. The only way applications can specify which key exchange algorithm is used is by selecting a CSP of the appropriate provider type.

    Digital signature algorithm - This is the same as with the key exchange algorithm. Each provider type specifies one and only one digital signature algorithm.

    Key blob format - When a public key or session key is exported out of a CSP, the format of the resulting "key blob" is specified by the provider type.

    Digital signature format - The provider type prescribes a particular digital signature format. This ensures that a signature produced by a CSP of a given provider type can be verified by any CSP of the same provider type.

    Session key derivation scheme - When a key is derived from a hash, the method used is specified by the provider type.

    Key length - Some provider types will specify that the public/private key pairs or the session keys be of a certain length.

    Default modes - The provider type will often specify a default mode for various options, such as the block encryption cipher mode or the block encryption padding method.

    Each application will generally work only with a single type of CSP. (However, an ambitious application can connect to more than one CSP at a time.) When writing an application, you will often need to obtain all the documentation that relates to the CSP type you are using. For example, it is not recommended that you try to write an application using the PROV_RSA_FULL provider type without obtaining the Public-Key Cryptographic Standards (PKCS) from RSA Data Security, Inc. The relevant third-party documentation for each provider type is listed later on in this section.

    Predefined Provider Types

    A number of provider types have already been defined. The following table lists these provider types, along with the algorithms that each type must support. A CSP of a given type is free to support other algorithms in addition to the ones listed.

    Provider Type   Key         Signature  Encryption Hashing      
                    Exchange                                       
    
                                                               
    
    PROV_RSA_FULL   RSA         RSA        RC2, RC4   MD5, SHA     
    
    PROV_RSA_SIG    n/a         RSA        n/a        MD5, SHA     
    
    PROV_DSS        n/a         DSS        n/a        SHA          
    
    PROV_FORTEZZA   KEA         DSS        Skipjack   SHA          
    
    PROV_MS_MAIL    RSA         RSA        CAST       MD5          
    
    PROV_SSL        RSA         RSA        varies     varies       
    
    
    

    If two or more applications plan to exchange keys and encrypted messages, they should both use CSPs of the same type, however, some CSP types may be partially compatible with others.

    Anyone writing a custom CSP can define a new provider type. However, this person is then responsible for distributing the new provider type to the authors of any applications that are to use it.

    In the event that the previous table mentioned algorithms you are not familiar with, the following table provides a brief description of each.

    Algorithm Description                                       
                                                                
    
                                                                
    
    CAST      This is a 64-bit symmetric block cipher           
              developed by C. M. Adams and S. E. Tavares. This  
              algorithm is somewhat similar to DES (Data        
              Encryption Standard).                             
    
    DES       National Institute of Standards and Technology    
              (NIST) Data Encryption Standard. This is a 64bit  
              symmetric block cipher that has a fixed key       
              length of 56-bits.                                
    
    DH        Diffie-Hellman. This is a public-key algorithm    
              used for secure key exchange. It cannot be used   
              for data encryption.                              
    
    DSS       Digital Signature Standard. This standard uses    
              the Digital Signature Algorithm (DSA), which is   
              a public-key cipher used to generate digital      
              signatures. It cannot be used for data            
              encryption.                                       
    
    KEA       Key Exchange Algorithm. This is an improved       
              version of Diffie-Hellman.                        
    
    MD2       MD2. This is a hashing algorithm that produces a  
              128bit hash value.                                
    
    MD4       MD4. This is a hashing algorithm that produces a  
              128bit hash value.                                
    
    MD5       MD5. This is an improved version of MD4. It also  
              produces a 128bit hash value.                     
    
    RC2       RC2 Block Cipher. This is a 64bit symmetric       
              block cipher.                                     
    
    RC4       RC4 Stream Cipher. This is a symmetric stream     
              cipher.                                           
    
    RSA       RSA Public-Key Cipher. This is a popular          
              public-key cipher used for both encryption and    
              signatures.                                       
    
    SHA       Secure Hash Algorithm. This is a hashing          
              algorithm that produces a 160bit hash value.      
    
    Skipjack  This is the algorithm used by the Clipper and     
              Capstone chips. It is a symmetric block cipher    
              with a fixed key length of 80 bits.               
    
    
    

    PROV_RSA_FULL Provider Type

    This provider type supports both digital signatures and data encryption, and considered general purpose. The RSA public-key algorithm is used for all public-key operations.

    This provider type has been thoroughly defined by Microsoft and RSA Data Security. It is described in the following documents:

    Microsoft Cryptographic Service Provider Programmer's Guide, Microsoft, 1995.

    RSA Laboratories, Public-Key Cryptography Standards, RSA Data Security, November 1993.

    PROV_RSA_SIG Provider Type

    This provider type is a subset of PROV_RSA_FULL. Only those functions and algorithms required for hashes and digital signatures are supported.

    PROV_DSS Provider Type

    This provider type is similar to PROV_RSA_SIG in that it only supports hashes and digital signatures, but the signature algorithm specified by the PROV_DSS provider type is the Digital Signature Algorithm (DSA).

    The DSA algorithm was proposed by the National Institute of Standards and Technology (NIST). A description of the algorithm can be found in many books on cryptography or from the following government reference:

    "Proposed Federal Information Processing Standard for Digital Signature Standard (DSS)," Federal Register, v. 57, no. 21, 31 Jan 1992, pp. 3747-3749.

    PROV_FORTEZZA Provider Type

    The set of cryptographic protocols and algorithms known as "Fortezza" is "owned" by the National Institute of Standards and Technology (NIST). More information is available directly from them or from other sources.

    PROV_MS_MAIL Provider Type

    CSPs of this type are designed to cater to the cryptographic needs of the Microsoft Mail application, as well as other applications that are compatible with MS Mail. This provider type is preliminary.

    PROV_SSL Provider Type

    CSPs of this type support the Secure Sockets Layer (SSL) protocol. A specification explaining the SSL protocol is available from Netscape Communications Corp.

    The Microsoft RSA Base Provider

    The Microsoft RSA Base Provider is supplied by Microsoft and is included with the operating system (either Windows NT or Windows 95).

    The Microsoft RSA Base Provider consists of a software implementation of the PROV_RSA_FULL provider type. The RSA public-key cipher is used for both key exchange and digital signatures, with a key length of 512 bits. The RC2 and RC4 encryption algorithms are implemented with a key length of 40 bits. The MD2, MD5, and SHA hashing algorithms are also provided.

    Connecting to a Cryptographic Service Provider

    Each time an application is run, the first CryptoAPI function an application calls is the CryptAcquireContext function. This function returns to the application a handle to a particular CSP. In addition, this handle specifies a particular key container within the CSP. If the CSP has just been installed and no key containers yet exist, the CryptAcquireContext function can also be used to create a new one.

    When an application uses CryptAcquireContext to obtain a CSP handle, it specifies a provider type and, optionally, a provider name. If both a type and a name are specified, then the function looks for a CSP with precisely the same type and name, loads it into memory, and returns a handle to the application.

    When an application calls CryptAcquireContext specifying a provider type but no provider name, the function tries to find the provider name, first on a list of default providers associated with the logged-on user and, if that fails, from a list of default providers associated with the computer.

    Once the provider name has been determined successfully, the CryptAcquireContext function searches for the CSP, loads it into memory, and returns a handle to the application.

    CHAPTER 4

    Generating Cryptographic Keys

    Keys lie near the center of almost every cryptographic operation. It is important to keep these secret because whoever possesses a given key then has access to any data that key is associated with. For example, if a key is used to encrypt a file, then anyone with a copy of that key can easily decrypt the file. Furthermore, if the key is used to sign messages, then anyone possessing that key can forge the signatures.

    Cryptographic Key Overview

    There are two types of cryptographic keys: session keys and public/private key pairs.

    Session Keys

    Session keys are primarily used for data encryption/decryption and are used with symmetric encryption algorithms. That is, the same key is used for both encryption and decryption.

    Most of the activity involving session keys relates to keeping them secret. It is important to keep the number of people who possess a particular session key as small as possible (one or two people is recommended).

    Public/Private Key Pairs

    Key pairs are composed of two components: the public key and the private key. The public key is distributed far and wide while the private key, on the other hand, is kept secret. Only the owner of the key pair is allowed to possess the private key.

    If one of the keys (the public key) is used to encrypt a message, then the other key is required to decrypt it. Thus, if you want to send someone a message, you can encrypt the file using their public key and be confident that no one else will be able to read the file.

    If the private key is used to sign a message, then the other key must be used to validate the signature. For example, if you want to send someone a digitally signed message, you would sign the message with your private key, and the other person could verify your signature using your public key.

    Unfortunately, public-key algorithms are incredibly slow and it is impractical to use them to encrypt large amounts of data. In practice, symmetric algorithms are used for encryption/decryption, while the public-key algorithms are used merely to encrypt the session keys. Similarly, it is not practical to use public-key signature algorithms to sign large messages. Instead, a hash is made of the message and the hash value is signed.

    Using Keys With CryptoAPI

    All keys are stored within cryptographic service providers (CSPs). CSPs are also responsible for creating the keys, destroying them, and using them to perform a variety of cryptographic operations. (Exporting keys out of the CSP so they can be sent to other users is discussed in Chapter 5.)

    Session Keys

    Applications can create any number of session keys, which can be used to encrypt messages. However, these keys are not preserved by the CSP from session to session. If you want to use a key for long periods, you need to export the key out of the CSP and into your application for long-term storage. (The procedure for doing this is discussed in Chapter 5.)

    Session keys are created using either the CryptGenKey or the CryptDeriveKey function. When these keys are generated, it is necessary to specify the algorithm to use for any subsequent encryption/decryption operations. This algorithm must be one of the symmetric algorithms supported by the CSP being used.

    Public/Private Key Pairs

    For each user, the CSP usually maintains two public/private key pairs. These keys are maintained from session to session.

    The key exchange key pair (also known as the exchange key) is used to encrypt session keys so that they can be safely stored and exchanged with other users. (This is discussed in detail in Chapter 5.)

    The digital signature key pair (also known as the signature key) is used to sign either hashes of data. This is discussed in detail in Chapter 7.)

    There are a number of reasons for having two separate key pairs. For example, some CSPs may opt to use one algorithm for key exchange and another for digital signatures. This is because some digital signature algorithms are unsuitable for encryption or key exchange, and vise versa. Also, if some data (for example, a session key) is both signed and encrypted with the same public key pair, subtle weaknesses could be introduced that make the data vulnerable.

    The exchange key and the signature key pairs are created by calling the CryptGenKey function and specifying either AT_KEYEXCHANGE or AT_SIGNATURE. The CSP implements these keys in an application-independent manner. Applications are not permitted to know the details about the algorithm used.

    CHAPTER 5

    Exchanging Cryptographic Keys

    This section discusses those situations when you must export keys from the secure environment of the cryptographic service provider (CSP) into your application's data space. Keys that have been exported are stored in encrypted data structures known as key blobs. These are discussed in the "Key Blobs Explained" section.

    There are two specific situations when it is necessary to export keys:

    You want to save a session key for later use by your application. For example, if your application has just encrypted a database file and you want your application to decrypt this file at a later time, your application is responsible for storing the encryption key. This is necessary because CSPs do not preserve symmetric keys from session to session.

    You want to send a key to someone else. This would be much easier (for your application) if the respective CSPs could communicate directly, but they cannot. This means the key has to be exported from your CSP, transmitted by your application to the destination application, and then imported into the destination CSP. If you don't trust the communication path, this can become somewhat complicated. However, this is covered in the next few sections.


    Note

    This section assumes that users (or CryptoAPI client) already possess their own set of public/private key pairs. Instructions for creating these can be found in Chapter 4.

    Storing Session Keys

    This section discusses how you use CryptoAPI to store a session key for later use. This is useful in those situations where you have encrypted a file using a key and want to decrypt the file at a later time. Another possible situation is one in which you have shared the session key with another user and you want to use the key at a later time to send the other user encrypted messages.

    In either case, your application will have to store the session key outside of the CSP for a certain period. Following is the procedure for storing a session key.

    1. Create a simple key blob using the CryptExportKey function. This will transfer the session key from the CSP to your application's memory space. Specify that your own key exchange public key be used to encrypt the key blob.

    2. Store the signed key blob to disk. The assumption is made here that all disks are nonsecure.

    3. Later, when you need to use the key, read the key blob from disk.

    4. Import the key blob back into the CSP using the CryptImportKey function.

    If the session key is just to be bundled with an encrypted file (so that you can later decrypt the file), and the key is not going to be used to encrypt any more data, then the above procedure provides adequate security.

    If you plan to use the session key for encryption at a later time, then the key blob should be signed with your key exchange key before the key is stored to disk. When you later read the key blob back from disk, you should validate the signature to make sure the key blob is intact. If these steps are omitted, then someone with access to your storage media can create their own session key, encrypt it with your key exchange public key, and substitute it for your key blob. You could then unknowingly use their session key to encrypt files and messages, which the unscrupulous user could then easily decrypt. (Digital signatures are discussed in detail in Chapter 7.)

    Alternatives to Storing Session Keys

    Instead of storing a random session key blob, a derived key can be used. Derived session keys are created from a password using the CryptDeriveKey function. In this way, instead of storing a particular derived key, an application can create a derived key as needed by prompting the user for the password.

    Stored key blobs are dependent on the stability of the public/private key pairs stored within the CSP. If these key pairs are somehow lost, (for example, through a hardware or software incident), you will be unable to decrypt your key blobs. This means that any data that has been encrypted using these keys will also be lost. For this reason, it is recommended that you use a backup authority when storing long-term archival data.

    A backup authority is a trusted application running on a secure computer which provides storage for the session keys of its clients. All session keys stored there are encrypted in the form of key blobs with the backup authority's public key. An application using a backup authority typically follows these steps:

    1. Encrypt the file normally.

    2. Export the session key used to encrypt the file into a simple key blob, specifying that your own key exchange public key be used to encrypt the key blob. Store this key blob with the encrypted file.

    3. Export the session key again, this time specifying that the backup authority's public key be used to encrypt the key blob. Send this key blob to the backup authority, along with the key's description, serial number, etc.

    If, at a later time, you lose your key pairs, you can retrieve the session keys from the backup authority. (You will first have to establish your identity to the backup authority, but this procedure falls outside the scope of CryptoAPI.)

    Exchanging Public Keys

    Exchanging public keys is the first step that two users contemplating encrypted communication need to do. Once this has been done, the users can send encrypted and signed data to each other in a straightforward manner.

    There are two fundamental ways to obtain each other's public keys:

    The users can obtain each other's keys in the form of certificates, from a certification authority. This is the most secure way to exchange public keys which does not require user interaction.

    The users can read their public keys to each other over the phone, use certified mail to send them to each other, or use another method that is reasonably tamperproof. Note that your public key is not secret, so that it doesn't matter if it is overheard by a third party.

    This method can also be used to validate the public key values that have been exchanged in some other manner.

    Certificates and Certification Authorities

    A certificate is a packet of data that contains a user's public key in addition to the data that serves to identify the user in the real world (for example, the user's name). Every certificate is created and signed by a trusted application known as a certification authority.

    Because certificates are signed, they can be transmitted over a nonsecure network or stored on nonsecure media. Each time you receive a certificate, you should verify the signature using the certification authority's public key.

    Certain details relating to certificates are beyond the scope of CryptoAPI. These include:

    The actual binary format of certificates is not specified by CryptoAPI, although ISO X.509 is recommended.

    The manner in which each client communicates his or her name and public keys to the certification authority is not specified.

    The manner in which the certification authority's public key is distributed is not specified.


    Warning

    If you use the Microsoft RSA Base Provider to create a certification authority, your license to issue certificates is limited to certificates intended for use in the context of your particular application or service.

    Exchanging Public Keys Manually

    If a certification authority is not available, or if one or more of the users has not registered their public keys with it, then the users need to exchange their public keys in some other manner. This can also be done if the certification authority is not considered trustworthy by one or more of the users.

    When transferring keys or messages from one user to another, one of the users is designated the sending user (or sender) and the other the destination user (or receiver).

    The first step is for the sender to export his public key from the CSP into a public key blob, using the CryptExportKey function. Next, the key blob must be sent to the destination user in some secure manner. Although secrecy is not necessary, both users must be confident that the integrity of the key blob remains untarnished during the transfer. (The mechanics of how this is done are completely independent of the CryptoAPI.)

    Public key blobs are not encrypted. Thus, it would not be difficult for the sending application to convert the key blob to a human-readable format, so that the sender could read the public key to the receiver over the phone. Furthermore, it would not be difficult for the receiving application to reconstruct the public key blob.

    Once the receiver has received the key blob data from the sender, it imports the key blob into its own CSP. This is done using the CryptImportKey function.

    Exchanging Session Keys

    To send another user an encrypted message, it becomes necessary to send that user the session key that was used to perform the encryption. There are two ways this can be approached:

    The sending user can create a random session key, encrypt it using the receiver's public key, and send the encrypted key (key blob) to the receiver. The sender can then send messages encrypted with this session key to the receiver. This approach is discussed in the following section.

    The sending and receiving users can mutually agree on a session key by exchanging several messages back and forth. The users can then use this session key to send encrypted messages back and forth. The "Sample Three-Phase Exchange Protocol" section describes a sample three-phase key exchange protocol that can be used for this purpose. Designing one of these protocols (and getting it right!) is fairly difficult and should only be attempted by an experienced cryptographer.


    Note

    This section assumes that the users (or CryptoAPI clients) already possess their own set of public/private key pairs and have also obtained each other's public keys.

    Sending an Encrypted Session Key

    The easiest way to send encrypted messages to another user is to send the message (encrypted with a random session key) along with the session key (encrypted with the receiver's exchange public key). These are the steps for sending an encrypted session key:

    1. Create a random session key using the CryptGenKey function.

    2. Encrypt the message using the session key. (This procedure is discussed in the section "Encrypting and Decrypting Data.")

    3. Export the session key into a key blob with the CryptExportKey function, specifying that the key be encrypted with the destination user's key exchange public key.

    4. Send both the encrypted message and the encrypted key blob to the destination user.

    5. The destination user should then import the key blob into his or her CSP using the CryptImportKey function. This will automatically decrypt the session key, provided the destination user's key exchange public key was specified in step 3.

    6. The destination user can then decrypt the message using the session key, following the procedure discussed in Chapter 6.

    The following illustration shows how to send an encrypted message using this procedure:

    Sending an Encrypted Message with Key Blob

    This approach is vulnerable to at least one common form of attack. An eavesdropper can acquire copies of one of more encrypted messages and the encrypted keys. Then, at some later time, the eavesdropper can send one of these messages to the receiver and the receiver will have no way of knowing the message did not come directly from the original sender. This risk can be reduced by timestamping all messages or by using serial numbers. Using a three-phase key exchange protocol will eliminate this problem entirely. See the "Sample Three-Phase Exchange Protocol" section.

    Key Blobs Explained

    Key blobs provide a way to store keys outside of the CSP. Chapter 4 stated that keys are always kept inside of the provider for safekeeping and applications are only allowed access to the key through a handle. Well, key blobs are the one exception to this rule.

    Key blobs are created by exporting an existing key out of the provider, using the CryptExportKey function. Later, the key blob can be imported into a provider (often a different provider on a different computer), using the CryptImportKey function. This will create a key in the provider that is a duplicate of the one that was exported. In this way, key blobs are used as the medium for securely transferring keys from one provider to another.


    Note

    Private keys can be neither exported nor imported - they never leave the safety of the CSP module. When the handle to a public/private key pair is passed into CryptExportKey, only the public portion is placed into the key blob.

    Key blobs consist of a standard header followed by data that represents the key itself. If the key blob contains a session key, then this data is always kept encrypted. Applications generally do not access the internals of key blobs but, instead, treat them as opaque objects. This opaque quality was the inspiration for the name of "key blob."

    Key blobs are personalized in that they are encrypted with the key exchange public key of the intended recipient. This makes them fairly secure. To make them tamperproof, keys are sometimes signed with the key exchange private key of the originating user.

    There are currently two types of key blobs:

    Simple key blobs

    Public key blobs

    Simple Key Blobs

    A simple key blob (SIMPLEBLOB) is a session key encrypted with the public key exchange key of the destination user. This key blob type is used when storing a session key or transmitting a session key to another user.

    Public Key Blobs

    A public key blob (PUBLICKEYBLOB) contains the public key portion of a public/private key pair. Unlike simple key blobs, these are not encrypted.

    When communicating with someone who is not using CryptoAPI, your application may need to build one of these key blobs manually so the other user's public keys can be imported into your CSP. In addition, it is not unheardof for an application to display the value of a public key in plaintext form so the user can validate it by hand. (The format of public key blobs is fully documented in the Microsoft Cryptographic Service Provider Programmer's Guide.)

    Sample Three-Phase Exchange Protocol

    To generate an authenticated and encrypted connection between two parties on a nonsecure network, a set of messages can be exchanged which negotiate an encryption key between them. Both parties contribute a portion of the data that the negotiated session key is derived from. This protocol ensures that both the parties are currently active and are sending messages directly to each other.


    Note

    This section assumes that both parties involved already possess their own set of public/private key pairs and that they have also obtained each other's public keys.

    It is further assumed that the parties have already exchanged human-readable user names. This is generally done at the same time the public keys are exchanged, since the user name is included as part of each certificate. When necessary, the public key data can be used as the user name, although this is not recommended. All that really matters, though, is that each party's user name be tightly bound to their public key and that both parties agree on what their respective user names are.

    Overview of the Sample Protocol

    This protocol provides a standard way for two parties to create an authenticated, real-time connection between themselves. The end result of this protocol is a session key that is shared by both of the parties involved. This protocol is known as a three-phase protocol because it requires that the two parties exchange three packets of data in the process of creating the shared session key. This is shown in the following illustration, reading from top to bottom.

    Sample Three-phase Key Exchange Protocol

    A variety of key exchange protocols can be implemented using CryptoAPI. The protocol discussed here is just one of many possibilities. However, using this particular protocol will tend to increase your application's potential interoperability.

    Following is a description of this protocol. One of the parties is arbitrarily designated the sending user (or sender) and the other the destination user (or receiver).

    Phase 1

    In Phase 1, the sender creates a random session key, to be known as "session key A", using the CryptGenKey function. The sender then uses CryptExportKey to export this key into a simple key blob, specifying that the receiver's exchange public key be used to encrypt the key blob. This key blob is then sent to the receiver.

    The receiver accepts the key blob from the sender and imports it into its CSP, using the CryptImportKey function. This function returns a handle to session key A to the receiver.

    Phase 2

    In Phase 2, the receiver then creates a random session key of its own, to be known as "session key B." The receiver exports this key into a key blob and transmits it to the sender.

    The receiver then builds up a hash value containing session key A, the receiver's name, session key B, the sender's name, and the text "phase 2." This hash value is then sent to the sending user. (The details of this process are discussed in this chapter under "Receiver Code Example.")

    The data must be hashed in the standard sequence, so the sender will be able to properly validate it. The data formats used by the sender and receiver must also match, although a standard format is not specified here.

    The sending user accepts the "session key B" key blob from the receiver, and imports it into its CSP. The hash value is also received.

    The sending user then validates the receiver's hash value by creating a hash of its own containing the same data, and comparing the two hash values. If the hash values do not match, then either the destination user has not been forthright, or someone else is tampering with the data between the two parties. In either case, the protocol should be terminated and the communication link severed.

    If the two hash value do match, this tells the sender that the destination user is presently online and in real-time communication. This is primarily because the hash value contains session key A, which was sent out encrypted with the destination user's public key. Only the real destination user could have decrypted the session key and built the hash value. Including the human-readable user names in the hash makes it possible to involve the users in the process as an additional check.

    Phase 3

    In Phase 3, the sender builds up a hash value containing session key B, the sender's name, the receiver's name, and the text "phase 3." This hash value is then sent to the destination user. (The details of this process are discussed in this chapter under "Sender Code Example.")

    The destination user accepts the hash value from the sender and validates it by creating a hash of its own and comparing the two hash values. If the hash values do not match, then the protocol should be terminated and the communication link severed.

    If the two hash value do match, this tells the receiver that the sending user is presently online and in real-time communication. This is primarily because the hash value contains session key B, which was sent out encrypted with the sending user's public key. Only the real sending user could have decrypted the session key and built the hash value.

    Protocol Conclusion

    Once the two parties have exchanged session keys and hash values and the hash values have been properly validated, the protocol is complete. Each party can now independently create a shared session key that can be used to send encrypted messages to each other.

    To create the shared session key, each party must create a hash object with CryptCreateHash, add session key A and session key B to the hash with CryptHashSessionKey, and then derive the key using CryptDeriveKey. This procedure is shown in detail in the code examples.

    Sender Code Example

    This section shows the code needed on the sending user side to implement the three-phase key exchange protocol. The details of the communication between the sending user and the destination user are not shown, because these will be different for each implementation.

    For purposes of readability, this example and the following one blatantly avoid good programming practice in two major ways:

    No error checking is shown. A working program should always check the returned error codes and perform some appropriate action when an error is encountered.

    Fixed-length buffers are used to store key blobs and hash values. In practice, these buffers should be allocated dynamically, because this data will vary in size depending on the CSP used.

    #include <wincrypt.h>
    HCRYPTPROV hProv = 0;
    #define NAME_SIZE 256
    BYTE pbDestName[NAME_SIZE];
    DWORD dwDestNameLen;
    BYTE pbSendName[NAME_SIZE];
    DWORD dwSendNameLen;
    HCRYPTKEY hDestPubKey = 0;
    HCRYPTKEY hSharedKey = 0;
    HCRYPTKEY hKeyA = 0;
    HCRYPTKEY hKeyB = 0;
    #define BLOB_SIZE 256
    BYTE pbKeyBlob[BLOB_SIZE];
    DWORD dwBlobLen;
    #define HASH_SIZE 256
    BYTE pbHash[HASH_SIZE];
    DWORD dwHashLen;
    BYTE pbDestHash[HASH_SIZE];
    DWORD dwDestHashLen;
    HCRYPTHASH hHash = 0;
    // Get handle to the default provider.
    CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0);
    // Obtain the destination user's exchange public key. Import it into
    // the CSP and place a handle to it in 'hDestPubKey'.
    ...
    CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hDestPubKey);
    // Obtain the destination user's name. This is usually done at the
    // same time as the public key was obtained. Place this in 
    // 'pbDestName' and set 'dwDestNameLen' to the number of bytes in 
    // the name.
    ...
    // Place the sending user's name in 'pbSendName' and set 
    // 'dwSendNameLen' to the number of bytes in it.
    ...
    // Create a random session key (session key A). Because this key will
    // be used solely for key exchange and not encryption, it 
    // does not matter which algorithm you specify here.
    CryptGenKey(hProv, CALG_RC2, CRYPT_EXPORTABLE, &hKeyA);
    // Export session key A into a simple key blob.
    dwBlobLen = BLOB_SIZE;
    CryptExportKey(hKeyA, hDestPubKey, SIMPLEBLOB, 0, pbKeyBlob, &dwBlobLen);
    // Send key blob containing session key A to the destination user.
    ...
    // Wait for the destination user to respond.
    ...
    // Receive a key blob containing session key B from the destination 
    // user and place it in 'pbKeyBlob'. Set 'dwBlobLen' to the number 
    // of bytes in the key blob.
    ...
    // Receive a hash value from the destination user and place it in
    // 'pbHashValue'. Set 'dwHashLen' to the number of bytes in the hash 
    // value.
    ...
    // Import the key blob into the CSP.
    CryptImportKey(hProv, pbKeyBlob, dwBlobLen, 0, 0, &hKeyB);
    //
    // Verify hash value received from the destination user.
    //
    // Create hash object.
    CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash);
    // Add session key A to hash.
    CryptHashSessionKey(hHash, hKeyA, 0);
    // Add destination user's name to hash.
    CryptHashData(hHash, pbDestName, dwDestNameLen, 0);
    // Add session key B to hash.
    CryptHashSessionKey(hHash, hKeyB, 0);
    // Add sending user's name to hash.
    CryptHashData(hHash, pbSendName, dwSendNameLen, 0);
    // Add "phase 2" text to hash.
    CryptHashData(hHash, "phase 3", 7, 0);
    // Complete the hash computation and retrieve the hash value.
    dwHashLen = HASH_SIZE;
    CryptGetHashParam(hHash, HP_HASHVALUE, pbHash, &dwHashLen, 0);
    // Destroy the hash object.
    CryptDestroyHash(hHash);
    //
    // Compare the hash value received from the destination user with 
    // the hash value that we just computed. If they do not match, then 
    // terminate the protocol.
    //
    if(dwHashLen!=dwDestHashLen || memcmp(pbHash, pbDestHash, dwHashLen)) {
        printf("Key exchange protocol failed in phase 2!\n");
        printf("Aborting protocol!\n");
        return;
    }
    //
    // Compute hash to be sent to the destination user.
    //
    // Create hash object.
    CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash);
    // Add session key B to hash.
    CryptHashSessionKey(hHash, hKeyB, 0);
    // Add sending user's name to hash.
    CryptHashData(hHash, pbSendName, dwSendNameLen, 0);
    // Add destination user's name to hash.
    CryptHashData(hHash, pbDestName, dwDestNameLen, 0);
    // Add "phase 3" text to hash.
    CryptHashData(hHash, "phase 3", 7, 0);
    // Complete the hash computation and retrieve the hash value.
    dwHashLen = HASH_SIZE;
    CryptGetHashParam(hHash, HP_HASHVALUE, pbHash, &dwHashLen, 0);
    // Destroy the hash object.
    CryptDestroyHash(hHash);
    // Send the hash value to the destination user.
    ...
    //
    // Create a shared session key to be used by both users for
    // exchanging encrypted messages. Both users must agree on the 
    // algorithm and parameters that this key is to use.
    //
    // Create hash object.
    CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash);
    // Add session key A to hash.
    CryptHashSessionKey(hHash, hKeyA, 0);
    // Add session key B to hash.
    CryptHashSessionKey(hHash, hKeyB, 0);
    // Complete the hash computation and derive a session key from it. 
    // The CRYPT_EXPORTABLE flag is not specified here because the key 
    // usually is not exported out of the CSP.
    CryptDeriveKey(hProv, CALG_RC4, hHash, 0, &hSharedKey);
    // Destroy the hash object.
    CryptDestroyHash(hHash);
    //
    // Use the shared key to send encrypted messages to the other user.
    //
    ...
    // Destroy session key.
    CryptDestroyKey(hSharedKey);
    // Release provider handle.
    CryptReleaseContext(hProv, 0);
     
    

    Receiver Code Example

    This section illustrates the code needed on the destination user side to implement the three-phase key exchange protocol. The details of the communication between sending user and the destination user are not shown, because these will be different for each implementation.

    #include <wincrypt.h>
    HCRYPTPROV hProv = 0;
    #define NAME_SIZE 256
    BYTE pbDestName[NAME_SIZE];
    DWORD dwDestNameLen;
    BYTE pbSendName[NAME_SIZE];
    DWORD dwSendNameLen;
    HCRYPTKEY hSendPubKey = 0;
    HCRYPTKEY hSharedKey = 0;
    HCRYPTKEY hKeyA = 0;
    HCRYPTKEY hKeyB = 0;
    #define BLOB_SIZE 256
    BYTE pbKeyBlob[BLOB_SIZE];
    DWORD dwBlobLen;
    #define HASH_SIZE 256
    BYTE pbHash[HASH_SIZE];
    DWORD dwHashLen;
    BYTE pbSendHash[HASH_SIZE];
    DWORD dwSendHashLen;
    HCRYPTHASH hHash = 0;
    // Get handle to the default provider.
    CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0);
    // Obtain the sending user's exchange public key. Import it into the
    // CSP and place a handle to it in 'hSendPubKey'.
    ...
    // Obtain the sending user's name. This is usually done at the 
    // same time the public key was obtained. Place this in 
    // 'pbSendName' and set 'dwSendNameLen' to the number of bytes in 
    // the name.
    ...
    // Place the destination user's name in 'pbDestName' and set
    // 'dwDestNameLen' to the number of bytes in the name.
    ...
    // Receive a key blob containing session key A from the sending user
    // and place it in 'pbKeyBlob'. Set 'dwBlobLen' to the number of 
    // bytes in the key blob.
    ...
    // Import the key blob into the CSP.
    CryptImportKey(hProv, pbKeyBlob, dwBlobLen, 0, 0, &hKeyA);
    // Create a random session key (session key B). Because this key is
    // going to be used solely for key exchange and not encryption, it 
    // does not matter which algorithm you specify here.
    CryptGenKey(hProv, CALG_RC2, CRYPT_EXPORTABLE, &hKeyB);
    // Export session key B into a simple key blob.
    dwBlobLen = BLOB_SIZE;
    CryptExportKey(hKeyB, hSendPubKey, SIMPLEBLOB, 0, pbKeyBlob, &dwBlobLen);
    // Transmit key blob containing session key B to the sending user.
    ...
    //
    // Compute hash value and transmit it to the sending user.
    //
    // Create hash object.
    CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash);
    // Add session key A to hash.
    CryptHashSessionKey(hHash, hKeyA, 0);
    // Add destination user's name to hash.
    CryptHashData(hHash, pbDestName, dwDestNameLen, 0);
    // Add session key B to hash.
    CryptHashSessionKey(hHash, hKeyB, 0);
    // Add sending user name to hash.
    CryptHashData(hHash, pbSendName, dwSendNameLen, 0);
    // Add "phase 2" text to hash.
    CryptHashData(hHash, "phase 2", 7, 0);
    // Complete the hash computation and retrieve the hash value.
    dwHashLen = HASH_SIZE;
    CryptGetHashParam(hHash, HP_HASHVALUE, pbHash, &dwHashLen, 0);
    // Destroy the hash object.
    CryptDestroyHash(hHash);
    // Transmit the hash value to the sending user.
    ...
    // Wait for the sending user to respond.
    ...
    // Receive a hash value from the sending user and place it in
    // 'pbSendHashValue'. Set 'dwSendHashLen' to the number of bytes in
    // the hash value.
    ...
    //
    // Verify hash value received from the sending user.
    //
    // Create hash object.
    CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash);
    // Add session key B to hash.
    CryptHashSessionKey(hHash, hKeyB, 0);
    // Add sending user's name to hash.
    CryptHashData(hHash, pbSendName, dwSendNameLen, 0);
    // Add destination user's name to hash.
    CryptHashData(hHash, pbDestName, dwDestNameLen, 0);
    // Add "phase 3" text to hash.
    CryptHashData(hHash, "phase 3", 7, 0);
    // Complete the hash computation and retrieve the hash value.
    dwHashLen = HASH_SIZE;
    CryptGetHashParam(hHash, HP_HASHVALUE, pbHash, &dwHashLen, 0);
    // Destroy the hash object.
    CryptDestroyHash(hHash));
    //
    // Compare the hash value received from the sending user with the
    // hash value that we just computed. If they do not match, then 
    // terminate the protocol.
    //
    if(dwHashLen!=dwSendHashLen || memcmp(pbHash, pbSendHash, dwHashLen)) {
        printf("Key exchange protocol failed in phase 3!\n");
        printf("Aborting protocol!\n");
        return;
    }
    //
    // Create a shared session key to be used by the two users for
    // exchanging encrypted messages. Both users must agree on the 
    // algorithm and parameters that this key is to use.
    //
    // Create hash object.
    CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash);
    // Add session key A to hash.
    CryptHashSessionKey(hHash, hKeyA, 0);
    // Add session key B to hash.
    CryptHashSessionKey(hHash, hKeyB, 0);
    // Complete the hash computation and derive a session key from it. 
    // The CRYPT_EXPORTABLE flag is not specified here because the key 
    // is not generally exported out of the CSP.
    CryptDeriveKey(hProv, CALG_RC4, hHash, 0, &hSharedKey);
    // Destroy the hash object.
    CryptDestroyHash(hHash);
    //
    // Use the shared key to send encrypted messages to the other user.
    //
    ...
    // Destroy session key.
    CryptDestroyKey(hSharedKey);
    // Destroy handle to sending user's public key.
    CryptDestroyKey(hSharedKey);
    // Release provider handle.
    CryptReleaseContext(hProv, 0);
     
    

    CHAPTER 6

    Encrypting and Decrypting Data

    Encryption is the process in which data (plaintext) is translated into something that appears to be random and meaningless (ciphertext). Decryption is the process in which the ciphertext is converted back to plaintext.

    A symmetric encryption key (also known here as a session key) is used during both the encryption and decryption processes. In order to decrypt a particular piece of ciphertext, you must possess the key that was used to encrypt the data. Essentially, a session key merely consists of a random number, of approximately 40 to 2000 bits in length. The longer the key that is used, the more difficult it is to decrypt a piece of ciphertext without possessing the key.

    The goal of every encryption algorithm is to make it as difficult as possible to decrypt the generated ciphertext without using the key. If a really good encryption algorithm is used, then there is no technique significantly better than methodically trying every possible key. Even for a key size of just 40 bits, this works out to 240 (just over 1 trillion) possible keys.

    It is surprisingly difficult to determine just how good an encryption algorithm is. Algorithms that look promising sometimes turn out to be very easy to break, given the proper attack. When selecting an encryption algorithm, it is probably a good idea to choose one that has been around for a while, and successfully resisted all attacks thus far.

    Introduction to Encryption Techniques

    CryptoAPI can be used by applications to easily encrypt and decrypt messages and files. This section discusses the various options available for encrypting data. For a hands-on description of how to encrypt data using CryptoAPI, see "Encrypting Files and Messages" in this chapter.

    The encryption algorithms available to an application depend on the cryptographic service provider (CSP) being used. However, most CSPs share most of the attributes discussed here. All data encryption using CryptoAPI is performed with a symmetric algorithm, regardless of which CSP is installed.

    Stream Ciphers

    Stream cipher algorithms encrypt data one bit at a time. A stream of plaintext bits flows in one side, and a stream of encrypted ciphertext flows out the other. At least, this is the way it works mathematically; in practice, data is always encrypted in byte units.

    Stream ciphers are not generally considered as secure as block ciphers, although this will vary depending on the particular algorithm. On the other hand, they do tend to execute faster in software. Ciphertext encrypted with stream ciphers is always the same size as the original plaintext.

    Error propagation is usually less when stream ciphers are used. If a bit of ciphertext gets garbled, many stream cipher algorithms will produce only a single bit of garbled plaintext. When a block cipher is used and a ciphertext bit is garbled, at minimum an entire block's worth of plaintext will be garbled. This can be good or bad, depending on the application.

    The only stream cipher provided with the Microsoft RSA Base Provider is the RC4 stream cipher.

    Block Ciphers

    Block cipher algorithms encrypt data in block units, rather than a single bit at a time. The most common block size is 64 bits.

    Because each block is heavily "processed," block ciphers are generally considered more secure than stream ciphers. However, block cipher algorithms tend to execute quite a bit slower.

    All that the basic block encryption algorithm specifies is how to get a block of ciphertext from a block of plaintext and vice versa. All the other implementation details (for example, padding, initialization vectors, and cipher modes) are specified independently of the algorithm. These options are discussed in the next few sections.

    The only block cipher provided with the Microsoft RSA Base Provider is the RC2 block cipher. This algorithm has a block size of 64 bits.

    Padding

    Most plaintext messages will not consist of an even number of blocks. Often, the last block is short, making it necessary to add a padding string. For example, if the block length is 64 bits and the last block contains only 40 bits, then 24 bits of padding must be added.

    This padding string can consist of all zeros, alternating zeros and ones, or some other pattern. Some encryption standards specify a particular padding scheme, such as the one described in the next section.

    Applications using CryptoAPI need not add padding to their plaintext before it is encrypted, nor do they have to remove it after decrypting. This is all handled automatically by CryptoAPI.

    PKCS Padding

    This padding scheme is defined by RSA Data Security, Inc. and is documented in Public-Key Cryptography Standards (PKCS), PKCS #5, section 6.2.

    When this method is used, a padding string is always added, even if the plaintext message divides evenly into blocks. The padding string consists of a sequence of bytes, each of which is equal to the total number of bytes in the padding string. If 24 bits of padding need to be added, then the padding string is "03 03 03." If 64 bits of padding needs to be added, then the string is "08 08 08 08 08 08 08 08."

    Cipher Modes

    When a block cipher is used, any one of the following cipher modes can be specified via the CryptSetKeyParam function. If the application does not explicitly specify one of these modes, then the cipher block chaining (CBC) cipher mode is used.

    Electronic Codebook (ECB)

    When this cipher mode is used, each block is encrypted individually. No feedback is used. This means any blocks of plaintext that are identical and are either in the same message, or in a different message that is encrypted with the same key, will be transformed into identical ciphertext blocks.

    If the plaintext to be encrypted contains substantial repetition, then it is feasible for the ciphertext to be broken one block at a time. Furthermore, it is possible for an unscrupulous person to substitute and exchange individual blocks without detection.

    Initialization vectors cannot be used with this cipher mode.

    If a single bit of the ciphertext block is garbled, then the entire corresponding plaintext block will also be garbled.

    Cipher Block Chaining (CBC)

    This cipher mode introduces feedback. Before each plaintext block is encrypted, it is XOR'ed with the ciphertext of the previous block. This ensures that even if the plaintext contains many identical blocks, they will each encrypt to a different ciphertext block.

    The initialization vector is XOR'ed with the first plaintext block before the block is encrypted.

    As with the Codebook cipher mode, if a single bit of the ciphertext block is garbled, then the corresponding plaintext block will also be garbled. In addition, a bit in the subsequent plaintext block (in the same position as the original garbled bit) will be garbled. Synchronization errors are fatal. If there are extra or missing bytes in the ciphertext, the plaintext will be garbled from that point on.

    When the Microsoft RSA Base Provider is used, this is the default cipher mode.

    Cipher Feedback Mode (CFB)

    The cipher feedback mode lets you process small increments of plaintext into ciphertext, instead of processing an entire block at a time. This can be is useful, for example, when encrypting a stream of data that originates at a keyboard. Each keystroke can be encrypted and transmitted without the need to wait for an entire block to be typed.

    This mode uses a shift register which is one block size in length and divided up into sections. For example, if the block size is 64 bits with 8 bits processed at a time, then the shift register would be divided up into 8 sections.

    This is the procedure for each encryption cycle:

    1. The block in the shift register is encrypted normally.

    2. The leftmost 8 bits in the encrypted shift register are XOR'ed with the next 8 bits of plaintext and sent off as 8 bits of ciphertext.

    3. The shift register is shifted 8 bits to the left.

    4. The 8 bits of ciphertext generated in step 2 is placed in the rightmost 8 bits of the shift register.

    In CryptoAPI, the number of bits processed at one time is specified by setting the encryption key's KP_MODE_BITS parameter using the CryptSetKeyParam function. This parameter typically defaults to 8.

    Depending on the value of the KP_MODE_BITS parameter, this cipher mode is substantially slower than the Cipher Block Chaining mode. For example, if the block size is 64 bits with 8 bits are processed at a time, this cipher mode is 64/8 or 8 times slower.

    Before the encryption process begins, the shift register is filled with the initialization vector.

    If a bit in the cipher text is garbled, one plaintext bit is garbled and the shift register is corrupted. This results in the next several plaintext blocks being garbled until the bad bit is shifted out of the shift register. In the preceding example, 9 bytes of plaintext would be garbled. This is the same amount of error propagation as with the Cipher Block Chaining mode. Synchronization errors are not fatal, provided that the slip is a multiple of KP_MODE_BITS. Thus, if KP_MODE_BITS is 8 and there are extra or missing bytes from the ciphertext, then 9 bytes of plaintext are garbled and the plaintext will have the same number of extra or missing bytes.

    Output Feedback Mode (OFB)

    This mode is similar to the cipher feedback mode. The only difference between the two modes is how the shift register is filled.

    The output feedback (OFB) cipher mode uses the following encryption cycle:

    1. The block in the shift register is encrypted normally.

    2. The leftmost 8 bits in the encrypted shift register are XOR'ed with the next 8 bits of plaintext and sent off as 8 bits of ciphertext.

    3. The shift register is shifted 8 bits to the left.

    4. The leftmost 8 bits of the encrypted shift register used in step 2 is placed in the rightmost 8 bits of the shift register.

    As with the Cipher Feedback mode, the shift register is filled with the initialization vector before the encryption process starts.

    If a bit in the cipher text is garbled, the corresponding bit of plaintext will also be garbled. This is much better than the Cipher Feedback mode. However, synchronization errors are fatal. If there are extra or missing bits from the ciphertext, then the plaintext will be garbled from that point on.


    Note

    According to Gait (see reference below), the OFB block cipher mode has a weakness when the number of bits fed back is different than the block size. It is thus recommended that the KP_MODE_BITS parameter be set to the block size when this cipher mode is used.

    *J. Gait, "A New Nonlinear Pseudorandom Number Generator," IEEE Transactions on Software Engineering, v. SE-3, n. 5, Sep 1977, pp. 359-363.

    Initialization Vectors

    An initialization vector is a random number, usually the same number of bits as the block size, that is used as a starting point when encrypting a set of data. Initialization vectors are only used with those cipher modes that make use of feedback. This ensures that the effect of the initialization vector is propagated throughout the entire plaintext message being encrypted.

    If initialization vectors are not used, then when two identical plaintext messages are encrypted with the same key, two identical ciphertext messages are generated. However, if each plaintext message is encrypted with a different initialization vector, the ciphertext messages generated are completely different.

    You should always encrypt each message with a different initialization vector, particularly when the messages contain a large amount of duplication.

    Applications using CryptoAPI are responsible for transmitting the initialization vector along with the encrypted message. There is no need to encrypt this vector.

    Salt Values

    Salt values make up a portion of many session keys, as shown.

    Structure of a session key.

    As with the key bits, the salt bits also consist of random data. The difference is that the key bits must be kept secret at all costs, while the salt values are made public. When exchanging keys using the CryptoAPI, the key bits are transmitted inside of encrypted key blobs. The salt bits, on the other hand, are transmitted in plaintext form.

    The size of the salt values will vary, depending on the CSP used. For example, the Microsoft RSA Base Provider uses salt values of 88 bits and key values of 40 bits, for a total key size of 128 bits. Even though the salt bits make up part of each encryption key, they are usually ignored when discussing keys and key sizes. That is, when talking about Microsoft RSA Base Provider encryption keys, we refer to them as 40 bit keys.

    Salt values are most useful when transmitting or storing large amounts of nearly identical packets using the same encryption key. Normally, two identical packets would encrypt into two identical ciphertext packets. However, this would indicate to an eavesdropper that the packets are identical and, thus, could be attacked simultaneously. But, if the salt value is changed with every packet sent, then a completely different ciphertext packet will always be generated, even if the plaintext packets are the same.

    Because salt values need not be kept secret and can be transmitted in plaintext form bundled with each ciphertext packet, it is much easier to change salt values once per packet than it would be to change the key value itself.

    Applications should generate salt values with the CryptGenRandom function. It is important that each salt value be completely different than the other ones, particularly when using stream ciphers.

    Common Encryption Algorithms

    This section briefly describes each of the encryption algorithms supplied with the Microsoft RSA Base Provider. The internal details of these algorithms are well beyond the scope of this document. Refer to "Related Documentation" at the beginning of this guide for a list of additional reading material.

    The following table lists several encryption algorithms along with some performance benchmarks. This table was generated by an application using CryptoAPI on a 120-MHz, Pentium-based computer. These figures are for comparison purposes only, your mileage may vary.

    Cipher    Cipher Type    Key Setup Time    Encryption Speed  
                             (microseconds)    (bytes/second)    
    
                                                                 
    
    DES       64-bit block   460               1,138,519         
    
    RC2       64-bit block   40                286,888           
    
    RC4       stream         151               2,377,723         
    
    
    

    RC2 Block Cipher

    The RC2 block cipher algorithm was developed by RSA Data Security, Inc. The details of this algorithm have not been published.

    RC2 is a variable-key-length cipher. However, when using CryptoAPI with the Microsoft RSA Base Provider, the key length is hard-coded to 40 bits. The block size is fixed at 64 bits.

    RC4 Stream Cipher

    The RC4 stream cipher was developed by RSA Data Security, Inc. The details of this algorithm have not been published.

    RC4 is a variable-key-length cipher. However, when using CryptoAPI with the Microsoft RSA Base Provider, the key length is hard-coded to 40 bits.

    RSA Public-Key Cipher

    The RSA public-key cipher was developed by (and named after) Ron Rivest, Adi Shamir, and Leonard Adleman, in the late 1970's. This algorithm is very well known; you can read about its internal details in any book on cryptography.

    RSA is used by many CSPs to encrypt/decrypt keys and to generate/verify digital signatures. This algorithm is used when operations are performed using either the key exchange or digital signature key pair. When using CryptoAPI, this algorithm cannot be used to encrypt bulk data.

    RSA is a variable-key-length cipher. However, when using CryptoAPI with the Microsoft RSA Base Provider, the key length is hard-coded to 512 bits.

    Encrypting Files and Messages

    To encrypt a file so only the current user can access its data, the file is bulk encrypted with a symmetric cipher. The key to this cipher is then kept in an access block (key blob) that can only be opened with the user's private key. Note that this technique also works for encrypting messages for specific recipients.

    Encrypting Messages Using CryptoAPI

    To encrypt a message, a session key must first be generated using the CryptGenKey function. Making this call generates a random key and returns a handle so the key can be used to encrypt and decrypt data. The encryption algorithm to use is also specified at this point. Because the CryptoAPI does not permit applications to use public-key algorithms to encrypt bulk data, you should specify a symmetric algorithm such as RC2 or RC4, with the CryptGenKey call.

    Alternatively, if an application needs to encrypt the message in such a way that anyone with a given password can decrypt the data, the CryptDeriveKey function should be used to transform the password into a key suitable for encryption. Note that, in this case, this function is called instead of the CryptGenKey function and the subsequent CryptExportKey calls are not needed.

    Once the key has been generated, extra cryptographic properties of the key can be set with the CryptSetKeyParam function. For example, this function allows different sections of the file to be encrypted with different key salts and provides a way to change the cipher mode or initialization vector of the key. These parameters can be used to make the encryption conform with a particular data encryption standard.

    Encrypt the data in the file with the CryptEncrypt function. The CryptEncrypt function takes a session key, which was generated in the previous step, and encrypts a buffer of data. Note that as the data is encrypted, the data may be slightly expanded by the encryption algorithm. The application is responsible for remembering the length of the encrypted data so the proper length can later be given to the CryptDecrypt function.

    To allow the current user to decrypt the data in the future, the CryptExportKey function is used to save the decryption key in an encrypted form (a key blob) that can only be decrypted with the user's private key. This function requires the user's key exchange public key for this purpose, which can be obtained by using the CryptGetUserKey function. The CryptExportKey function will return a key blob that must be stored by the application for use in decrypting the file.

    Note that if the application has certificates (or public keys) for other users, it can permit other users to decrypt the file by performing CryptExportKey calls for each user it wants to give access. The returned key blobs must be stored by the application, as in the previous step.

    Structure of an Encrypted File

    There are a number of standard formats for encrypted files and messages. These are designed to make it easier for different applications to communicate. An explanation of these formats falls outside the scope of this document. Refer to "Related Documentation" at the beginning of this guide for a list of additional reading material.

    Once a file or message has been encrypted, the following data must be stored by the application and is usually kept bundled together. This is the data:

    The encrypted data. When a block cipher is used, the data is padded out to a multiple of the cipher's block size. Padding is often added even when the original message is already an even multiple. When a stream cipher is used, the encrypted data is generally the same size as the original plaintext.

    One or more key blobs, each containing the session key used to encrypt the message. Each of these key blobs is encrypted with the key exchange public key of a user who is to later decrypt the data. Note that these are not stored if the key was derived from a password. Instead, when it is time to decrypt the message, the session key is recreated from the password. The password itself must be remembered by the user, of course.

    Any salt values that were specified as the data was being encrypted. When the data is decrypted, these values will have to be specified (using the CryptSetKeyParam function) in the same manner as when the data was encrypted.

    Any initialization vectors that were specified as the data was being encrypted. These values are handled in much the same way as the salts.

    All parameters that were specified with the CryptSetKeyParam function as the message was being encrypted must also be specified as the message is decrypted. It may be appropriate to store some of these parameters with the encrypted message as well.

    Encryption Example

    This example reads data from a text file (test1.txt), encrypts it using the RC2 block cipher, and writes out the encrypted data to another file (test1.xxx). A random session key is generated to perform the encryption and is stored to the output file along with the encrypted data. Note that this session key is encrypted with our own public key exchange key by the CryptExportKey function.

    #include <wincrypt.h>
    FILE *hSource = NULL;
    FILE *hDest = NULL;
    int eof = 0;
    HCRYPTPROV hProv = 0;
    HCRYPTKEY hKey = 0;
    HCRYPTKEY hXchgKey = 0;
    #define BLOCK_SIZE 160
    #define BUFFER_SIZE (BLOCK_SIZE+16) // Give buffer 16 bytes of extra
                                        // room for padding, etc.
    BYTE pbBuffer[BUFFER_SIZE];
    DWORD dwCount;
    BYTE *pbKeyBlob = NULL;
    DWORD dwBlobLen;
    // Open source file.
    if((hSource=fopen("test1.txt","rb"))==NULL) {
        printf("Error opening source file!\n");
        goto done;
    }
    // Open destination file.
    if((hDest=fopen("test1.xxx","wb"))==NULL) {
        printf("Error opening destination file!\n");
        goto done;
    }
    // Get handle to the default provider.
    if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
        printf("Error %x during CryptAcquireContext!\n", GetLastError());
        goto done;
    }
    // Get handle to key exchange key.
    if(!CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hXchgKey)) {
        printf("Error %x during CryptGetUserKey!\n", GetLastError());
        goto done;
    }
    // Create a random block cipher session key.
    if(!CryptGenKey(hProv, CALG_RC2, CRYPT_EXPORTABLE, &hKey)) {
        printf("Error %x during CryptGenKey!\n", GetLastError());
        goto done;
    }
    // Determine size of key blob and allocate memory.
    if(!CryptExportKey(hKey, hXchgKey, SIMPLEBLOB, 0, NULL, &dwBlobLen)) {
        printf("Error %x computing blob length!\n", GetLastError());
        goto done;
    }
    if((pbKeyBlob = malloc(dwBlobLen)) == NULL) {
        printf("Out of memory!\n");
        goto done;
    }
    // Export key into a simple key blob.
    if(!CryptExportKey(hKey, hXchgKey, SIMPLEBLOB, 0, pbKeyBlob, &dwBlobLen)) {
        printf("Error %x during CryptExportKey!\n", GetLastError());
        free(pbKeyBlob);
        goto done;
    }
    // Write size of key blob to destination file.
    fwrite(&dwBlobLen, sizeof(DWORD), 1, hDest);
    if(ferror(hDest)) {
        printf("Error writing header!\n");
        free(pbKeyBlob);
        goto done;
    }
    // Write key blob to destination file.
    fwrite(pbKeyBlob, 1, dwBlobLen, hDest);
    if(ferror(hDest)) {
        printf("Error writing header!\n");
        free(pbKeyBlob);
        goto done;
    }
    // Free memory.
    free(pbKeyBlob);
    // Encrypt source file and write to destination file.
    do {
        // Read up to BLOCK_SIZE bytes from source file.
        dwCount = fread(pbBuffer, 1, BLOCK_SIZE, hSource);
        if(ferror(hSource)) {
            printf("Error reading data!\n");
            goto done;
        }
        eof=feof(hSource);
        // Encrypt data
        if(!CryptEncrypt(hKey, 0, eof, 0, pbBuffer, &dwCount, BUFFER_SIZE)) {
            printf("Error %x during CryptEncrypt!\n", GetLastError());
            goto done;
        }
        // Write data to destination file.
        fwrite(pbBuffer, 1, dwCount, hDest);
        if(ferror(hDest)) {
            printf("Error writing data!\n");
            goto done;
        }
    } while(!feof(hSource));
    done:
    // Destroy session key.
    if(hKey != 0) CryptDestroyKey(hKey);
    // Destroy key exchange key.
    if(hXchgKey != 0) CryptDestroyKey(hXchgKey);
    // Release provider handle.
    if(hProv != 0) CryptReleaseContext(hProv, 0);
    // Close source file.
    if(hSource != NULL) fclose(hSource);
    // Close destination file.
    if(hDest != NULL) fclose(hDest);
     
    

    Decrypting Messages Using CryptoAPI

    If a message was encrypted for a particular user, then the CryptGenKey function was used to create a random session key, before the encryption was performed. This means that before the message can be decrypted, the key blob containing the session key needs to be imported into the CSP with the CryptImportKey function. This function will use your key exchange private key to decrypt the key blob. This means that the key blob must have been originally created using the matching key exchange public key.

    If the message was encrypted so that any password holder can access the data, the CryptImportKey function is not used. Instead, you create the decryption session key with the CryptDeriveKey function. You will also need to supply the function with the password (or other access token).

    The session key's parameters need to be configured in the same way as when the encryption was performed. These parameters can be specified using the CryptSetKeyParam function. For example, if the salt value was changed one or more times during the encryption process, then it must also be changed during the decryption process in exactly the same manner.

    The message is decrypted using the CryptDecrypt function. If the message is too large to fit comfortably in memory, it can be decrypted in sections, through multiple calls to CryptDecrypt.

    When the decryption is complete, be sure to destroy the session key, using the CryptDestroyKey function. In addition to destroying the key, this will free up CSP resources.

    Decryption Example

    This example reads the encrypted data from the file created by the "Encryption Example" (test1.xxx), decrypts it using the RC2 block cipher, and writes out the plaintext data to another file (test1.txt). The session key used to perform the decryption is read from the ciphertext file.

    #include <wincrypt.h>
    FILE *hSource = NULL;
    FILE *hDest = NULL;
    int eof = 0;
    HCRYPTPROV hProv = 0;
    HCRYPTKEY hKey = 0;
    #define BLOCK_SIZE 160
    BYTE pbBuffer[BLOCK_SIZE];
    DWORD dwCount;
    BYTE *pbKeyBlob = NULL;
    DWORD dwBlobLen;
    // Open source file.
    if((hSource=fopen("test1.xxx","rb"))==NULL) {
        printf("Error opening source file!\n");
        goto done;
    }
    // Open destination file.
    if((hDest=fopen("test1.txt","wb"))==NULL) {
        printf("Error opening destination file!\n");
        goto done;
    }
    // Get handle to the default provider.
    if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
        printf("Error %x during CryptAcquireContext!\n", GetLastError());
        goto done;
    }
    // Read key blob length from source file and allocate memory.
    fread(&dwBlobLen, sizeof(DWORD), 1, hSource);
    if(ferror(hSource) || feof(hSource)) {
        printf("Error reading file header!\n");
        goto done;
    }
    if((pbKeyBlob = malloc(dwBlobLen)) == NULL) {
        printf("Out of memory!\n");
        goto done;
    }
    // Read key blob from source file.
    fread(pbKeyBlob, 1, dwBlobLen, hSource);
    if(ferror(hSource) || feof(hSource)) {
        printf("Error reading file header!\n");
        goto done;
    }
    // Import key blob into CSP.
    if(!CryptImportKey(hProv, pbKeyBlob, dwBlobLen, 0, 0, &hKey)) {
        printf("Error %x during CryptImportKey!\n", GetLastError());
        goto done;
    }
    // Decrypt source file and write to destination file.
    do {
        // Read up to BLOCK_SIZE bytes from source file.
        dwCount = fread(pbBuffer, 1, BLOCK_SIZE, hSource);
        if(ferror(hSource)) {
            printf("Error reading data from source file!\n");
            goto done;
        }
        eof=feof(hSource);
        // Decrypt data.
        if(!CryptDecrypt(hKey, 0, eof, 0, pbBuffer, &dwCount)) {
            printf("Error %x during CryptDecrypt!\n", GetLastError());
            goto done;
        }
        // Write data to destination file.
        fwrite(pbBuffer, 1, dwCount, hDest);
        if(ferror(hDest)) {
            printf("Error writing data to destination file!\n");
            goto done;
        }
    } while(!feof(hSource));
    done:
    // Free memory.
    if(pbKeyBlob) free(pbKeyBlob);
    // Destroy session key.
    if(hKey != 0) CryptDestroyKey(hKey);
    // Release provider handle.
    if(hProv != 0) CryptReleaseContext(hProv, 0);
    // Close source file.
    if(hSource != NULL) fclose(hSource);
    // Close destination file.
    if(hDest != NULL) fclose(hDest);
     
    

    Encrypting and Decrypting Simultaneously

    When encrypting or decrypting two streams of data simultaneously with the same cryptographic key, a certain amount of care must be taken. The same physical session key must not be used for both operations, because every session key contains internal state information and it will get mixed up if used for more than one operation at a time. A fairly simple solution to this problem is to make a copy of the session key. In this way, the original key can be used for one operation and the copy used for the other.

    Copying a session key is done by exporting the key with CryptExportKey and then using CryptImportKey to import it back in. When the key is imported, the CSP will give the "new" key its own section of internal memory, as if it were not related at all to the original key.

    The following code fragment shows how a copy of a session key can be obtained.

    HCRYPTPROV hProv;    // Handle to a CSP.
    HCRYPTKEY hKey;      // Handle to a session key.
    HCRYPTKEY hCopyKey = 0;
    HCRYPTKEY hPubKey = 0;
    BYTE pbBlob[256];
    DWORD dwBlobLen;
    // Get a handle to our own key exchange public key.
    CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hPubKey);
    // Export the session key into a key blob.
    dwBlobLen = 256;
    CryptExportKey(hKey, hPubKey, SIMPLEBLOB, 0, pbBlob, &dwBlobLen);
    // Import the session key back into the CSP. This is stored separately
    // from the original session key.
    CryptImportKey(hProv, pbBlob, dwBlobLen, 0, 0, &hCopyKey);
    // Use 'hKey' for one set of operations and 'hCopyKey' for the other.
    ...
     
    

    Note that this technique should not be used with stream ciphers, as stream cipher keys should never be used more than once. Instead, separate transmit and receive keys should be used.

    CHAPTER 7

    Hashes and Digital Signatures

    Using the functions described in this section, a user can "digitally sign" a piece of data such that any other user can easily verify that the data has not been changed since it was signed. The identity of the user that signed the data can also be easily verified.

    A digital signature consists of a small amount of binary data, typically less than 256 bytes. This signature can be bundled with the signed message or stored separately; this is up to the individual application.

    The Microsoft RSA Base Provider creates digital signatures that conform to the RSA Public-Key Cryptography Standard (PKCS) #6.

    How Digital Signatures Work

    There are two steps involved in creating a digital signature from a message. The first step involves creating a hash value (also known as a message digest) from the message. This hash value is then signed, using the private key of the signer. Following is an illustration of the steps involved in creating a digital signature:

    Creating a Digital Signature

    To verify a signature, both the message and the signature are required. First, a hash value must be created from the message, in the same way as when the signature was created. This hash value is then verified against the signature, using the public key of the signer. If the hash value and the signature match, you can be confident that the message is indeed the one the signer originally signed and that it has not been tampered with. The following diagram illustrates the process involved in verifying a digital signature.

    Verifying a Digital Signature

    A hash value consists of a small amount of binary data, typically around 160 bits. This is produced using a hashing algorithm. A number of these algorithms are listed later in this section.

    All hash values share the following properties, regardless of the algorithm used:

    The hash value is of a fixed length, regardless of the size of the message. The message can be several kilobytes or several gigabytes, it doesn't matter. Depending on the algorithm used, the hash value length will generally be either 128 or 160 bits.

    Every pair of nonidentical messages will translate into a completely different hash value, even if the two messages differ only by a single bit. Using today's technology, it is not feasible to discover a pair of messages that translate to the same hash value without breaking the hashing algorithm.

    All hashing algorithms are fully deterministic. That is, each time a particular message is hashed using the same algorithm, the exact same hash value will be produced.

    All hashing algorithms are one-way. Given a hash value, it is not possible to recover the original message. In fact, none of the properties of the original message can be determined given the hash value alone.

    Signing and Verifying Messages

    To apply a digital signature to a piece of data, a secure hash function is used to build a digest of the data (for example, a 160-bit hash value) which is then transformed with the private key of the signer. Other users can then check the authenticity of the signature by reconstructing the hash value, and checking it against the "inverse" of the digital signature data. CryptoAPI abstracts out the actual method of doing the signature, so that applications need not be aware of the signature mechanics.

    Signing Data

    In order to sign data, a hash object must first be created using the CryptCreateHash function. This object will accumulate the data to be signed. Next, the data is added to the hash object with the CryptHashData function.

    After the last block of data is added to the hash, the CryptSignHash function is used to sign the hash. A description of the data can also be added to the hash object at this point. Once the digital signature data has been obtained, the hash object should be destroyed with the CryptDestroyHash function.

    Hashes can be signed with either the signature private key or the key exchange private key. The signature key should be used when the user who owns the signature key is signing some of his or her data. The key exchange key should be used when signing data that does not directly belong to the user. The classic example of this is when the exchange key is used to sign session keys during a key exchange protocol.

    Verifying Signatures

    To verify a signature, a hash object must first be created using the CryptCreateHash function. This object will accumulate the data to be verified. The data is then added to the hash object with the CryptHashData function.

    After the last block of data is added to the hash, the CryptVerifySignature function is used to verify the signature. The signature data, a handle to the hash object, and the description string must all be supplied to CryptVerifySignature. A handle to the key pair that was used to sign the data must also be specified.

    Once the signature has been verified (or has failed the verification) the hash object should be destroyed with the CryptDestroyHash function.

    Obtaining the Hash Value

    To obtain the hash value, a hash object must first be created using the CryptCreateHash function. This object will accumulate the data to be verified. The data is then added to the hash object with the CryptHashData function.

    After the last block of data is added to the hash, the CryptGetHashParam function is used to obtain the hash value.

    Once the hash value has been obtained, the hash object should be destroyed with the CryptDestroyHash function.

    Hashing and Signature Algorithms

    This section lists several algorithms used to compute hashes and digital signatures. Each of these algorithms is supported by the Microsoft RSA Base Provider. However, the internal details of these algorithms are well beyond the scope of this document. Refer to "Related Documentation" at the beginning of this guide for a list of additional sources.

    MD2, MD4, and MD5

    The MD2, MD4, and MD5 hashing algorithms were all developed by RSA Data Security, Inc. These algorithms were developed in sequential order, with the later algorithms generally being better (more secure) than the earlier ones. All three generate 128-bit hash values. Of the three algorithms, MD5 is recommended.

    These algorithms are well known and can be reviewed in detail in any reference on cryptography.

    Secure Hash Algorithm (SHA)

    The SHA hashing algorithm was developed by the National Institute of Standards and Technology (NIST) and by the National Security Agency (NSA). This algorithm was developed for use with DSA (Digital Signature Algorithm) or DSS (Digital Signature Standard).

    This algorithm generates a 160-bit hash value.

    Message Authentication Code (MAC)

    Message Authentication Codes (MACs) are similar to hash values, but are computed using a session key. Because of this difference, you must possess the session key in order to recompute the hash value to verify that the base data has not changed.

    The MACs implemented by the Microsoft RSA Base Provider are of the most common sort. That is, they are block cipher MACs. This method encrypts the base data with a block cipher and then uses the last encrypted block as the hash value. The encryption algorithm used to build the MAC is the one that was specified when the session key was created.


    Warning

    The same session key should not be used for both message encryption and MAC generation. Doing so greatly increases the risk of your messages being decoded.

    CHAPTER 8

    System Administration

    This section discusses how multiple cryptographic service providers (CSPs) can be installed on a computer and the default providers specified. The structure of the system Registry is also mentioned.

    Installing a New Provider

    New providers are installed by running their Setup program. This copies the CSP files to the appropriate directories and makes all needed changes to the system Registry.

    Outline of CryptoAPI Registry Usage

    CryptoAPI uses the system Registry to store a database of the CSPs that have been installed on the computer. Both the machine default providers and the user default providers are also recorded here.


    Warning

    This section is included for informational purposes only. The details of CryptoAPI's Registry usage may change at any time. Under no circumstances should an application read from or alter the Registry directly.

    The following is a partial outline of the portions of the system Registry used by CryptoAPI. Some sample entries are also shown.

    HKEY_LOCAL_MACHINE
    SOFTWARE
    Microsoft
    Cryptography
    Defaults
    Provider
    Microsoft Base Cryptographic Provider v1.0
    >Image Path:REG_SZ:rsabase.dll
    >Signature:REG_BINARY:<digital signature>
    >Type:REG_DWORD:0x1
    John's Provider
    >Image Path:REG_SZ:johncsp.dll
    >Signature:REG_BINARY:<digital signature>
    >Type:REG_DWORD:0x2a
    Provider Types
    Type 001
    >Name:REG_SZ:Microsoft Base Cryptographic Provider v1.0
    Type 042
    >Name:REG_SZ:John's Provider

    HKEY_CURRENT_USER
    Software
    Microsoft
    Cryptography
    Providers
    Type 001
    >Name:REG_SZ:Microsoft Base Cryptographic Provider v1.0

    Entries under the HKEY_LOCAL_MACHINE\...\Provider key contain information about all the CSPs that have been installed on the computer. These entries are created by the Setup program used to install a new CSP. Note that these entries are organized under subkeys whose names indicate the provider name.

    Entries under the HKEY_LOCAL_MACHINE\...\Provider Types key contain the name of the machine default CSP for each provider type. These entries are also created by the Setup program used to install a new CSP. Note that these entries are organized under subkeys whose names indicate the provider type (in decimal format).

    Entries under the HKEY_CURRENT_USER\...\Providers key contain the name of the current user default CSP for each provider type. These entries are created/modified by the CryptSetProvider function. Note that these entries are also organized under subkeys whose names indicate the provider type.

    CHAPTER 9

    Service Provider Functions

    The functions described in this section are used by applications to connect to and disconnect from cryptographic service providers (CSPs). The following table briefly describes each function:

    Function            Description                            
    
                                                               
    
    CryptAcquireContext Acquires a handle to the current       
                        user's key container within a          
                        particular CSP.                        
    
    CryptGetProvParam   Retrieves attributes of a CSP.         
    
    CryptReleaseContext Releases the handle acquired by        
                        CryptAcquireContext.                   
    
    CryptSetProvider    Specifies the user default CSP for a   
                        particular CSP type.                   
    
    CryptSetProvParam   Specifies attributes of a CSP.         
    
    
    


    CryptAcquireContext

    The CryptAcquireContext function is used to acquire a handle to a particular key container within a particular CSP. This returned handle can then be used to make calls to the selected CSP.

    This function performs two operations. It first attempts to find a CSP with the characteristics described in the dwProvType and pszProvider parameters. If the CSP is found, then the function attempts to find a key container within the CSP matching the name specified by the pszContainer parameter.

    This function can also be used to create and destroy key containers, depending on the value of the dwFlags parameter.

    BOOL CRYPTFUNC CryptAcquireContext(
    HCRYPTPROV *
    phProv, // out
    LPCTSTR pszContainer, // in
    LPCTSTR pszProvider, // in
    DWORD dwProvType, // in
    DWORD dwFlags) // in

    Parameters

    phProv

    The address to which the function copies a handle to the CSP.

    pszContainer

    The key container name. This is a zero-terminated string that identifies the key container to the CSP. This name is independent of the method used to store the keys. Some CSPs will store their key containers internally (in hardware), some will use the system Registry, and others will use the file system.

    If this parameter is NULL, then a default key container name will be used. For example, if the Microsoft RSA Base Provider is being used, then the current user's logon name will be used as the name of the key container. Other CSPs may also have default key containers that can be acquired in this way.

    An application can obtain the name of the acquired key container at a later time by reading the PP_CONTAINER parameter from the CryptGetProvParam function.

    pszProvider

    The provider name. This is a zero-terminated string that specifies the CSP to be used.

    If this parameter is NULL then the user default provider is used. This situation is discussed in detail in Chapter 3.

    An application can obtain the name of the acquired CSP at a later time by reading the PP_NAME parameter from the CryptGetProvParam function.

    dwProvType

    The type of provider to acquire. The following provider types are predefined. These are discussed in detail in Chapter 3.

    PROV_RSA_FULL

    PROV_RSA_SIG

    PROV_DSS

    PROV_FORTEZZA

    PROV_MS_MAIL

    dwFlags

    The flag values. This parameter is normally set to zero, but some applications will set one (and only one) of the following flags:

    CRYPT_VERIFYCONTEXT

    If this flag is set, then the application will have no access to the key container's private keys. In fact, if pszContainer is NULL and no default key container is present, the application will have no access to a key container at all.

    This option is intended to be used by applications whose only cryptographic need is to verify digital signatures. The only operations normally needed in this case are public key import, hashing, and signature verification.

    When CryptAcquireContext is called, many CSPs will require input from the owning user before granting access to the private keys in the key container. For example, the private keys may be encrypted, requiring a password from the user before they can be used. However, if the CRYPT_VERIFYCONTEXT flag is specified, access to the private keys is not required and the user interface can be bypassed.

    CRYPT_NEWKEYSET

    If this flag is set, then a new key container will be created with the name specified by pszContainer. If pszContainer is NULL, then a key container with the default name will be created.

    Note that when key containers are created, most CSPs will not automatically create any public/private key pairs. These keys must be created as a separate step with the CryptGenKey function.


    Important

    This flag should only be set by administrative applications. Normal applications should not create key containers.

    CRYPT_DELETEKEYSET

    If this flag is set, then the key container specified by pszContainer is deleted. If pszContainer is NULL, then the key container with the default name is deleted. All key pairs in the key container are also destroyed.

    When the CRYPT_DELETEKEYSET flag is set, the value returned in phProv is undefined and, thus, the CryptReleaseContext function need not be called afterwards.


    Important

    This flag should only be set by administrative applications. Normal applications should not destroy key containers.

    Return Value

    If the function succeeds, the return value is TRUE. If it does not succeed, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

    The following table lists the error codes most commonly returned by the GetLastError function.

    Error                       Description                    
    
                                                               
    
    ERROR_INVALID_PARAMETER     One of the parameters          
                                contains an invalid value.     
                                This is most often an illegal  
                                pointer.                       
    
    ERROR_NOT_ENOUGH_MEMORY     The operating system ran out   
                                of memory during the           
                                operation.                     
    
    NTE_BAD_FLAGS               The dwFlags parameter has an   
                                illegal value.                 
    
    NTE_BAD_KEYSET              The Registry entry for the     
                                key container could not be     
                                opened and may not exist.      
    
    NTE_BAD_KEYSET_PARAM        The pszContainer or            
                                pszProvider parameter is set   
                                to an illegal value.           
    
    NTE_BAD_PROV_TYPE           The value of the dwProvType    
                                parameter is out of range.     
                                All provider types must be     
                                from 1 to 999, inclusive.      
    
    NTE_BAD_SIGNATURE           The provider DLL signature     
                                did not verify correctly.      
                                Either the DLL or the digital  
                                signature has been tampered    
                                with.                          
    
    NTE_EXISTS                  The dwFlags parameter is       
                                CRYPT_NEWKEYSET, but the key   
                                container already exists.      
    
    NTE_KEYSET_ENTRY_BAD        The Registry entry for the     
                                pszContainer key container     
                                was found (in the              
                                HKEY_CURRENT_USER window),     
                                but is corrupt. See Chapter 8  
                                for details about CryptoAPI's  
                                Registry usage.                
    
    NTE_KEYSET_NOT_DEF          No Registry entry exists in    
                                the HKEY_CURRENT_USER window   
                                for the key container          
                                specified by pszContainer.     
    
    NTE_NO_MEMORY               The CSP ran out of memory      
                                during the operation.          
    
    NTE_PROV_DLL_NOT_FOUND      The provider DLL file does     
                                not exist or is not on the     
                                current path.                  
    
    NTE_PROV_TYPE_ENTRY_BAD     The Registry entry for the     
                                provider type specified by     
                                dwProvType is corrupt. This    
                                error may relate to either     
                                the user default CSP list or   
                                the machine default CSP list.  
                                See Chapter 8 for details      
                                about CryptoAPI's Registry     
                                usage.                         
    
    NTE_PROV_TYPE_NO_MATCH      The provider type specified    
                                by dwProvType does not match   
                                the provider type found in     
                                the Registry. Note that this   
                                error can only occur when      
                                pszProvider specifies an       
                                actual CSP name.               
    
    NTE_PROV_TYPE_NOT_DEF       No Registry entry exists for   
                                the provider type specified    
                                by dwProvType.                 
    
    NTE_PROVIDER_DLL_FAIL       The provider DLL file could    
                                not be loaded, and may not     
                                exist. If it exists, then the  
                                file is not a valid DLL.       
    
    NTE_SIGNATURE_FILE_BAD      An error occurred while        
                                loading the DLL file image,    
                                prior to verifying its         
                                signature.                     
    
    
    

    Example

    #include <wincrypt.h>
    HCRYPTPROV hProv = 0;
    BYTE pbData[1000];
    DWORD dwDataLen;
    // Get handle to the default PROV_RSA_FULL provider.
    if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
        printf("Error %x during CryptAcquireContext!\n", GetLastError());
        return;
    }
    // Read the name of the default CSP.
    dwDataLen = 1000;
    if(!CryptGetProvParam(hProv, PP_NAME, pbData, &dwDataLen, 0)) {
        printf("Error %x reading CSP name!\n", GetLastError());
        return;
    }
    printf("Provider name:%s\n", pbData);
    // Read the name of the default key container.
    dwDataLen = 1000;
    if(!CryptGetProvParam(hProv, PP_CONTAINER, pbData, &dwDataLen, 0)) {
        printf("Error %x reading key container name!\n", GetLastError());
        return;
    }
    printf("Key Container name:%s\n", pbData);
    // Perform cryptographic operations.
    ...
    // Release provider handle.
    if(!CryptReleaseContext(hProv, 0)) {
        printf("Error %x during CryptReleaseContext!\n", GetLastError());
        return;
    }
    // ****************************************************************
    // Get handle to the Microsoft RSA Base Provider and the 
    // "Foo" key container.
    if(!CryptAcquireContext(&hProv, TEXT("Foo"), MS_DEF_PROV, 
                            PROV_RSA_FULL, 0)) {
        printf("Error %x during CryptAcquireContext!\n", GetLastError());
        return;
    }
    // Perform cryptographic operations.
    ...
    // Release provider handle.
    if(!CryptReleaseContext(hProv, 0)) {
        printf("Error %x during CryptReleaseContext!\n", GetLastError());
        return;
    }
    // ****************************************************************
    // Get handle to the default provider. Create a new key container 
    // named "Bar". Note that this key container will be empty until keys
    // are explicitly created with the CryptGenKey function.
    lstrcpy(szProv, );
    lstrcpy(szContainer, );
    if(!CryptAcquireContext(&hProv, TEXT("Bar"), NULL, PROV_RSA_FULL,
                            CRYPT_NEWKEYSET)) {
        printf("Error %x during CryptAcquireContext!\n", GetLastError());
        return;
    }
    // Perform cryptographic operations.
    ...
    // Release provider handle.
    if(!CryptReleaseContext(hProv, 0)) {
        printf("Error %x during CryptReleaseContext!\n", GetLastError());
        return;
    }
     
    

    See Also

    CryptGetProvParam, CryptReleaseContext

    CryptGetProvParam

    The CryptGetProvParam function lets applications retrieve parameters that govern the operations of a CSP.

    BOOL CRYPTFUNC CryptGetProvParam(
    HCRYPTPROV
    hProv, // in
    DWORD dwParam, // in
    BYTE *pbData, // out
    DWORD *pdwDataLen, // in, out
    DWORD dwFlags) // in

    Parameters

    hProv

    A handle to the CSP on which to query parameters.

    dwParam

    The parameter number. See the "Remarks" section for a list of valid parameters.

    pbData

    The parameter data buffer. The function will copy the specified parameter data to this buffer. The form of this data will vary, depending on the parameter number.

    This parameter can be NULL if all you are doing is determining the number of bytes required for the returned parameter data.

    pdwDataLen

    The address of the parameter data length. Before calling this function, the caller should set this parameter to the length, in bytes, of the pbData buffer. Upon return, this address will contain the number of bytes of parameter data copied to the buffer.

    If the buffer specified by pbData is not large enough to hold the data, the function returns the ERROR_MORE_DATA error code through the GetLastError function, and stores the required buffer size in bytes into the variable pointed to by pdwDataLen.

    If pbData is NULL, then no error is returned and the function stores the size of the data in bytes in the variable pointed to by pdwDataLen.


    Note

    When one of the enumeration parameters (PP_ENUMALGS or PP_ENUMCONTAINERS) is being read, the pdwDataLen parameter works somewhat differently. If pbData is NULL or the value pointed to pdwDataLen is too small, the value returned in this parameter is the size of the largest item in the enumeration list instead of the size of the item currently being read.

    When one of the enumeration parameters is read and the pbData parameter is NULL, the CRYPT_FIRST flag must be specified in order for the size information to be correctly retrieved.

    dwFlags

    The flag values. This parameter is normally set to zero.

    When one of the enumeration parameters (PP_ENUMALGS or PP_ENUMCONTAINERS) is being read, then the CRYPT_FIRST flag can be specified. When this flag is set, the first item in the enumeration list is returned. If this flag is not set, then the next item in the list is returned.

    Remarks

    Parameter Numbers

    The dwParam parameter can be set to one of the following values:

    PP_CONTAINER

    The key container name. When this parameter is specified, the function fills the pbData buffer with the name of the current key container. This name is in the form of a zero-terminated CHAR string.

    This string is exactly the same as the one passed in the pszContainer parameter of the CryptAcquireContext function in order to specify that the current key container be used. This parameter is often read in order to determine the name of the default key container.

    PP_ENUMALGS

    The algorithm information. When this parameter is specified, the function fills the pbData buffer with information about one of the algorithms supported by the CSP. The PP_ENUMALGS parameter must be read repeatedly to enumerate all the supported algorithms. The algorithms are not enumerated in any particular order.

    The first time that the PP_ENUMALGS parameter is read, the CRYPT_FIRST flag should be specified. This will ensure that information about the "first" algorithm in the enumeration list is returned. The PP_ENUMALGS parameter can then be repeatedly read in order to retrieve the information about the rest of the algorithms. When the CryptGetProvParam function fails with the ERROR_NO_MORE_ITEMS, then the end of the enumeration list has been reached. A code sample illustrating this is located in the "Example" section.

    The following code fragment indicates the format of the data that the function returns in the pbData buffer.

    ALG_ID aiAlgid;
    DWORD dwBits;
    DWORD dwNameLen;
    CHAR szName[dwNameLen];
     
    

    The following table defines each of these fields.

    Field        Description                                 
    
                                                             
    
    aiAlgid      The algorithm identifier. This is the       
                 value that is passed to the CryptGenKey,    
                 CryptDeriveKey, or CryptCreateHash          
                 functions in order to specify that a        
                 particular algorithm be used.               
    
    dwBits       The number of bits in the keys used by the  
                 algorithm.                                  
                 If this is a hash algorithm, this value     
                 indicates the number of bits in the hash    
                 values generated by this algorithm.         
    
    dwNameLen    The number of characters in the algorithm   
                 name, including the terminating zero.       
    
    szName       The zero-terminated name of the algorithm.  
    
    
    

    PP_ENUMCONTAINERS

    The key container names. When this parameter is specified, the function fills the pbData buffer with the name of one of the key containers maintained by the CSP. This name is in the form of a zero-terminated CHAR string. The PP_ENUMCONTAINERS parameter must be read repeatedly to enumerate all the container names.

    These container names are enumerated in the same way as are the CSP's supported algorithms. Refer to the PP_ENUMALGS for more information.

    PP_IMPTYPE

    The CSP implementation type. The pbData buffer will contain a DWORD value that indicates how the CSP is implemented. Possible values are:

    CRYPT_IMPL_HARDWARE

    CRYPT_IMPL_SOFTWARE

    CRYPT_IMPL_MIXED

    CRYPT_IMPL_UNKNOWN (the CSP isn't telling)

    PP_NAME

    The CSP name. When this parameter is specified, the function fills the pbData buffer with the name of the CSP. This name is in the form of a zero-terminated CHAR string.

    This string is identical to the one passed in the pszProvider parameter of the CryptAcquireContext function in order to specify that the current CSP be used. For example, the Microsoft RSA Base Provider will return "Microsoft Base Cryptographic Provider v1.0" when this parameter is read.

    PP_VERSION

    The CSP version number. The pbData buffer will contain a DWORD value that indicates the version number of the CSP. The least significant byte contains the minor version number and the next most significant byte the major version number. For example, version 1.0 would be represented here as 0x00000100.

    Algorithm Identifiers

    When enumerating algorithms, your application may need to determine the class of a particular algorithm. For example, you may want to display a list of encryption algorithms to the user and disregard the rest. This can be done with the GET_ALG_CLASS(x) macro. This macro takes an algorithm identifier as an argument and returns a code indicating the general class of algorithm that the identifier belongs to. Possible return values include:

    ALG_CLASS_DATA_ENCRYPT

    ALG_CLASS_HASH

    ALG_CLASS_KEY_EXCHANGE

    ALG_CLASS_SIGNATURE

    The following table lists the algorithms supported by the Microsoft RSA Base Provider along with the class of each algorithm.

    Name         Identifier          Class                      
    
                                                                
    
    "MD2"        CALG_MD2            ALG_CLASS_HASH             
    
    "MD5"        CALG_MD5            ALG_CLASS_HASH             
    
    "SHA"        CALG_SHA            ALG_CLASS_HASH             
    
    "MAC"        CALG_MAC            ALG_CLASS_HASH             
    
    "RSA_SIGN"   CALG_RSA_SIGN       ALG_CLASS_SIGNATURE        
    
    "RSA_KEYX"   CALG_RSA_KEYX       ALG_CLASS_KEY_EXCHANGE     
    
    "RC2"        CALG_RC2            ALG_CLASS_DATA_ENCRYPT     
    
    "RC4"        CALG_RC4            ALG_CLASS_DATA_ENCRYPT     
    
    
    

    If your application does not recognize an algorithm identifier, it is not recommended that it use the algorithm. Making use of an unknown cryptographic algorithm can sometimes produce unpredictable results.

    Return Value

    If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

    The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

    Error                       Description                    
    
                                                               
    
    ERROR_INVALID_HANDLE        One of the parameters          
                                specifies an invalid handle.   
    
    ERROR_INVALID_PARAMETER     One of the parameters          
                                contains an invalid value.     
                                This is most often an illegal  
                                pointer.                       
    
    ERROR_NO_MORE_ITEMS         The end of the enumeration     
                                list has been reached. No      
                                valid data has been placed in  
                                the pbData buffer. This error  
                                is only returned when dwParam  
                                equals PP_ENUMALGS or          
                                PP_ENUMCONTAINERS.             
    
    NTE_BAD_FLAGS               The dwFlags parameter is       
                                nonzero.                       
    
    NTE_BAD_TYPE                The dwParam parameter          
                                specifies an unknown           
                                parameter number.              
    
    NTE_BAD_UID                 The CSP context specified by   
                                hProv is invalid.              
    
    
    

    Example

    This example shows how the list of algorithms supported by a particular CSP is accessed by an application.

    HCRYPTPROV hProv;         // Handle to CSP
    DWORD dwAlgCount;
    BYTE *ptr = NULL;
    DWORD i;
    ALG_ID aiAlgid;
    DWORD dwBits;
    DWORD dwNameLen;
    CHAR szName[100];         // Often allocated dynamically.
    BYTE pbData[1000];        // Often allocated dynamically.
    DWORD dwDataLen;
    DWORD dwFlags;
    CHAR *pszAlgType = NULL;
    // Enumerate the supported algorithms.
    for(i=0 ; ; i++) {
        // Set the CRYPT_FIRST flag the first time through the loop.
        if(i == 0) {
            dwFlags = CRYPT_FIRST;
        } else {
            dwFlags = 0;
        }
        // Retrieve information about an algorithm.
        dwDataLen = 1000;
        if(!CryptGetProvParam(hProv, PP_ENUMALGS, pbData, &dwDataLen, 0)) {
            if(GetLastError() == ERROR_NO_MORE_ITEMS) {
                // Exit the loop.
                break;
            } else {
                printf("Error %x reading algorithm!\n", GetLastError());
                return;
            }
        }
        // Extract algorithm information from 'pbData' buffer.
        ptr = pbData;
        aiAlgid = *(ALG_ID *)ptr;
        ptr += sizeof(ALG_ID);
        dwBits = *(DWORD *)ptr;
        ptr += sizeof(DWORD);
        dwNameLen = *(DWORD *)ptr;
        ptr += sizeof(DWORD);
        strncpy(szName, ptr,dwNameLen);
        // Determine algorithm type.
        switch(GET_ALG_CLASS(aiAlgid)) {
            case ALG_CLASS_DATA_ENCRYPT: pszAlgType = "Encrypt  ";
                                         break;
            case ALG_CLASS_HASH:         pszAlgType = "Hash     ";
                                         break;
            case ALG_CLASS_KEY_EXCHANGE: pszAlgType = "Exchange ";
                                         break;
            case ALG_CLASS_SIGNATURE:    pszAlgType = "Signature";
                                         break;
            default:                     pszAlgType = "Unknown  ";
        }
        // Print information about algorithm.
        printf("Algid:%8.8xh, Bits:%-4d, Type:%s, NameLen:%-2d, Name:%s\n",
            aiAlgid, dwBits, pszAlgType, dwNameLen, szName
        );
    }
     
    

    See Also

    CryptAcquireContext, CryptSetProvParam

    CryptReleaseContext

    The CryptReleaseContext function is used to release a handle to a CSP and a key container.

    This should be performed when the application is finished using the CSP. Once this function is called, the CSP handle specified by the hProv parameter will no longer be valid. Neither the key container nor any key pairs are destroyed by this function.

    BOOL CRYPTFUNC CryptReleaseContext(
    HCRYPTPROV
    hProv, // in
    DWORD dwFlags) // in

    Parameters

    hProv

    A handle to the application's CSP. This is the handle the application obtained using the CryptAcquireContext function.

    dwFlags

    The flag values. This parameter is reserved for future use and should always be zero.

    Remarks

    Once this function has been called, the "session" is over, and all existing session keys and hash objects that were created using the hProv handle become invalid. In practice, all of these objects should be destroyed (with the CryptDestroyKey and CryptDestroyHash functions) before the CryptReleaseContext function is called.

    Return Value

    If the function succeeds, the return value is TRUE. If it fails, then the return value is FALSE. To retrieve extended error information, use the GetLastError function.

    The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

    Error                      Description                     
    
                                                               
    
    ERROR_BUSY                 The CSP context specified by    
                               hProv is currently being used   
                               by another process.             
    
    ERROR_INVALID_HANDLE       One of the parameters           
                               specifies an invalid handle.    
    
    ERROR_INVALID_PARAMETER    One of the parameters contains  
                               an invalid value. This is most  
                               often an illegal pointer.       
    
    NTE_BAD_FLAGS              The dwFlags parameter is        
                               nonzero.                        
    
    NTE_BAD_UID                The hProv parameter does not    
                               contain a valid context         
                               handle.                         
    
    
    

    Example

    See the "Example" section in the CryptAcquireContext function.

    See Also

    CryptAcquireContext


    CryptSetProvider

    The CryptSetProvider function is used to specify the current user default CSP.

    After this function has been called, any calls this user subsequently makes to CryptAcquireContext specifying the dwProvType provider type but not a provider name, will result in the pszProvName provider being used.


    Note

    Typical applications will not use this function. It is intended for sole use by administrative applications.

    BOOL CRYPTFUNC CryptSetProvider(
    LPCTSTR
    pszProvName, // in
    DWORD dwProvType) // in

    Parameters

    pszProvName

    The name of the new default CSP. This CSP should have already been installed on the computer.

    dwProvType

    The provider type of the CSP specified by the pszProvName parameter.

    Remarks

    Well-behaved applications do not usually specify a CSP name when calling the CryptAcquireContext function. This gives the users a certain amount of freedom in that they can select a CSP that has an appropriate level of security.

    This means that a call to CryptSetProvider will often determine the CSP of a given type used by all applications that run from that point on. With this being the case, the CryptSetProvider function should never be called without the user's consent.

    Return Value

    If the function succeeds, the return value is TRUE. If the function fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

    The following table lists the error codes most commonly returned by the GetLastError function.

    Error                       Description                    
    
                                                               
    
    ERROR_INVALID_HANDLE        One of the parameters          
                                specifies an invalid handle.   
    
    ERROR_INVALID_PARAMETER     One of the parameters          
                                contains an invalid value.     
                                This is most often an illegal  
                                pointer.                       
    
    ERROR_NOT_ENOUGH_MEMORY     The operating system ran out   
                                of memory during the           
                                operation.                     
    
    Error codes returned from   See RegCreateKeyEx.            
    the RegCreateKeyEx                                         
    function.                                                  
    
    Error codes returned from   See RegSetValueEx.             
    the RegSetValueEx                                          
    function.                                                  
    
    
    

    Example

    HCRYPTPROV hProv = 0;
    // Specify the default PROV_RSA_SIG provider. Note that this assumes
    // that a CSP with a type of PROV_RSA_SIG and named "Joe's Provider"
    // has already been installed.
    if(!CryptSetProvider(TEXT("Joe's Provider"), PROV_RSA_SIG)) {
        printf("Error %x during CryptSetProvider!\n", GetLastError());
        return;
    }
    // Get handle to the provider that we just made default.
    if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_SIG, 0)) {
        printf("Error %x during CryptAcquireContext!\n", GetLastError());
        return;
    }
    ...
    // Release provider handle.
    if(!CryptReleaseContext(hProv, 0)) {
        printf("Error %x during CryptReleaseContext!\n", GetLastError());
        return;
    }
     
    

    See Also

    CryptAcquireContext

    CryptSetProvParam

    The CryptSetHashParam function lets applications customize the operations of a CSP.

    This function is not currently useful, since no settable CSP parameters have yet been defined.

    BOOL CRYPTFUNC CryptSetProvParam(
    HCRYPTPROV
    hProv, // in
    DWORD dwParam, // in
    BYTE *pbData, // in
    DWORD dwFlags) // in

    Parameters

    hProv

    A handle to the CSP on which to set parameters.

    dwParam

    The parameter number to set.

    pbData

    The parameter data buffer. Place the parameter data in this buffer before calling CryptSetKeyParam. The form of this data will vary, depending on the parameter number.

    dwFlags

    The flag values. This parameter is reserved for future use and should always be zero.

    Return Value

    If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

    The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

    Error                      Description                     
    
                                                               
    
    ERROR_INVALID_HANDLE       One of the parameters           
                               specifies an invalid handle.    
    
    ERROR_BUSY                 The CSP context is currently    
                               being used by another process.  
    
    ERROR_INVALID_PARAMETER    One of the parameters contains  
                               an invalid value. This is most  
                               often an illegal pointer.       
    
    NTE_BAD_FLAGS              The dwFlags parameter is        
                               nonzero or the pbData buffer    
                               contains an invalid value.      
    
    NTE_BAD_TYPE               The dwParam parameter           
                               specifies an unknown            
                               parameter.                      
    
    NTE_BAD_UID                The CSP context that was        
                               specified when the hKey key     
                               was created cannot be found.    
    
    NTE_FAIL                   The function failed in some     
                               unexpected way.                 
    
    
    

    See Also

    CryptAcquireContext, CryptGetProvParam

    CHAPTER 10

    Key Generation and Exchange Functions

    The functions described in this section are used by applications to create, configure, and destroy cryptographic keys, and to exchange them with other users. The following table briefly describes each function:

    Function           Description                              
    
                                                                
    
    CryptDeriveKey     Create a key derived from a password.    
    
    CryptDestroyKey    Destroy a key.                           
    
    CryptExportKey     Transfer a key from the CSP into a key   
                       blob in the application's memory space.  
    
    CryptGenKey        Create a random key.                     
    
    CryptGenRandom     Generate random data.                    
    
    CryptGetKeyParam   Retrieve a key's parameters.             
    
    CryptGetUserKey    Get a handle to the key exchange or      
                       signature key.                           
    
    CryptImportKey     Transfer a key from a key blob to a      
                       CSP.                                     
    
    CryptSetKeyParam   Specify a key's parameters.              
    
    
    


    CryptDeriveKey

    The CryptDeriveKey function generates cryptographic keys derived from base data. This function guarantees that all keys generated from the same base data will be identical, provided the same CSP and algorithms are used. The base data can be a password or any other user data.

    This function is the same as CryptGenKey, except that the generated session keys are derived from base data instead of being random. Another difference is that the CryptDeriveKey function cannot be used to generate public/private key pairs.

    A handle to the session key is returned in phKey. This handle can then be used as needed with any of the other CryptoAPI functions that require key handles.

    BOOL CRYPTFUNC CryptDeriveKey(
    HCRYPTPROV
    hProv, // in
    ALG_ID Algid, // in
    HCRYPTHASH hBaseData, // in
    DWORD dwFlags, // in
    HCRYPTKEY *phKey) // in, out

    Parameters

    hProv

    A handle to the application's CSP. An application obtains this handle using the CryptAcquireContext function.

    Algid

    The identifier for the algorithm for which the key is to be generated.

    The valid values for this parameter will vary, depending on the CSP that is used. See the "Remarks" section for a list of possible algorithm identifiers.

    hBaseData

    A handle to a hash object that has been fed exactly the base data.

    To obtain this handle, an application must first create a hash object with CryptCreateHash and then add the base data to the hash object with CryptHashData. This process is described in detail in Chapter 7.

    dwFlags

    The flags specifying the type of key generated. This parameter can be zero, or you can specify one or more of the following flags, using the binary OR operator to combine them.

    CRYPT_EXPORTABLE

    If this flag is set, then the session key can be transferred out of the CSP into a key blob through the CryptExportKey function. Because keys generally must be exportable, this flag should usually be set.

    If this flag is not set, then the session key will not be exportable. This means the key will only be available within the current session and only the application that created it will be able to use it.

    This flag does not apply to public/private key pairs.

    CRYPT_CREATE_SALT

    Typically, when a session key is made from a hash value, there are a number of leftover bits. For example, if the hash value is 128 bits and the session key is 40 bits, there will be 88 bits leftover.

    If this flag is set, then the key will be assigned a salt value based on the unused hash value bits. You can retrieve this salt value using the CryptGetKeyParam function with the dwParam parameter set to KP_SALT.

    If this flag is not set, then the key will be given a salt value of zero.

    When keys with nonzero salt values are exported (using CryptExportKey), the salt value must also be obtained and kept with the key blob.

    CRYPT_USER_PROTECTED

    If this flag is set, then the user will be notified through a dialog box or another method when certain actions are attempted using this key. The precise behavior is specified by the CSP being used.

    The Microsoft RSA Base Provider ignores this flag.

    CRYPT_UPDATE_KEY

    Some CSPs use session keys that are derived from multiple hash values. When this is the case, CryptDeriveKey must be called multiple times.

    If this flag is set, a new session key is not generated. Instead, the key specified by phKey is modified. The precise behavior of this flag is dependent on the type of key being generated and on the particular CSP being used.

    The Microsoft RSA Base Provider ignores this flag.

    phKey

    The address to which the function copies the handle of the newly generated key.

    Remarks

    To generate a key for a symmetric encryption algorithm, use the Algid parameter to specify the algorithm. The algorithms available will most likely be different for each CSP. If you are using the Microsoft RSA Base Provider, use one of the following values to specify the algorithm:

    CALG_RC2 - RC2 block cipher

    CALG_RC4 - RC4 stream cipher

    When keys are generated for symmetric block ciphers, the key by default will be set up in cipher block chaining (CBC) mode with an initialization vector of zero. This cipher mode provides a good default method for bulk encrypting data. To change these parameters, use the CryptSetKeyParam function.

    Once the CryptDeriveKey function has been called, no more data can be added to the hash object. The CryptDestroyHash function should be called at this point to destroy the hash object.

    Return Value

    If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

    The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

    Error                      Description                     
    
                                                               
    
    ERROR_INVALID_HANDLE       One of the parameters           
                               specifies an invalid handle.    
    
    ERROR_INVALID_PARAMETER    One of the parameters contains  
                               an invalid value. This is most  
                               often an illegal pointer.       
    
    NTE_BAD_ALGID              The Algid parameter specifies   
                               an algorithm that this CSP      
                               does not support.               
    
    NTE_BAD_FLAGS              The dwFlags parameter contains  
                               an invalid value.               
    
    NTE_BAD_HASH               The hBaseData parameter does    
                               not contain a valid handle to   
                               a hash object.                  
    
    NTE_BAD_UID                The hProv parameter does not    
                               contain a valid context         
                               handle.                         
    
    NTE_FAIL                   The function failed in some     
                               unexpected way.                 
    
    
    

    Example

    #include <wincrypt.h>
    HCRYPTPROV hProv = 0;
    HCRYPTKEY hKey = 0;
    HCRYPTHASH hHash = 0;
    CHAR szPassword[ ] = "apple-camshaft";
    DWORD dwLength;
    // Get handle to user default provider.
    if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
        printf("Error %x during CryptAcquireContext!\n", GetLastError());
        goto done;
    }
    // Create hash object.
    if(!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) {
        printf("Error %x during CryptCreateHash!\n", GetLastError());
        goto done;
    }
    // Hash password string.
    dwLength = strlen(szPassword);
    if(!CryptHashData(hHash, (BYTE *)szPassword, dwLength, 0)) {
        printf("Error %x during CryptHashData!\n", GetLastError());
        goto done;
    }
    // Create block cipher session key based on hash of the password.
    if(!CryptDeriveKey(hProv, CALG_RC2, hHash, CRYPT_EXPORTABLE, &hKey)) {
        printf("Error %x during CryptDeriveKey!\n", GetLastError());
        goto done;
    }
    // Use 'hKey' to do something.
    ...
    done:
    // Destroy hash object.
    if(hHash != 0) CryptDestroyHash(hHash);
    // Destroy session key.
    if(hKey != 0) CryptDestroyKey(hKey);
    // Release provider handle.
    if(hProv != 0) CryptReleaseContext(hProv, 0);
     
    

    See Also

    CryptCreateHash, CryptDestroyKey, CryptGenKey, CryptHashData


    CryptDestroyKey

    The CryptDestroyKey function releases the handle referenced by the hKey parameter. Once a key handle has been released, it becomes invalid and cannot be used again.

    If the handle refers to a session key, or to a public key that has been imported into the CSP through CryptImportKey, this function destroys the key and frees the memory that the key occupied. Many CSPs will scrub the memory where the key was held before freeing it.

    On the other hand, if the handle refers to a public/private key pair (obtained from CryptGetUserKey), the underlying key pair is not destroyed by this function. Only the handle is destroyed.

    BOOL CRYPTFUNC CryptDestroyKey(
    HCRYPTKEY
    hKey) // in

    Parameters

    hKey

    A handle to the key to be destroyed.

    Remarks

    Keys take up memory in both the operating system's memory space and the CSP's memory space. Some CSPs will be implemented in hardware with very limited memory resources. For this reason, it is important that applications destroy all keys with the CryptDestroyKey function when they are finished with them.

    Return Value

    If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

    The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

    Error                      Description                     
    
                                                               
    
    ERROR_INVALID_HANDLE       One of the parameters           
                               specifies an invalid handle.    
    
    ERROR_INVALID_PARAMETER    One of the parameters contains  
                               an invalid value. This is most  
                               often an illegal pointer.       
    
    NTE_BAD_KEY                The hKey parameter does not     
                               contain a valid handle to a     
                               key.                            
    
    NTE_BAD_UID                The CSP context that was        
                               specified when the key was      
                               created cannot be found.        
    
    
    

    Example

    See the "Example" section in the CryptGenKey function.

    See Also

    CryptDeriveKey, CryptGenKey, CryptGetUserKey


    CryptExportKey

    The CryptExportKey function is used to export cryptographic keys out of a cryptographic service provider in a secure manner.

    A handle to the key to be exported is passed into the function and the function returns a key blob to the caller. This key blob can be sent over a nonsecure transport or stored in a nonsecure storage location. The key blob is useless until the intended recipient uses the CryptImportKey function on it, which will then import the key into the recipient's CSP.

    BOOL CRYPTFUNC CryptExportKey(
    HCRYPTKEY
    hKey, // in
    HCRYPTKEY hExpKey, // in
    DWORD dwBlobType, // in
    DWORD dwFlags, // in
    BYTE *pbData, // out
    DWORD *pdwDataLen) // in, out

    Parameters

    hKey

    A handle to the key to be exported.

    hExpKey

    A handle to a cryptographic key belonging to the destination user. The key data within the key blob created is encrypted using this key. This ensures that only the destination user will be able to make use of the key blob.

    Most often, this will be the key exchange public key of the destination user. However, certain protocols require that a session key belonging to the destination user be used for this purpose.

    If the key blob type specified by dwBlobType is PUBLICKEYBLOB, then this parameter is unused and should be set to zero.

    dwBlobType

    The type of key blob to be exported. This must currently be one of the following constants. These constants are discussed in Chapter 5.

    SIMPLEBLOB

    PUBLICKEYBLOB

    dwFlags

    The flag values. This parameter is reserved for future use and should always be zero.

    pbData

    The buffer that the function places the key blob in. The required size for this buffer can be determined by calling CryptExportKey with NULL for this parameter.

    As a rule, SIMPLEBLOBs will be 256 bytes or less, and PUBLICKEYBLOBs will be 1024 bytes or less.

    pdwDataLen

    The address of the key blob data length. Before calling this function, the caller should set this parameter to the length, in bytes, of the pbData buffer. Upon return, this address will contain the number of bytes taken up by the key blob.

    If the buffer specified by pbData is not large enough to hold the data, the function returns the ERROR_MORE_DATA error code (through GetLastError) and stores the required buffer size, in bytes, into the variable pointed to by pdwDataLen.

    If pbData is NULL, then no error is returned and the function stores the size of the data, in bytes, in the variable pointed to by pdwDataLen.

    Return Value

    If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

    The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

    Error                      Description                     
    
                                                               
    
    ERROR_INVALID_HANDLE       One of the parameters           
                               specifies an invalid handle.    
    
    ERROR_INVALID_PARAMETER    One of the parameters contains  
                               an invalid value. This is most  
                               often an illegal pointer.       
    
    NTE_BAD_FLAGS              The dwFlags parameter is        
                               nonzero.                        
    
    NTE_BAD_KEY                One or both of the keys         
                               specified by hKey and hExpKey   
                               are invalid.                    
    
    NTE_BAD_KEY_STATE          You do not have permission to   
                               export the key. That is, when   
                               the hKey key was created, the   
                               CRYPT_EXPORTABLE flag was not   
                               specified.                      
    
    NTE_BAD_PUBLIC_KEY         The key blob type specified by  
                               dwBlobType is PUBLICKEYBLOB,    
                               but hExpKey does not contain a  
                               public key handle.              
    
    NTE_BAD_TYPE               The dwBlobType parameter        
                               specifies an unknown blob       
                               type.                           
    
    NTE_BAD_UID                The CSP context that was        
                               specified when the hKey key     
                               was created cannot be found.    
    
    NTE_NO_KEY                 A session key is being          
                               exported and the hExpKey        
                               parameter does not specify a    
                               public key.                     
    
    
    

    Example

    #include <wincrypt.h>
    HCRYPTPROV hProv;      // Handle to CSP
    HCRYPTKEY hKey;        // Handle to session key
    HCRYPTKEY hXchgKey;    // Handle to receiver's exchange public key
    BYTE *pbKeyBlob = NULL;
    DWORD dwBlobLen;
    ...
    // Determine size of key blob and allocate memory.
    if(!CryptExportKey(hKey, hXchgKey, SIMPLEBLOB, 0, NULL, &dwBlobLen)) {
        printf("Error %x computing blob length!\n", GetLastError());
        ...
    }
    if((pbKeyBlob = malloc(dwBlobLen)) == NULL) {
        printf("Out of memory!\n");
        ...
    }
    // Export key into a simple key blob.
    if(!CryptExportKey(hKey, hXchgKey, SIMPLEBLOB, 0, pbKeyBlob, &dwBlobLen)) {
        printf("Error %x during CryptExportKey!\n", GetLastError());
        ...
    }
     
    

    See Also

    CryptImportKey

    CryptGenKey

    The CryptGenKey function generates random cryptographic keys for use with the CSP module. A handle to the key is returned in phKey. This handle can then be used as needed with any of the other CryptoAPI functions requiring key handles.

    The calling application is required to specify the algorithm when calling this function. Because this algorithm type is kept bundled with the key, the application does not need to specify the algorithm later when the actual cryptographic operations are performed.

    BOOL CRYPTFUNC CryptGenKey(
    HCRYPTPROV
    hProv, // in
    ALG_ID Algid, // in
    DWORD dwFlags, // in
    HCRYPTKEY *phKey) // out

    Parameters

    hProv

    A handle to the application's CSP. An application obtains this handle using the CryptAcquireContext function.

    Algid

    The identifier for the algorithm for which the key is to be generated.

    The valid values for this parameter will vary, depending on the CSP that is used. See the "Remarks" section for a list of possible algorithm identifiers.

    dwFlags

    The flags specifying the type of key generated. This parameter can be zero, or you can specify one or more of the following flags, using the binary OR operator to combine them.

    CRYPT_EXPORTABLE

    If this flag is set, then the session key can be transferred out of the CSP into a key blob using the CryptExportKey function. Because keys generally must be exportable, this flag should usually be set.

    If this flag is not set, then the session key will not be exportable. This means that the key will only be available within the current session and only the application that created it will be able to use it.

    This flag does not apply to public/private key pairs.

    CRYPT_CREATE_SALT

    If this flag is set, then the key will be assigned a random salt value automatically. You can retrieve this salt value using the CryptGetKeyParam function with the dwParam parameter set to KP_SALT.

    If this flag is not set, then the key will be given a salt value of zero.

    When keys with non-zero salt values are exported (through CryptExportKey), then the salt value must also be obtained and kept with the key blob.

    CRYPT_USER_PROTECTED

    If this flag is set, then the user will be notified through a dialog box or another method when certain actions are attempted using this key. The precise behavior is specified by the CSP being used.

    The Microsoft RSA Base Provider ignores this flag.

    phKey

    The address that the function copies the handle of the newly generated key to.

    Remarks

    To generate a key to be used with a symmetric encryption algorithm (that is, a session key), use the Algid parameter to specify the algorithm. The algorithms available will most likely be different for each CSP. If you are using the Microsoft RSA Base Provider, one of the following values can be used to specify the algorithm:

    CALG_RC2 - RC2 block cipher

    CALG_RC4 - RC4 stream cipher

    When keys are generated for symmetric block ciphers, the key by default will be set up in cipher block chaining (CBC) mode with an initialization vector of zero. This cipher mode provides a good default method for bulk encrypting data. To change these parameters, use the CryptSetKeyParam function.

    In addition to generating keys for symmetric algorithms, the CryptGenKey function can also generate keys for public-key algorithms. The use of public-key algorithms is restricted to key exchange and digital signatures. Each CryptoAPI client generally possesses one key pair for each of these operations. To generate one of these key pairs, set the Algid parameter to one of the following values:

    AT_KEYEXCHANGE - Key exchange

    AT_SIGNATURE - Digital signature

    Return Value

    If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

    The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

    Error                      Description                     
    
                                                               
    
    ERROR_INVALID_HANDLE       One of the parameters           
                               specifies an invalid handle.    
    
    ERROR_INVALID_PARAMETER    One of the parameters contains  
                               an invalid value. This is most  
                               often an illegal pointer.       
    
    NTE_BAD_ALGID              The Algid parameter specifies   
                               an algorithm that this CSP      
                               does not support.               
    
    NTE_BAD_FLAGS              The dwFlags parameter contains  
                               an invalid value.               
    
    NTE_BAD_UID                The hProv parameter does not    
                               contain a valid context         
                               handle.                         
    
    NTE_FAIL                   The function failed in some     
                               unexpected way.                 
    
    
    

    Example

    #include <wincrypt.h>
    HCRYPTPROV hProv = 0;
    HCRYPTKEY hKey = 0;
    // Get handle to user default provider.
    if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
        printf("Error %x during CryptAcquireContext!\n", GetLastError());
        goto done;
    }
    // Create block cipher session key.
    if(!CryptGenKey(hProv, CALG_RC2, CRYPT_EXPORTABLE, &hKey)) {
        printf("Error %x during CryptGenKey!\n", GetLastError());
        goto done;
    }
    // Use 'hKey' to do something.
    ...
    done:
    // Destroy session key.
    if(hKey != 0) CryptDestroyKey(hKey);
    // Release provider handle.
    if(hProv != 0) CryptReleaseContext(hProv, 0);
     
    

    See Also

    CryptDestroyKey, CryptExportKey, CryptImportKey

    CryptGenRandom

    The CryptGenRandom function fills a buffer with random bytes.

    BOOL CRYPTFUNC CryptGenRandom(
    HCRYPTPROV
    hProv, // in
    DWORD dwLen, // in
    BYTE *pbBuffer) // in, out

    Parameters

    hProv

    A handle to the application's CSP. An application obtains this handle using the CryptAcquireContext function.

    dwLen

    The number of bytes of random data to be generated.

    pbBuffer

    The buffer the function is to copy the random data to. This buffer must be at least dwLen bytes in length.

    Optionally, the application can fill this buffer with data to use as an auxiliary random seed. This is explained further in the "Remarks" section.

    Remarks

    The data produced by this function is "cryptographically random." It is far more random than the data generated by the typical random number generator such as the one shipped with your "C" compiler.

    This function is often used to generate random initialization vectors and salt values.

    Seeding the Random Number Generator

    All software random number generators work in fundamentally the same way. They start with one truly random number, known as the "seed," and then use an algorithm to generate a pseudo-random sequence of bits based on it. The most difficult part of this process is to get a seed that is truly random. This is usually based on user input latency, or the jitter from one or more hardware components.

    If your application has access to a good random source, then it can fill the pbBuffer buffer with some amount of random data before calling CryptGenRandom. The CSP will then use this data to further randomize its internal seed. Failing to initialize the pbBuffer buffer before calling CryptGenRandom is acceptable.

    Return Value

    If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

    The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

    Error                      Description                     
    
                                                               
    
    ERROR_INVALID_HANDLE       One of the parameters           
                               specifies an invalid handle.    
    
    ERROR_INVALID_PARAMETER    One of the parameters contains  
                               an invalid value. This is most  
                               often an illegal pointer.       
    
    NTE_BAD_UID                The hProv parameter does not    
                               contain a valid context         
                               handle.                         
    
    NTE_FAIL                   The function failed in some     
                               unexpected way.                 
    
    
    

    Example

    See the "Example" section in the CryptSetKeyParam function.

    See Also

    CryptAcquireContext, CryptSetKeyParam


    CryptGetKeyParam

    The CryptGetKeyParam function lets applications retrieve data that governs of the operations of a key. Note that the base keying material is not obtainable by this function or any other function.

    BOOL CRYPTFUNC CryptGetKeyParam(
    HCRYPTKEY
    hKey, // in
    DWORD dwParam, // in
    BYTE *pbData, // out
    DWORD *pdwDataLen, // in, out
    DWORD dwFlags) // in

    Parameters

    hKey

    A handle to the key on which to query parameters.

    dwParam

    The parameter number. See the "Remarks" section for a list of valid parameters.

    pbData

    The parameter data buffer. The function will copy the specified parameter data to this buffer. The form of this data will vary, depending on the parameter number.

    This parameter can be NULL if all you are doing is determining the number of bytes required for the returned parameter data.

    pdwDataLen

    The address of the parameter data length. Before calling this function, the caller should set this parameter to the length, in bytes, of the pbData buffer. Upon return, this address will contain the number of bytes of parameter data copied to the buffer.

    If the buffer specified by pbData is not large enough to hold the data, the function returns the ERROR_MORE_DATA error code (through GetLastError) and stores the required buffer size, in bytes, into the variable pointed to by pdwDataLen.

    If pbData is NULL, then no error is returned and the function stores the size of the data, in bytes, in the variable pointed to by pdwDataLen.

    dwFlags

    The flag values. This parameter is reserved for future use and should always be zero.

    Remarks

    For all key types, the dwParam value can be set to one of the following key parameter types:

    Parameter        Description                               
    
                                                               
    
    KP_ALGID         Key algorithm. The pbData buffer will     
                     contain an ALG_ID value indicating that   
                     the algorithm was specified when the key  
                     was created.                              
    
    KP_BLOCKLEN      If a session key is specified by hKey,    
                     this parameter returns the block length,  
                     in bytes, of the cipher. The pbData       
                     buffer will contain a DWORD value         
                     indicating the block length. For stream   
                     ciphers, this value will always be zero.  
                     If a public/private key pair is           
                     specified by hKey, this parameter         
                     returns the key pair's encryption         
                     granularity in bits. For example, the     
                     Microsoft RSA Base Provider generates     
                     512-bit RSA key pairs, so a value of 512  
                     is returned for these keys. If the        
                     public-key algorithm does not support     
                     encryption, the value returned by this    
                     parameter is undefined.                   
    
    KP_SALT          The salt value. The pbData buffer will    
                     contain a BYTE array indicating the       
                     current salt value. The size of the salt  
                     value will vary depending on the CSP and  
                     algorithm being used. Before setting      
                     this parameter, it should be read using   
                     CryptGetKeyParam in order to determine    
                     the size.                                 
                     Salt values do not apply to               
                     public/private key pairs.                 
    
    KP_PERMISSIONS   Key permissions. The pbData buffer will   
                     contain a DWORD value with zero or more   
                     permission flags set. Refer to the table  
                     at the end of this section for a          
                     description of each of these flags.       
    
    
    

    If a block cipher session key is specified by hKey, the dwParam value can also be set to one of the following parameter types.

    Parameter        Description                               
    
                                                               
    
    KP_IV            The initialization vector. The pbData     
                     buffer will contain a BYTE array          
                     indicating the current initialization     
                     vector. This array contains <block        
                     length>/8 elements. For example, if the   
                     block length is 64 bits, the              
                     initialization vector will consist of 8   
                     bytes.                                    
    
    KP_PADDING       The padding mode. The pbData buffer will  
                     contain a DWORD value indicating the      
                     padding method used by the cipher.        
                     Following are the padding modes           
                     currently defined:                        
                     PKCS5_PADDING - PKCS 5 (sec 6.2) padding  
                     method.                                   
    
    KP_MODE          The cipher mode. The pbData buffer will   
                     contain a DWORD value indicating the      
                     mode of the cipher. Refer to the          
                     following table for a list of valid       
                     cipher modes.                             
    
    KP_MODE_BITS     The number of bits to feed back. The      
                     pbData buffer will contain a DWORD value  
                     indicating the number of bits that are    
                     processed per cycle when the OFB or CFB   
                     cipher modes are used.                    
    
    
    

    The following table lists the possible values for the KP_MODE parameter. These cipher modes are discussed in Chapter 6.

    Cipher Mode        Description                              
    
                                                                
    
    CRYPT_MODE_ECB     Electronic codebook.                     
    
    CRYPT_MODE_CBC     Cipher block chaining.                   
    
    CRYPT_MODE_OFB     Output feedback mode.                    
    
    CRYPT_MODE_CFB     Cipher feedback mode.                    
    
    
    

    The following table lists the flags in the bit field that are obtained when the KP_PERMISSIONS parameter is read. These permission flags are ignored by the Microsoft RSA Base Provider. However, custom CSPs can use these flags to restrict operations on keys.

    Permission Flag    Description                              
    
                                                                
    
    CRYPT_ENCRYPT      Allow encryption.                        
    
    CRYPT_DECRYPT      Allow decryption.                        
    
    CRYPT_EXPORT       Allow key to be exported.                
    
    CRYPT_READ         Allow parameters to be read.             
    
    CRYPT_WRITE        Allow parameters to be set.              
    
    CRYPT_MAC          Allow MACs to be used with key.          
    
    
    

    Return Value

    If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

    The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

    Error                       Description                    
    
                                                               
    
    ERROR_INVALID_HANDLE        One of the parameters          
                                specifies an invalid handle.   
    
    ERROR_INVALID_PARAMETER     One of the parameters          
                                contains an invalid value.     
                                This is most often an illegal  
                                pointer.                       
    
    NTE_BAD_FLAGS               The dwFlags parameter is       
                                nonzero.                       
    
    NTE_BAD_KEY or NTE_NO_KEY   The key specified by the hKey  
                                parameter is invalid.          
    
    NTE_BAD_TYPE                The dwParam parameter          
                                specifies an unknown           
                                parameter number.              
    
    NTE_BAD_UID                 The CSP context that was       
                                specified when the key was     
                                created cannot be found.       
    
    
    

    Example

    #include <wincrypt.h>
    HCRYPTPROV hProv = 0;
    HCRYPTKEY hKey = 0;
    DWORD dwMode;
    BYTE pbData[16];
    DWORD dwCount;
    DWORD i;
    // Get handle to user default provider.
    if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
        printf("Error %x during CryptAcquireContext!\n", GetLastError());
        goto done;
    }
    // Create random block cipher session key.
    if(!CryptGenKey(hProv, CALG_RC2, CRYPT_EXPORTABLE, &hKey)) {
        printf("Error %x during CryptGenKey!\n", GetLastError());
        goto done;
    }
    // Read the cipher mode.
    dwCount = sizeof(DWORD);
    if(!CryptGetKeyParam(hKey, KP_MODE, &dwMode, &dwCount, 0)) {
        printf("Error %x during CryptGetKeyParam!\n", GetLastError());
        goto done;
    }
    assert(dwCount==sizeof(BYTE));
    // Print out cipher mode.
    printf("Default cipher mode:%d\n", dwMode);
    // Read initialization vector.
    dwCount = 16;
    if(!CryptGetKeyParam(hKey, KP_IV, pbData, &dwCount, 0)) {
        printf("Error %x during CryptGetKeyParam!\n", GetLastError());
        goto done;
    }
    // Print out initialization vector.
    printf("Default IV:");
    for(i=0;i<dwCount;i++) printf("%2.2x ",pbData[i]);
    printf("\n");
    done:
    // Destroy session key.
    if(hKey != 0) CryptDestroyKey(hKey);
    // Release provider handle.
    if(hProv != 0) CryptReleaseContext(hProv, 0);
     
    

    See Also

    CryptSetKeyParam


    CryptGetUserKey

    The CryptGetUserKey function retrieves a handle to a permanent user key pair, such as the user's signature key pair.

    BOOL CRYPTFUNC CryptGetUserKey(
    HCRYPTPROV
    hProv, // in
    DWORD dwKeySpec, // in
    HCRYPTKEY *phUserKey) // out

    Parameters

    hProv

    A handle to the application's CSP. An application obtains this handle using the CryptAcquireContext function.

    dwKeySpec

    The specification of the key to retrieve. The following keys are retrievable from almost all providers:

    AT_KEYEXCHANGE - Exchange public key

    AT_SIGNATURE - Signature public key

    Additionally, some providers allow access to other user specific keys through this function. See the documentation on the specific provider for details.

    phUserKey

    The address that the function copies the handle of the retrieved key to.

    Return Value

    If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

    The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

    Error                      Description                     
    
                                                               
    
    ERROR_INVALID_HANDLE       One of the parameters           
                               specifies an invalid handle.    
    
    ERROR_INVALID_PARAMETER    One of the parameters contains  
                               an invalid value. This is most  
                               often an illegal pointer.       
    
    NTE_BAD_KEY                The dwKeySpec parameter         
                               contains an invalid value.      
    
    NTE_BAD_UID                The hProv parameter does not    
                               contain a valid context         
                               handle.                         
    
    NTE_NO_KEY                 The key requested by the        
                               dwKeySpec parameter does not    
                               exist.                          
    
    
    

    Example

    #include <wincrypt.h>
    HCRYPTPROV hProv = 0;
    HCRYPTKEY hSignKey = 0;
    HCRYPTKEY hXchgKey = 0;
    // Get handle to user default provider.
    if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
        printf("Error %x during CryptAcquireContext!\n", GetLastError());
        goto done;
    }
    // Get handle to signature key.
    if(!CryptGetUserKey(hProv, AT_SIGNATURE, &hSignKey)) {
        printf("Error %x during CryptGetUserKey!\n", GetLastError());
        goto done;
    }
    // Get handle to key exchange key.
    if(!CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hXchgKey)) {
        printf("Error %x during CryptGetUserKey!\n", GetLastError());
        goto done;
    }
    // Do something with 'hSignKey' and 'hXchgKey'.
    ...
    done:
    // Destroy signature key handle.
    if(hSignKey != 0) CryptDestroyKey(hSignKey);
    // Destroy key exchange key handle.
    if(hXchgKey != 0) CryptDestroyKey(hXchgKey);
    // Release provider handle.
    if(hProv != 0) CryptReleaseContext(hProv, 0);
     
    

    See Also

    CryptAcquireContext, CryptDestroyKey, CryptGenKey


    CryptImportKey

    The CryptImportKey function is used to transfer a cryptographic key from a key blob to the CSP.

    BOOL CRYPTFUNC CryptImportKey(
    HCRYPTPROV
    hProv, // in
    BYTE *pbData, // in
    DWORD dwDataLen, // in
    HCRYPTKEY hImpKey, // in
    DWORD dwFlags, // in
    HCRYPTKEY *phKey) // out

    Parameters

    hProv

    A handle to the application's CSP. An application obtains this handle using the CryptAcquireContext function.

    pbData

    The buffer containing the key blob. This key blob was generated by the CryptExportKey function, either by this same application or by another application running on a distant computer.

    This key blob consists of a standard header followed by the encrypted key.

    dwDataLen

    The length, in bytes, of the key blob.

    hImpKey

    The meaning of this parameter differs, depending on the CSP type and the type of key blob being imported.

    If the key blob is not encrypted (for example, a PUBLICKEYBLOB) or if the key blob is encrypted with the key exchange key pair (for example, a SIMPLEBLOB), then this parameter is not used, and should be zero.

    If a signed key blob is being imported, this key is used to validate the signature of the key blob. In this case, this parameter should contain a handle to the key exchange public key of the party that created the key blob.

    If the key blob is encrypted with a session key (as is is often done by Fortezza CSPs, for example), then this parameter should contain a handle to this session key.

    The Microsoft RSA Base Provider does not use this parameter, and expects it to be zero.

    dwFlags

    The flag values. This parameter is reserved for future use and should always be zero.

    phKey

    The address to which the function copies a handle to the key that was imported.

    Return Value

    If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

    The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

    Error                      Description                     
    
                                                               
    
    ERROR_INVALID_HANDLE       One of the parameters           
                               specifies an invalid handle.    
    
    ERROR_INVALID_PARAMETER    One of the parameters contains  
                               an invalid value. This is most  
                               often an illegal pointer.       
    
    NTE_BAD_ALGID              The simple key blob you are     
                               trying to import is not         
                               encrypted with the expected     
                               key exchange algorithm.         
    
    NTE_BAD_DATA               The algorithm that works with   
                               the public key you are trying   
                               to import is not supported by   
                               this CSP.                       
    
    NTE_BAD_FLAGS              The dwFlags parameter is        
                               nonzero.                        
    
    NTE_BAD_TYPE               The key blob type is not        
                               supported by this CSP and is    
                               possibly invalid.               
    
    NTE_BAD_UID                The hProv parameter does not    
                               contain a valid context         
                               handle.                         
    
    NTE_BAD_VER                The key blob's version number   
                               does not match the CSP          
                               version. This usually           
                               indicates that the CSP needs    
                               to be upgraded.                 
    
    
    

    Example

    #include <wincrypt.h>
    FILE *hSourceFile = NULL;
    HCRYPTPROV hProv = 0;
    HCRYPTKEY hKey = 0;
    BYTE *pbKeyBlob = NULL;
    DWORD dwBlobLen;
    // Open file, getting file handle 'hSourceFile'.
    ...
    // Get handle to the default provider.
    if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
        printf("Error %x during CryptAcquireContext!\n", GetLastError());
        goto done;
    }
    // Read key blob length from file and allocate memory.
    fread(&dwBlobLen, sizeof(DWORD), 1, hSourceFile);
    pbKeyBlob = malloc(dwBlobLen);
    // Read key blob from file.
    fread(pbKeyBlob, 1, dwBlobLen, hSourceFile);
    // Import key blob into CSP.
    if(!CryptImportKey(hProv, pbKeyBlob, dwBlobLen, 0, 0, &hKey)) {
        printf("Error %x during CryptImportKey!\n", GetLastError());
        free(pbKeyBlob);
        goto done;
    }
    // Free memory.
    free(pbKeyBlob);
    // Use 'hKey' to perform cryptographic operations.
    ...
    done:
    // Destroy session key.
    if(hKey) CryptDestroyKey(hKey);
    // Release provider handle.
    if(hProv) CryptReleaseContext(hProv, 0);
     
    

    See Also

    CryptDestroyKey, CryptExportKey


    CryptSetKeyParam

    The CryptSetKeyParam function lets applications customize various aspects of a key's operations.

    Generally, this function is used to set session-specific parameters on symmetric keys. Note that the base keying material is not accessible by this function.

    The Microsoft RSA Base Provider has no settable parameters on key exchange or signature keys. However, custom providers may define parameters that can be set on these keys.

    BOOL CRYPTFUNC CryptSetKeyParam(
    HCRYPTKEY
    hKey, // in
    DWORD dwParam, // in
    BYTE *pbData, // in
    DWORD dwFlags) // in

    Parameters

    hKey

    A handle to the key on which to set parameters.

    dwParam

    The parameter number. See the "Remarks" section for a list of valid parameters.

    pbData

    The parameter data buffer. Place the parameter data in this buffer before calling CryptSetKeyParam. The form of this data will vary, depending on the parameter number.

    dwFlags

    The flag values. This parameter is reserved for future use and should always be zero.

    Remarks

    For all session key types, the dwParam value can be set to one of the following key parameter types;

    Parameter        Description                               
    
                                                               
    
    KP_SALT          The salt value. The pbData buffer should  
                     contain a BYTE array specifying a new     
                     salt value. This value is made part of    
                     the session key. The size of the salt     
                     value will vary depending on the CSP      
                     being used so, before setting this        
                     parameter, it should be read using        
                     CryptGetKeyParam in order to determine    
                     its size.                                 
                     When it is suspected that the base data   
                     used for derived keys is less than        
                     ideal, salt values are often used to      
                     make the session keys more unique. This   
                     makes dictionary attacks more difficult.  
                     When using the Microsoft RSA Base         
                     Provider, this parameter defaults to      
                     zero.                                     
    
    KP_PERMISSIONS   The key permissions flags. The pbData     
                     buffer should contain a DWORD value       
                     specifying zero or more permission        
                     flags. Refer to the CryptGetKeyParam      
                     function for a description of these       
                     flags.                                    
                     When using the Microsoft RSA Base         
                     Provider, this parameter defaults to      
                     0xFFFFFFFF.                               
    
    
    

    If a block cipher session key is specified by hKey, the dwParam value can also be set to one of the following parameter types.

    Parameter        Description                               
    
                                                               
    
    KP_IV            The initialization vector. The pbData     
                     buffer should contain a BYTE array        
                     specifying the initialization vector.     
                     This array should contain <block          
                     length>/8 elements. For example, if the   
                     block length is 64 bits, the              
                     initialization vector will consist of 8   
                     bytes.                                    
                     When using the Microsoft RSA Base         
                     Provider, this parameter defaults to      
                     zero.                                     
    
    KP_PADDING       The padding mode. The pbData buffer       
                     should contain a DWORD value specifying   
                     the padding method to be used by the      
                     cipher. Following are the padding modes   
                     currently defined:                        
                     PKCS5_PADDING - PKCS 5 (sec 6.2) padding  
                     method.                                   
                     When using the Microsoft RSA Base         
                     Provider, this parameter defaults to      
                     PKCS5_PADDING.                            
    
    KP_MODE          The cipher mode. The pbData buffer        
                     should contain a DWORD value specifying   
                     the cipher mode to be used. Refer to the  
                     CryptGetKeyParam function for a list      
                      of the defined cipher modes.             
                     When using the Microsoft RSA Base         
                     Provider, this parameter defaults to      
                     CRYPT_MODE_CBC.                           
    
    KP_MODE_BITS     The number of bits to feed back. The      
                     pbData buffer contains a DWORD value      
                     indicating the number of bits that are    
                     processed per cycle when the OFB or CFB   
                     cipher modes are used.                    
                     When using the Microsoft RSA Base         
                     Provider, this parameter defaults to 8.   
    
    
    

    Return Value

    If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

    The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

    Error                      Description                     
    
                                                               
    
    ERROR_INVALID_HANDLE       One of the parameters           
                               specifies an invalid handle.    
    
    ERROR_BUSY                 The CSP context is currently    
                               being used by another process.  
    
    ERROR_INVALID_PARAMETER    One of the parameters contains  
                               an invalid value. This is most  
                               often an illegal pointer.       
    
    NTE_BAD_FLAGS              The dwFlags parameter is        
                               nonzero or the pbData buffer    
                               contains an invalid value.      
    
    NTE_BAD_TYPE               The dwParam parameter           
                               specifies an unknown            
                               parameter.                      
    
    NTE_BAD_UID                The CSP context that was        
                               specified when the hKey key     
                               was created cannot be found.    
    
    NTE_FAIL                   The function failed in some     
                               unexpected way.                 
    
    
    

    Example

    #include <wincrypt.h>
    HCRYPTPROV hProv = 0;
    HCRYPTKEY hKey = 0;
    DWORD dwMode;
    BYTE pbData[16];
    DWORD dwCount;
    DWORD i;
    // Get handle to user default provider.
    if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
        printf("Error %x during CryptAcquireContext!\n", GetLastError());
        goto done;
    }
    // Create random block cipher session key.
    if(!CryptGenKey(hProv, CALG_RC2, CRYPT_EXPORTABLE, &hKey)) {
        printf("Error %x during CryptGenKey!\n", GetLastError());
        goto done;
    }
    // Set the cipher mode.
    dwMode = CRYPT_MODE_ECB;
    if(!CryptSetKeyParam(hKey, KP_MODE, &dwMode, 0)) {
        printf("Error %x during CryptSetKeyParam!\n", GetLastError());
        goto done;
    }
    // Generate random initialization vector.
    if(!CryptGenRandom(hProv, 8, pbData)) {
        printf("Error %x during CryptGenRandom!\n", GetLastError());
        goto done;
    }
    // Set initialization vector.
    if(!CryptSetKeyParam(hKey, KP_IV, pbData, 0)) {
        printf("Error %x during CryptGetKeyParam!\n", GetLastError());
        goto done;
    }
    // Do something with 'hKey'.
    ...
    done:
    // Destroy session key.
    if(hKey != 0) CryptDestroyKey(hKey);
    // Release provider handle.
    if(hProv != 0) CryptReleaseContext(hProv, 0);
     
    

    See Also

    CryptGenKey, CryptGetKeyParam

    CHAPTER 11

    Data Encryption Functions

    The functions in this section support encryption and decryption operations. Before invoking these functions, you must first acquire an encryption key. This is done using CryptGenKey, CryptDeriveKey, or CryptImportKey, which are defined in Chapter 4. The encryption algorithm is specified when the key is created. You can also specify additional encryption parameters using the CryptSetKeyParam function.

    Function        Description                                 
    
                                                                
    
    CryptDecrypt    Decrypt a section of cipher text using the  
                    specified encryption key.                   
    
    CryptEncrypt    Encrypt a section of plaintext using the    
                    specified encryption key.                   
    
    
    


    CryptDecrypt

    The CryptDecrypt function is used to decrypt data that was previously encrypted via the CryptEncrypt function.

    BOOL CRYPTFUNC CryptDecrypt(
    HCRYPTKEY
    hKey, // in
    HCRYPTHASH hHash, // in
    BOOL Final, // in
    DWORD dwFlags, // in
    BYTE *pbData, // in, out
    DWORD *pdwDataLen) // in, out

    Parameters

    hKey

    A handle to the key to use for the decryption. An application obtains this handle by using either the CryptGenKey or CryptImportKey function.

    This key specifies the decryption algorithm that is used.

    hHash

    A handle to a hash object. This parameter is only used if a hash of the data is to be computed. See the "Remarks" section for more information.

    If no hash is to be done, this parameter must be zero.

    Final

    The Boolean value that specifies whether this is the last section in a series being decrypted. This will be TRUE if this is the last or only block. If it is not, then it will be FALSE. See the "Remarks" section for more information.

    dwFlags

    The flag values. This parameter is reserved for future use and should always be zero.

    pbData

    The buffer holding the data to be decrypted. Once that decryption has been performed, the plaintext is placed back in this same buffer.

    The number of encrypted bytes in this buffer is specified by pdwDataLen.

    pdwDataLen

    The address of the data length. Before calling this function, the caller should set this parameter to the number of bytes to be decrypted. Upon return, this address will contain the number of bytes of plaintext generated.

    When a block cipher is used, this data length must be a multiple of the block size, unless this is the final section of data to be decrypted and the Final flag is TRUE.

    Remarks

    If data is to be decrypted and hashed simultaneously, a handle to a hash object can be passed in the hHash parameter. The hash value will be updated with the decrypted plaintext. This option is useful when simultaneously decrypting and verifying a signature.

    Prior to calling CryptDecrypt, the application should obtain a handle to the hash object by calling the CryptCreateHash function. Once the decryption is complete, the hash value can be obtained (through CryptGetHashParam) or it can be signed (through CryptSignHash), or it can be used to verify a digital signature (through CryptVerifySignature).

    When a large amount of data needs to be decrypted, it can be done in sections. This is done by calling CryptDecrypt repeatedly. The Final parameter should be set to TRUE only on the last invocation of CryptDecrypt, so the decryption engine can properly finish the decryption process. The following extra actions are performed when Final is TRUE:

    If the key is a block cipher key, the data will be padded to a multiple of the block size of the cipher. To find the block size of a cipher, use CryptGetKeyParam to get the KP_BLOCKLEN parameter of the key.

    If the cipher is operating in a chaining mode, the next CryptDecrypt operation will reset the cipher's feedback register to the KP_IV value of the key.

    If the cipher is a stream cipher, the next CryptDecrypt call will reset the cipher to its initial state.

    Return Value

    If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

    The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

    Error                    Description                        
    
                                                                
    
    ERROR_INVALID_HANDLE     One of the parameters specifies    
                             an invalid handle.                 
    
    ERROR_INVALID            One of the parameters contains an  
    _PARAMETER               invalid value. This is most often  
                             an illegal pointer.                
    
    NTE_BAD_ALGID            The hKey session key specifies an  
                             algorithm that this CSP does not   
                             support.                           
    
    NTE_BAD_DATA             The data to be decrypted is        
                             invalid. For example, when a       
                             block cipher is used and the       
                             Final flag FALSE, the value        
                             specified by pdwDataLen must be a  
                             multiple of the block size. This   
                             error can also be returned when    
                             the padding is found to be         
                             invalid.                           
    
    NTE_BAD_FLAGS            The dwFlags parameter is nonzero.  
    
    NTE_BAD_HASH             The hHash parameter contains an    
                             invalid handle.                    
    
    NTE_BAD_KEY              The hKey parameter does not        
                             contain a valid handle to a key.   
    
    NTE_BAD_LEN              The size of the output buffer is   
                             too small to hold the generated    
                             plaintext.                         
    
    NTE_BAD_UID              The CSP context that was           
                             specified when the key was         
                             created cannot be found.           
    
    NTE_DOUBLE_ENCRYPT       The application attempted to       
                             decrypt the same data twice.       
    
    NTE_FAIL                 The function failed in some        
                             unexpected way.                    
    
    
    

    Example

    See "Decryption Example" in Chapter 6.

    See Also

    CryptCreateHash, CryptEncrypt, CryptGenKey, CryptGetHashParam, CryptSignHash, CryptVerifySignature

    CryptEncrypt

    The CryptEncrypt function is used to encrypt data. The algorithm used to encrypt the data is designated by the key held by the CSP module, which is referenced by the hKey parameter.

    BOOL CRYPTFUNC CryptEncrypt(
    CRYPTHANDLE
    hKey, // in
    HCRYPTHASH hHash, // in
    BOOL Final, // in
    DWORD dwFlags, // in
    BYTE *pbData, // in, out
    DWORD *pdwDataLen, // in, out
    DWORD dwBufLen) // in

    Parameters

    hKey

    A handle to the key to use for the encryption. An application obtains this handle by using either the CryptGenKey or the CryptImportKey function.

    This key specifies the encryption algorithm that is used.

    hHash

    A handle to a hash object. This parameter is used only if a hash of the data is to be computed at the same time the encryption is being performed. See the "Remarks" section for more information.

    If no hash is to be done, this parameter must be zero.

    Final

    The Boolean value that specifies whether this is the last section in a series being encrypted. This should be TRUE if this is the last or only block, and FALSE if it is not. See the "Remarks" section for more information.

    dwFlags

    The flag values. This parameter is reserved for future use and should always be zero.

    pbData

    The buffer holding the data to be encrypted. Once the encryption has been performed, the encrypted data is placed back in this same buffer.

    The size of this buffer is specified by dwBufLen. The number of bytes of data to be encrypted is specified by pdwDataLen.

    This parameter can be NULL if all you are doing is determining the number of bytes required for the returned data.

    pdwDataLen

    The address of the data length. Before calling this function, the caller should set this parameter to the number of bytes to be encrypted. Upon return, this address will contain the number of bytes of encrypted data.

    If the buffer specified by pbData is not large enough to hold the data, the function returns the ERROR_MORE_DATA error code (through GetLastError) and stores the required buffer size, in bytes, into the variable pointed to by pdwDataLen.

    If pbData is NULL, then no error is returned, and the function stores the size of the data, in bytes, in the variable pointed to be pdwDataLen. This lets an application determine the correct buffer size unambiguously.

    When a block cipher is used, this data length must be a multiple of the block size, unless this is the final section of data to be encrypted and the Final flag is TRUE.

    dwBufLen

    The number of bytes in the pbData buffer.

    Note that, depending on the algorithm used, the encrypted text can be slightly larger than the original plaintext. In this case, the pbData buffer needs to be sized accordingly.

    As a rule, if a stream cipher is used the ciphertext will be the same size as the plaintext. If a block cipher is used, the ciphertext will be up to a "block length" larger than the plaintext.

    Remarks

    If data is to be hashed and encrypted simultaneously, a handle to a hash object can be passed in the hHash parameter. The hash value will be updated with the plaintext passed in. This option is useful when generating signed and encrypted text.

    Prior to calling CryptEncrypt, the application should obtain a handle to the hash object by calling the CryptCreateHash function. Once the encryption is complete, the hash value can be obtained through the CryptGetHashParam function or the hash can be signed using the CryptSignHash function.

    When a large amount of data needs to be encrypted, it can be done in sections. This is done by calling CryptEncrypt repeatedly. The Final parameter should be set to TRUE only on the last invocation of CryptEncrypt, so the encryption engine can properly finish the encryption process. The following extra actions are performed when Final is TRUE:

    If the key is a block cipher key, the data will be padded to a multiple of the block size of the cipher. To find the block size of a cipher, use CryptGetKeyParam to get the KP_BLOCKLEN parameter of the key.

    If the cipher is operating in a chaining mode, the next CryptEncrypt operation will reset the cipher's feedback register to the KP_IV value of the key.

    If the cipher is a stream cipher, the next CryptEncrypt will reset the cipher to its initial state.

    Return Value

    If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

    The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

    Error                    Description                       
    
                                                               
    
    ERROR_INVALID_HANDLE     One of the parameters specifies   
                             an invalid handle.                
    
    ERROR_INVALID_PARAMETER  One of the parameters contains    
                             an invalid value. This is most    
                             often an illegal pointer.         
    
    NTE_BAD_ALGID            The hKey session key specifies    
                             an algorithm that this CSP does   
                             not support.                      
    
    NTE_BAD_DATA             The data to be encrypted is       
                             invalid. For example, when a      
                             block cipher is used and the      
                             Final flag is FALSE, the value    
                             specified by pdwDataLen must be   
                             a multiple of the block size.     
    
    NTE_BAD_FLAGS            The dwFlags parameter is          
                             nonzero.                          
    
    NTE_BAD_HASH             The hHash parameter contains an   
                             invalid handle.                   
    
    NTE_BAD_KEY              The hKey parameter does not       
                             contain a valid handle to a key.  
    
    NTE_BAD_LEN              The size of the output buffer is  
                             too small to hold the generated   
                             ciphertext.                       
    
    NTE_BAD_UID              The CSP context that was          
                             specified when the key was        
                             created cannot be found.          
    
    NTE_DOUBLE_ENCRYPT       The application attempted to      
                             encrypt the same data twice.      
    
    NTE_FAIL                 The function failed in some       
                             unexpected way.                   
    
    NTE_NO_MEMORY            The CSP ran out of memory during  
                             the operation.                    
    
    
    

    Example

    See "Encryption Example" in Chapter 6.

    See Also

    CryptDecrypt, CryptGenKey

    CHAPTER 12

    Hashing and Digital Signature Functions

    The functions described in this section are used by applications to compute hashes (also known as message digests), and are also used to create and verify digital signatures. The following table briefly describes each function.

    Function           Description                              
    
                                                                
    
    CryptCreateHash    Create an "empty" hash object.           
    
    CryptDestroyHash   Destroy a hash object.                   
    
    CryptGetHashParam  Retrieve a hash object parameter.        
    
    CryptHashData      Hash a block of data, adding it to the   
                       specified hash object.                   
    
    CryptHashSessionKe Hash a session key, adding it to the     
    y                  specified hash object.                   
    
    CryptSetHashParam  Set a hash object parameter.             
    
    CryptSignHash      Sign the specified hash object.          
    
    CryptVerifySignatu Verify a digital signature, given a      
    re                 handle to the hash object that was       
                       supposedly signed.                       
    
    
    


    CryptCreateHash

    The CryptCreateHash function is used to initiate the hashing of a stream of data. It returns to the caller a handle to a CSP hash object. This handle can also be used in subsequent calls to CryptHashData and CryptHashSessionKey in order to hash streams of data and session keys.

    BOOL CRYPTFUNC CryptCreateHash(
    HCRYPTPROV
    hProv, // in
    ALG_ID Algid, // in
    HCRYPTKEY hKey, // in
    DWORD dwFlags, // in
    HCRYPTHASH *phHash) // out

    Parameters

    hProv

    A handle to the CSP to use. An application obtains this handle using the CryptAcquireContext function.

    Algid

    An algorithm identifier of the hash algorithm to use.

    The valid values for this parameter will vary, depending on the CSP that is used. See the "Remarks" section for the list of default algorithms.

    hKey

    If the type of hash algorithm is a keyed hash, such as a MAC algorithm, the key for the hash should be passed in this parameter. For nonkeyed algorithms, this parameter should be set to zero.

    The key must be to a block cipher, such as RC2, with a cipher mode of CBC.

    dwFlags

    The flag values. This parameter is reserved for future use and should always be zero.

    phHash

    The address to which the function copies a handle to the new hash object.

    Remarks

    The Microsoft RSA Base Provider defines the following hashing algorithms:

    Constant        Description                                 
    
                                                                
    
    CALG_MAC        Message Authentication Code                 
    
    CALG_MD2        MD2                                         
    
    CALG_MD5        MD5                                         
    
    CALG_SHA        US DSA Secure Hash Algorithm                
    
    
    

    The computation of the actual hash is done with the CryptHashData and CryptHashSessionKey functions. These require a handle to the hash object. Once all the data has been added to the hash object, exactly one of the following operations can be performed:

    The hash value can be retrieved using CryptGetHashParam.

    A session key can be derived using CryptDeriveKey.

    The hash can be signed using CryptSignHash.

    A signature can be verified using CryptVerifySignature.

    Once one of the functions from this list has been called, the only hashing function that can be used with the same hash handle is CryptDestroyHash.

    Return Value

    If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

    The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

    Error                       Description                    
    
                                                               
    
    ERROR_INVALID_HANDLE        One of the parameters          
                                specifies an invalid handle.   
    
    ERROR_INVALID_PARAMETER     One of the parameters          
                                contains an invalid value.     
                                This is most often an illegal  
                                pointer.                       
    
    ERROR_NOT_ENOUGH_MEMORY     The operating system ran out   
                                of memory during the           
                                operation.                     
    
    NTE_BAD_ALGID               The Algid parameter specifies  
                                an algorithm that this CSP     
                                does not support.              
    
    NTE_BAD_FLAGS               The dwFlags parameter is       
                                nonzero.                       
    
    NTE_BAD_KEY                 A keyed hash algorithm (such   
                                as CALG_MAC) is specified by   
                                Algid and the hKey parameter   
                                is either zero or it           
                                specifies an invalid key       
                                handle. This error code will   
                                also be returned if the key    
                                is to a stream cipher, or if   
                                the cipher mode is anything    
                                other than CBC.                
    
    NTE_NO_MEMORY               The CSP ran out of memory      
                                during the operation.          
    
    
    

    Example

    See the "Example" section in the CryptSignHash function.

    See Also

    CryptDeriveKey, CryptHashData, CryptHashSessionKey, CryptSignHash, CryptVerifySignature


    CryptDestroyHash

    The CryptDestroyHash function destroys the hash object referenced by the hHash parameter. Once a hash object has been destroyed, it can no longer be used and its handle is useless from then on.

    All hash objects should be destroyed with the CryptDestroyHash function when the application is finished with them.

    BOOL CRYPTFUNC CryptDestroyHash(
    HCRYPTHASH
    hHash) // in

    Parameters

    hHash

    A handle to the hash object to be destroyed.

    Remarks

    When a hash object is destroyed, the many CSPs will scrub the memory in the CSP where the hash object was held. The CSP memory is then freed.

    There should be a one-to-one correspondence between calls to CryptCreateHash and CryptDestroyHash.

    Return Value

    If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

    The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

    Error                     Description                      
    
                                                               
    
    ERROR_BUSY                The hash object specified by     
                              hHash is currently being used    
                              by another process.              
    
    ERROR_INVALID_HANDLE      One of the parameters specifies  
                              an invalid handle.               
    
    ERROR_INVALID_PARAMETER   One of the parameters contains   
                              an invalid value. This is most   
                              often an illegal pointer.        
    
    NTE_BAD_ALGID             The hHash handle specifies an    
                              algorithm that this CSP does     
                              not support.                     
    
    NTE_BAD_HASH              The hash object specified by     
                              the hHash parameter is invalid.  
    
    NTE_BAD_UID               The CSP context that was         
                              specified when the hash object   
                              was created cannot be found.     
    
    
    

    Example

    See the "Example" section in the CryptSignHash function.

    See Also

    CryptCreateHash, CryptHashData, CryptSignHash


    CryptGetHashParam

    The CryptGetHashParam function lets applications retrieve data that governs of the operations of a hash object. The actual hash value can also be retrieved using this function.

    BOOL CRYPTFUNC CryptGetHashParam(
    HCRYPTHASH
    hHash, // in
    DWORD dwParam, // in
    BYTE *pbData, // out
    DWORD *pdwDataLen, // in, out
    DWORD dwFlags) // in

    Parameters

    hHash

    A handle to the hash object on which to query parameters.

    dwParam

    The parameter number. See the "Remarks" section for a list of valid parameters.

    pbData

    The parameter data buffer. The function copies the specified parameter data to this buffer. The form of this data will vary, depending on the parameter number.

    This parameter can be NULL if all you are doing is determining the number of bytes required for the returned parameter data.

    pdwDataLen

    The address of the parameter data length. Before calling this function, the caller should set this parameter to the length, in bytes, of the pbData buffer. Upon return, this address will contain the number of bytes of parameter data copied to the buffer.

    If the buffer specified by pbData is not large enough to hold the data, the function returns the ERROR_MORE_DATA error code (through GetLastError), and stores the required buffer size, in bytes, in the variable pointed to by pdwDataLen.

    If pbData is NULL, then no error is returned and the function stores the size of the data, in bytes, in the variable pointed to by pdwDataLen.

    dwFlags

    The flag values. This parameter is reserved for future use and should always be zero.

    Remarks

    The dwParam value can be set to one of the following key parameter types:

    HP_ALGID

    The hash algorithm. The pbData buffer will contain a ALG_ID value indicating the algorithm that was specified when the hash object was created. See the CryptCreateHash function for a list of hash algorithms.

    HP_HASHSIZE

    The hash value size. The pbData buffer will contain a DWORD value indicating the number of bytes in the hash value. This value will usually be 16 or 20, depending on the hash algorithm.

    Applications should retrieve this parameter just before the HP_HASHVAL parameter so the correct amount of memory can be allocated.

    HP_HASHVAL

    The hash value. The pbData buffer will contain the hash value or message digest for the hash object specified by hHash. This value is generated based on the data supplied earlier to the hash object through the CryptHashData and CryptHashSessionKey functions.

    Once this parameter has been retrieved, the hash object is marked "finished" and no more data can be added to it.

    Note that some CSPs may add additional parameters that can be queried through this function.

    Return Value

    If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

    The following table lists the error codes most commonly returned by the GetLastError function. The error codes tat prefaced by "NTE" are generated by the particular CSP you are using.

    Error                      Description                     
    
                                                               
    
    ERROR_INVALID_HANDLE       One of the parameters           
                               specifies an invalid handle.    
    
    ERROR_INVALID_PARAMETER    One of the parameters contains  
                               an invalid value. This is most  
                               often an illegal pointer.       
    
    NTE_BAD_FLAGS              The dwFlags parameter is        
                               nonzero.                        
    
    NTE_BAD_HASH               The hash object specified by    
                               the hHash parameter is          
                               invalid.                        
    
    NTE_BAD_TYPE               The dwParam parameter           
                               specifies an unknown parameter  
                               number.                         
    
    NTE_BAD_UID                The CSP context that was        
                               specified when the hash was     
                               created cannot be found.        
    
    
    

    Example

    #include <wincrypt.h>
    HCRYPTPROV hProv = 0;
    HCRYPTHASH hHash = 0;
    BYTE *pbHash = NULL;
    DWORD dwHashLen;
    #define BUFFER_SIZE 256
    BYTE pbBuffer[BUFFER_SIZE];
    DWORD dwCount;
    DWORD i;
    // Get handle to the default provider.
    if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
        printf("Error %x during CryptAcquireContext!\n", GetLastError());
        goto done;
    }
    // Create hash object.
    if(!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) {
        printf("Error %x during CryptBeginHash!\n", GetLastError());
        goto done;
    }
    // Fill buffer with test data.
    for(i = 0 ; i < BUFFER_SIZE ; i++) {
        pbBuffer[i] = (BYTE)i;
    }
    // Hash in buffer.
    if(!CryptHashData(hHash, pbBuffer, BUFFER_SIZE, 0)) {
        printf("Error %x during CryptHashData!\n", GetLastError());
        goto done;
    }
    // Read hash value size and allocate memory.
    dwCount = sizeof(DWORD);
    if(!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&dwHashLen, 
                          &dwCount, 0)) {
        printf("Error %x during reading hash size!\n", GetLastError());
        goto done;
    }
    if((pbHash = malloc(dwHashLen)) == NULL) {
        printf("Out of memory!\n");
        goto done;
    }
    // Read hash value.
    if(!CryptGetHashParam(hHash, HP_HASHVAL, pbHash, &dwHashLen, 0)) {
        printf("Error %x during reading hash value!\n", GetLastError());
        goto done;
    }
    // Print hash value.
    for(i = 0 ; i < dwHashLen ; i++) {
        printf("%2.2x ",pbHash[i]);
    }
    printf("\n");
    done:
    // Free memory.
    if(pbHash !=NULL) free(pbHash);
    // Destroy hash object.
    if(hHash) CryptDestroyHash(hHash);
    // Release CSP handle.
    if(hProv) CryptReleaseContext(hProv,0);
     
    

    See Also

    CryptCreateHash, CryptGetKeyParam, CryptSetHashParam


    CryptHashData

    The CryptHashData function is used to compute the cryptographic hash on a stream of data. This function and CryptHashSessionKey can be called multiple times to compute the hash on long streams or on discontinuous streams.

    Before calling this function, the CryptCreateHash function must be called to get a handle to a hash object.

    BOOL CRYPTFUNC CryptHashData(
    HCRYPTHASH
    hHash, // in
    BYTE *pbData, // in
    DWORD dwDataLen, // in
    DWORD dwFlags) // in

    Parameters

    hHash

    A handle to the hash object. An application obtains this handle using the CryptCreateHash function.

    pbData

    The address of the data to be hashed.

    dwDataLen

    The number of bytes of data to be hashed. This must be zero if the CRYPT_USERDATA flag is set.

    dwFlags

    The flag values. The following values are currently defined:

    CRYPT_USERDATA

    When this flag is set, the CSP will prompt the user to input some data directly. This is then added to the hash. The application is not allowed access to the data. For example, this flag can be used to allow the user to enter a PIN into the system.

    The Microsoft RSA Base Provider ignores this parameter.

    Return Value

    If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

    The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

    Error                      Description                     
    
                                                               
    
    ERROR_INVALID_HANDLE       One of the parameters           
                               specifies an invalid handle.    
    
    ERROR_INVALID_PARAMETER    One of the parameters contains  
                               an invalid value. This is most  
                               often an illegal pointer.       
    
    NTE_BAD_ALGID              The hHash handle specifies an   
                               algorithm that this CSP does    
                               not support.                    
    
    NTE_BAD_FLAGS              The dwFlags parameter contains  
                               an invalid value.               
    
    NTE_BAD_HASH               The hash object specified by    
                               the hHash parameter is          
                               invalid.                        
    
    NTE_BAD_HASH_STATE         An attempt was made to add      
                               data to a hash object that is   
                               already marked "finished."      
    
    NTE_BAD_KEY                A keyed hash algorithm is       
                               being used, but the session     
                               key is no longer valid. This    
                               error will be generated if the  
                               session key is destroyed        
                               before the hashing operating    
                               is complete.                    
    
    NTE_BAD_LEN                The CRYPT_USERDATA flag is set  
                               and the dwDataLen parameter     
                               has a nonzero value.            
    
    NTE_BAD_UID                The CSP context that was        
                               specified when the hash object  
                               was created cannot be found.    
    
    NTE_FAIL                   The function failed in some     
                               unexpected way.                 
    
    NTE_NO_MEMORY              The CSP ran out of memory       
                               during the operation.           
    
    
    

    Example

    See the "Example" section in the CryptSignHash function.

    See Also

    CryptCreateHash, CryptHashSessionKey


    CryptHashSessionKey

    The CryptHashSessionKey function is used to compute the cryptographic hash on a key object. This function can be called multiple times with the same hash handle to compute the hash on multiple keys. Calls to CryptHashSessionKey can be interspersed with calls to CryptHashData.

    Before calling this function the CryptCreateHash function must be called to get a handle to a hash object.

    BOOL CRYPTFUNC CryptHashSessionKey(
    HCRYPTHASH
    hHash, // in
    HCRYPTKEY hKey, // in
    DWORD dwFlags) // in

    Parameters

    hHash

    A handle to the hash object. An application obtains this handle using the CryptCreateHash function.

    hKey

    A handle to the key object to be hashed.

    dwFlags

    The flag values. This parameter is reserved for future use and should always be zero.

    Return Value

    If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

    The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

    Error                      Description                     
    
                                                               
    
    ERROR_INVALID_HANDLE       One of the parameters           
                               specifies an invalid handle.    
    
    ERROR_INVALID_PARAMETER    One of the parameters contains  
                               an invalid value. This is most  
                               often an illegal pointer.       
    
    NTE_BAD_ALGID              The hHash handle specifies an   
                               algorithm that this CSP does    
                               not support.                    
    
    NTE_BAD_FLAGS              The dwFlags parameter is        
                               nonzero.                        
    
    NTE_BAD_HASH               The hash object specified by    
                               the hHash parameter is          
                               invalid.                        
    
    NTE_BAD_HASH_STATE         An attempt was made to add      
                               data to a hash object that is   
                               already marked "finished."      
    
    NTE_BAD_KEY                A keyed hash algorithm is       
                               being used, but the session     
                               key is no longer valid. This    
                               error will be generated if the  
                               session key is destroyed        
                               before the hashing operating    
                               is complete.                    
    
    NTE_BAD_UID                The CSP context that was        
                               specified when the hash object  
                               was created cannot be found.    
    
    NTE_FAIL                   The function failed in some     
                               unexpected way.                 
    
    
    

    Example

    #include <wincrypt.h>
    HCRYPTPROV hProv = 0;
    HCRYPTHASH hHash = 0;
    HCRYPTKEY hKey   = 0;
    // Get handle to the default provider.
    if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
        printf("Error %x during CryptAcquireContext!\n", GetLastError());
        goto done;
    }
    // Create hash object.
    if(!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) {
        printf("Error %x during CryptBeginHash!\n", GetLastError());
        goto done;
    }
    // Create random session key.
    if(!CryptGenKey(hProv, CALG_RC2, CRYPT_EXPORTABLE, &hKey)) {
        printf("Error %x during CryptGenKey!\n", GetLastError());
        goto done;
    }
    // Hash session key.
    if(!CryptHashSessionKey(hHash, hKey, 0)) {
        printf("Error %x during CryptHashSessionKey!\n", GetLastError());
        goto done;
    }
    // Use the hash object for something.
    ...
    done:
    // Destroy hash object.
    if(hHash) CryptDestroyHash(hHash);
    // Destroy session key.
    if(hKey) CryptDestroyKey(hKey);
    // Release CSP handle.
    if(hProv) CryptReleaseContext(hProv,0);
     
    

    See Also

    CryptCreateHash, CryptGenKey, CryptHashData

    CryptSetHashParam

    The CryptSetHashParam function, in theory, allows applications to customize the operations of a hash object. Currently, only a single parameter is defined for this function.

    BOOL CRYPTFUNC CryptSetHashParam(
    HCRYPTHASH
    hHash, // in
    DWORD dwParam, // in
    BYTE *pbData, // in
    DWORD dwFlags) // in

    Parameters

    hHash

    A handle to the hash object on which to set parameters.

    dwParam

    The parameter number. See the "Remarks" section for a list of valid parameters.

    pbData

    The parameter data buffer. Place the parameter data in this buffer before calling CryptSetHashParam. The form of this data will vary, depending on the parameter number.

    dwFlags

    The flag values. This parameter is reserved for future use and should always be zero.

    Remarks

    The dwParam parameter can be set to one of the following values:

    HP_HASHVAL

    Hash value. The pbData buffer should contain a byte array containing a hash value to place directly into the hash object. Before setting this parameter, the size of the hash value should be determined by reading the HP_HASHSIZE parameter with the CryptGetHashParam function.

    Normal applications should never set this parameter. In fact, some CSPs may not even support this capability. Occasionally though, it is convenient to sign a hash value that has been generated elsewhere. This is the usual sequence of operations:

    1. The application creates a hash object with CryptCreateHash.

    2. It specifies a hash value by setting the HP_HASHVAL parameter.

    3. It signs the hash value using CryptSignHash, obtaining a digital signature block.

    Because the binding between the hashed data and the signature is fairly tenuous, no description string can be passed into CryptSignHash in this situation.

    4. It destroys the hash object using CryptDestroyHash.

    Note that some CSP types may add additional parameters that can be set with this function.

    Return Value

    If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

    The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

    Error                      Description                     
    
                                                               
    
    ERROR_INVALID_HANDLE       One of the parameters           
                               specifies an invalid handle.    
    
    ERROR_BUSY                 The CSP context is currently    
                               being used by another process.  
    
    ERROR_INVALID_PARAMETER    One of the parameters contains  
                               an invalid value. This is most  
                               often an illegal pointer.       
    
    NTE_BAD_FLAGS              The dwFlags parameter is        
                               nonzero or the pbData buffer    
                               contains an invalid value.      
    
    NTE_BAD_HASH               The hash object specified by    
                               the hHash parameter is          
                               invalid.                        
    
    NTE_BAD_TYPE               The dwParam parameter           
                               specifies an unknown            
                               parameter.                      
    
    NTE_BAD_UID                The CSP context that was        
                               specified when the hKey key     
                               was created cannot be found.    
    
    NTE_FAIL                   The function failed in some     
                               unexpected way.                 
    
    
    

    Example

    This function is used in a way similar to the CryptSetKeyParam function.

    See Also

    CryptCreateHash, CryptGetHashParam, CryptSetKeyParam, CryptSignHash

    CryptSignHash

    The CryptSignHash function is used to sign a piece of data. Because all signature algorithms are asymmetric and thus incredibly slow, CryptoAPI will not let data be signed directly. Instead, you must first hash the data and then use CryptSignHash to sign the hash value.

    BOOL CRYPTFUNC CryptSignHash(
    HCRYPTHASH
    hHash, // in
    DWORD dwKeySpec, // in
    LPCTSTR sDescription, // in
    DWORD dwFlags, // in
    BYTE *pbSignature, // out
    DWORD *pdwSigLen) // in, out

    Parameters

    hHash

    A handle to the hash object to be signed.

    dwKeySpec

    The key pair to use to sign the hash. The following keys can be specified:

    AT_KEYEXCHANGE - Exchange private key

    AT_SIGNATURE - Signature private key

    The signature algorithm used is specified when the key pair was originally created.

    The only signature algorithm that the Microsoft RSA Base Provider supports is the RSA Public-Key algorithm.

    sDescription

    The string describing the data to sign. This description text is added to the hash object before the signature is generated. Whenever the signature is authenticated (with CryptVerifySignature), the exact same description string must be supplied. This ensures that both the signer and the authenticator agree on what is being signed or authenticated.

    Some CSPs (not the Microsoft RSA Base Provider) will display this description string to the user. This lets the user confirm what he or she is signing. This protects the user from unscrupulous applications and also reduces misunderstandings.

    This parameter can be NULL if no description string is to included in the signature. Usually, this is only the case when the signature is performed using a signature key that is not legally bound to the user. For example, when a signature operation is performed with the key exchange private key as part of a key exchange protocol, no description string is typically specified.

    dwFlags

    The flag values. This parameter is reserved for future use and should always be zero.

    pbSignature

    The buffer in which the function places the signature data.

    This parameter can be NULL if all you are doing is determining the number of bytes required for the returned signature data.

    pdwSigLen

    The address of the signature data length. Before calling this function, the caller should set this parameter to the length, in bytes, of the pbSignature buffer. Upon return, this address will contain the number of bytes in the signature data.

    If the buffer specified by pbSignature is not large enough to hold the data, the function returns the ERROR_MORE_DATA error code (through GetLastError) and stores the required buffer size, in bytes, into the variable pointed to by pdwSigLen.

    If pbSignature is NULL, then no error is returned and the function stores the size of the data, in bytes, in the variable pointed to by pdwSigLen.

    Remarks

    Before calling this function, the CryptCreateHash function must be called to get a handle to a hash object. The CryptHashData or CryptHashSessionKey function is then used to add the data or session keys to the hash object.

    Once this function has been completed, the only hash function that can be called using the hHash handle is the CryptDestroyHash function.

    Return Value

    If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

    The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

    Error                      Description                     
    
                                                               
    
    ERROR_INVALID_HANDLE       One of the parameters           
                               specifies an invalid handle.    
    
    ERROR_INVALID_PARAMETER    One of the parameters contains  
                               an invalid value. This is most  
                               often an illegal pointer.       
    
    NTE_BAD_ALGID              The hHash handle specifies an   
                               algorithm that this CSP does    
                               not support.                    
    
    NTE_BAD_FLAGS              The dwFlags parameter is        
                               nonzero.                        
    
    NTE_BAD_HASH               The hash object specified by    
                               the hHash parameter is          
                               invalid.                        
    
    NTE_BAD_UID                The CSP context that was        
                               specified when the hash object  
                               was created cannot be found.    
    
    NTE_NO_KEY                 The private key specified by    
                               dwKeySpec does not exist.       
    
    NTE_NO_MEMORY              The CSP ran out of memory       
                               during the operation.           
    
    
    

    Example

    #include <wincrypt.h>
    HCRYPTPROV hProv = 0;
    #define BUFFER_SIZE 256
    BYTE pbBuffer[BUFFER_SIZE];
    HCRYPTHASH hHash = 0;
    BYTE *pbSignature = NULL;
    DWORD dwSigLen;
    LPTSTR szDescription = TEXT("Test Data");
    DWORD i;
    // Get handle to the default provider.
    if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
        printf("Error %x during CryptAcquireContext!\n", GetLastError());
        goto done;
    }
    // Fill buffer with test data.
    for(i = 0 ; i < BUFFER_SIZE ; i++) {
        pbBuffer[i] = (BYTE)i;
    }
    // Create hash object.
    if(!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) {
        printf("Error %x during CryptCreateHash!\n", GetLastError());
        goto done;
    }
    // Hash buffer.
    if(!CryptHashData(hHash, pbBuffer, BUFFER_SIZE, 0)) {
        printf("Error %x during CryptHashData!\n", GetLastError());
        goto done;
    }
    // Determine size of signature and allocate memory.
    dwSigLen = 0;
    if(!CryptSignHash(hHash, AT_SIGNATURE, TEXT(""), 0, NULL, &dwSigLen)) {
        printf("Error %x during CryptSignHash!\n", GetLastError());
        if(GetLastError()!=NTE_BAD_LEN) goto done;
    }
    if((pbSignature = malloc(dwSigLen)) == NULL) {
        printf("Out of memory!\n");
        goto done;
    }
    // Sign hash object.
    if(!CryptSignHash(hHash, AT_SIGNATURE, szDescription, 0, pbSignature, &dwSigLen)) {
        printf("Error %x during CryptSignHash!\n", GetLastError());
        goto done;
    }
    // Store or transmit the signature, test buffer, and description string.
    ...
    done:
    // Free memory used to store signature.
    if(pbSignature != NULL) free(pbSignature);
    // Destroy hash object.
    if(hHash != 0) CryptDestroyHash(hHash);
    // Release provider handle.
    if(hProv != 0) CryptReleaseContext(hProv, 0);
     
    

    See Also

    CryptCreateHash, CryptHashData, CryptVerifySignature


    CryptVerifySignature

    The CryptVerifySignature function is used to verify a signature against a hash object.

    Before calling this function, the CryptCreateHash function must be called to get a handle to a hash object. The CryptHashData and/or CryptHashSessionKey functions are then used to add the data and/or session keys to the hash object.

    Once this function has been completed, the only hash function that can be called using the hHash handle is the CryptDestroyHash function.

    BOOL CRYPTFUNC CryptVerifySignature(
    HCRYPTHASH
    hHash, // in
    BYTE *pbSignature, // in
    DWORD dwSigLen, // in
    HCRYPTKEY hPubKey, // in
    LPCTSTR sDescription, // in
    DWORD dwFlags) // in

    Parameters

    hHash

    A handle to the hash object to verify against.

    pbSignature

    The address of the signature data to be verified.

    dwSigLen

    The number of bytes in the pbSignature signature data.

    hPubKey

    A handle to the public key to use to authenticate the signature. This public key must belong to the key pair that was originally used to create the digital signature.

    sDescription

    String describing the signed data. This must be exactly the same string that was passed in to the CryptSignHash function when the signature was created. If this string does not match, the signature verification will fail.

    When this function is called, some CSPs (not the Microsoft RSA Base Provider) will display this description string to the user, together with an indication of whether the signature verified correctly. This provides the user with the verification results in a way that is completely independent of the application.

    dwFlags

    The flag values. This parameter is reserved for future use and should always be zero.

    Return Value

    If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

    The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

    Error                      Description                     
    
                                                               
    
    ERROR_INVALID_HANDLE       One of the parameters           
                               specifies an invalid handle.    
    
    ERROR_INVALID_PARAMETER    One of the parameters contains  
                               an invalid value. This is most  
                               often an illegal pointer.       
    
    NTE_BAD_FLAGS              The dwFlags parameter is        
                               nonzero.                        
    
    NTE_BAD_HASH               The hash object specified by    
                               the hHash parameter is          
                               invalid.                        
    
    NTE_BAD_KEY                The hPubKey parameter does not  
                               contain a handle to a valid     
                               public key.                     
    
    NTE_BAD_SIGNATURE          The signature failed to         
                               verify. This could be because   
                               the data itself has changed,    
                               the description string did not  
                               match, or the wrong public key  
                               was specified by hPubKey.       
                               This error can also be          
                               returned if the hashing or      
                               signature algorithms do not     
                               match the ones used to create   
                               the signature.                  
    
    NTE_BAD_UID                The CSP context that was        
                               specified when the hash object  
                               was created cannot be found.    
    
    NTE_NO_MEMORY              The CSP ran out of memory       
                               during the operation.           
    
    
    

    Example

    #include <wincrypt.h>
    HCRYPTPROV hProv = 0;
    #define BUFFER_SIZE 256
    BYTE pbBuffer[BUFFER_SIZE];
    HCRYPTHASH hHash = 0;
    HCRYPTKEY hPubKey = 0;
    BYTE *pbSignature = NULL;
    DWORD dwSigLen;
    LPTSTR szDescription = NULL;
    // Get handle to the default provider.
    if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
        printf("Error %x during CryptAcquireContext!\n", GetLastError());
        goto done;
    }
    // Load 'pbBuffer' with 'BUFFER_SIZE' bytes of test data. This must
    // be the same data that was originally signed.
    ...
    // Point 'pbSignature' at the signature created by a previous call
    // to CryptSignHash. Set 'dwSigLen' to the number of bytes in the
    // signature.
    ...
    // Point 'szDescription' at some text describing the data being 
    // signed. This must be the same description text that was originally
    // passed to CryptSignHash.
    ...
    // Get public key of the user that created the digital signature 
    // and import it into the CSP using CryptImportKey. This will return
    // a handle to the public key in 'hPubKey'.
    ...
    // Create hash object.
    if(!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) {
        printf("Error %x during CryptCreateHash!\n", GetLastError());
        goto done;
    }
    // Hash buffer.
    if(!CryptHashData(hHash, pbBuffer, BUFFER_SIZE, 0)) {
        printf("Error %x during CryptHashData!\n", GetLastError());
        goto done;
    }
    // Validate digital signature.
    if(!CryptVerifySignature(hHash, pbSignature, dwSigLen, hPubKey, szDescription, 0)) {
        if(GetLastError() == NTE_BAD_SIGNATURE) {
            printf("Signature failed to validate!\n");
        } else {
            printf("Error %x during CryptSignHash!\n", GetLastError());
        }
    } else {
        printf("Signature validated OK\n");
    }
    done:
    ...
    // Release public key.
    if(hPubKey != 0) CryptDestroyKey(hPubKey);
    // Destroy hash object.
    if(hHash != 0) CryptDestroyHash(hHash);
    // Release provider handle.
    if(hProv != 0) CryptReleaseContext(hProv, 0);
     
    

    See Also

    CryptCreateHash, CryptHashData, CryptSignHash

    CHAPTER 13

    Data Types and Constants

    This section describes some of the data types and constants that are used by the functions in CryptoAPI.


    ALG_ID

    The ALG_ID data type is used to specify algorithm identifiers. Parameters of this data type are passed to most of the functions in CryptoAPI. This data type is defined in the WINCRYPT.H header file as:

    typedef unsigned int ALG_ID;
     
    

    The following table lists the algorithm identifiers that are currently defined. Authors of custom CSPs can define new values.

    Constant           Description                             
    
                                                               
    
    CALG_MD2 *         MD2 hashing algorithm                   
    
    CALG_MD4           MD4 hashing algorithm                   
    
    CALG_MD5 *         MD5 hashing algorithm                   
    
    CALG_SHA *         SHA hashing algorithm                   
    
    CALG_MAC *         MAC keyed hash algorithm                
    
    CALG_RSA_SIGN *    RSA public-key signature algorithm      
    
    CALG_DSS_SIGN      DSA public-key signature algorithm      
    
    CALG_RSA_KEYX *    RSA public-key key exchange algorithm   
    
    CALG_DES           DES encryption algorithm                
    
    CALG_RC2 *         RC2 block encryption algorithm          
    
    CALG_RC4 *         RC4 stream encryption algorithm         
    
    CALG_SEAL          SEAL encryption algorithm               
    
    
    

    The algorithms with an asterisk (*) are supported by the Microsoft RSA Base Provider.


    HCRYPTHASH

    The HCRYPTHASH data type is used to represent handles to a hash object. These handles are used to indicate to the CSP module which hash is being used in a particular operation. The CSP module does not allow direct manipulation of the hash values. Instead, the user manipulates the hash values through the hash handle.

    HCRYPTHASH is defined in the WINCRYPT.H header file as:

    typedef unsigned long HCRYPTHASH;
     
    

    HCRYPTKEY

    The HCRYPTKEY data type is used to represent handles to cryptographic keys. These handles are used to indicate to the CSP module which key is being used in a specific operation. The CSP module does not allow direct access to the key values. Instead, the user performs functions using the key value through the key handle.

    HCRYPTKEY is defined in the WINCRYPT.H header file as:

    typedef unsigned long HCRYPTKEY;
     
    

    HCRYPTPROV

    The HCRYPTPROV data type is used to represent handles to CSPs. These handles are used to indicate which CSP module should perform the specific operation.

    HCRYPTPROV is defined in the WINCRYPT.H header file as:

    typedef unsigned long HCRYPTPROV;
     
    

    MAXUIDLEN

    MAXUIDLEN is a numeric constant that specifies the maximum size for CSP names and key container names. No CSP or key container name can be longer than MAXUIDLEN characters, including the terminating zero.

    MAXUIDLEN is defined in the WINCRYPT.H header file as:

    #define MAXUIDLEN 64
     
    

    MS_DEF_PROV

    MS_DEF_PROV is a string constant set to the name of the Microsoft RSA Base Provider. This constant is used with the CryptAcquireContext CryptSetProvider functions.

    MS_DEF_PROV is defined in the WINCRYPT.H header file as:

    #define MS_DEF_PROV TEXT("Microsoft Base Cryptographic Provider v1.0")