Encrypting and Decrypting Data
A version of this page is also available for
4/8/2010
An encryption key is needed before invoking encryption and decryption operations. This key is obtained by using the CryptGenKey, CryptDeriveKey, or CryptImportKey functions. The encryption algorithm is specified when the key is created. You can also specify additional encryption parameters, using the CryptSetKeyParam function.
For more information about CryptGenKey and CryptDeriveKey, see Generating Cryptographic Keys. For more information about CryptImportKey, see Exporting Cryptographic Keys.
The following table shows the functions you can use to encode and decode a message.
Function | Description |
---|---|
Encodes a section of plaintext, using the specified encryption key. |
|
Decodes a section of cipher, using the specified decryption key. |
To enable the user to decode the data in the future, the CryptExportKey function is used to save the decryption key in a key BLOB that can only be decoded 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. CryptExportKey returns a key BLOB that must be stored by the application for use in decoding the file.
To encode a file so that only the current user can access its data, bulk encode the file with a symmetric cipher. The key to this cipher is kept in the key BLOB that can only be decoded with the user's private key. This technique also works for encoding messages for specific recipients.
To encode a message, a session key must first be generated by using the CryptGenKey function. Calling this function generates a random key and returns a handle so that the key can encode and decode data. You should specify the encryption algorithm at this point. Because CryptoAPI does not permit applications to use public-key algorithms to encode bulk data, call CryptGenKey to specify a symmetric algorithm, such as RC2 or RC4, for your application.
Alternatively, if your application needs to encode the message in such a way that anyone with a specified password can decode the data, the CryptDeriveKey function should be used to transform the password into a key suitable for encryption. In this case, CryptDeriveKey is called instead of CryptGenKey, and the subsequent CryptExportKey calls are not needed.
Once the key is generated, other cryptographic properties of the key can be set with CryptSetKeyParam. For example, different sections of the file can be encoded with different salt values, and the cipher mode or initialization vector can be changed. Applications can generate salt values with the CryptGenRandom function.
In block ciphers, you can change the method of encryption by setting the block cipher properties with CryptSetKeyParam. The following table shows the cipher modes.
Cipher mode | Description |
---|---|
Electronic codebook (ECB) |
Encodes blocks individually. No feedback is used. |
Cipher block chaining (CBC) |
Encodes blocks, using feedback to ensure uniqueness. |
Cipher feedback mode (CFB) |
Encodes small increments of plaintext at a time, not entire blocks. |
Output feedback mode (OFB) |
Encodes similarly to CFB, but uses a different method for filling shift registers. |
In this ECB cipher mode, each block is encoded individually and no feedback is used. This means that identical blocks of plaintext encoded with the same key are transformed into identical cipher blocks. If a single bit of the cipher block is garbled, then the entire corresponding plaintext block is also garbled.
Each plaintext block in this CBC cipher mode is encoded based on the cipher of the previous block. CBC ensures that even if the plaintext contains many identical blocks, each encodes to a different cipher block. Similarly to EBC, if a single bit of the cipher block is garbled, the corresponding plaintext block is also garbled. Moreover, a bit in the subsequent plaintext block in the same position as the original garbled bit, is garbled. If there are extra or missing bytes in the cipher, the plaintext is garbled from that point on.
In this CFB cipher mode, small increments of plaintext can be processed into cipher, instead of processing entire blocks at a time. CFB is useful in some situations. For example, data originating from a keyboard can be encoded at each keystroke without waiting for an entire block to be typed.
This mode uses a shift register that 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 is divided into eight sections.
CFB follows this process for each encryption cycle:
- The shift register is filled with the initialization vector.
- The block in the shift register is encoded.
- The leftmost 8 bits in the encoded shift register are matched with the next 8 bits of plaintext and sent off as 8 bits of cipher.
- The shift register shifts 8 bits to the left.
- The 8 bits of cipher generated in step 2 are placed in the rightmost 8 bits of the shift register.
In CryptoAPI, the number of bits processed at a time is specified by setting the encryption key's KP_MODE_BITS parameter using the CryptSetKeyParam function. The default value for this parameter is typically 8 bits.
If 1 bit in the cipher is garbled, 1 bit in the plaintext is garbled, and the shift register is corrupted. This corruption results in the corrupting of subsequent plaintext blocks until the bad bit is shifted out of the shift register.
This OFB cipher mode is identical to CFB, except the shift register is filled differently. If 1 bit in the cipher is garbled, the corresponding bit of plaintext is also garbled. If there are extra or missing bits from the cipher, the plaintext is garbled from that point on.
If the application does not explicitly specify one of these modes, then CBC is used.
Encode the data in the file with the CryptEncrypt function, which takes the previously generated session key and encodes a buffer of data. As the data is encoded, it may be slightly expanded by the encryption algorithm. The application is responsible for remembering the length of the encoded data so the proper length can later be given to the CryptDecrypt function.
If your application has certificates or public keys for other users, it can permit other users to decode the file by performing CryptExportKey calls for each user to whom it wants to give access. The returned key BLOBs must be stored by the application, as in the previous paragraph.
Once a file or message has been encoded, the following data must be stored by the application:
- Encoded data
- One or more key BLOBs, each containing the session key used to encode the message
- Any salt values specified as the data was encoded
- Any initialization vectors specified as the data was encoded
All parameters that were specified with the CryptSetKeyParam function as the message was being encoded must also be specified as the message is decoded. It may be appropriate to store some of these parameters with the encoded message, as well.
See Also
Concepts
Microsoft Cryptographic System