1 out of 14 rated this helpful - Rate this topic

CryptEncrypt function

Applies to: desktop apps only

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

Important changes to support Secure/Multipurpose Internet Mail Extensions (S/MIME) email interoperability have been made to CryptoAPI that affect the handling of enveloped messages. For more information, see the Remarks section of CryptMsgOpenToEncode.

Important  The CryptEncrypt function is not guaranteed to be thread safe and may return incorrect results if invoked simultaneously by multiple callers.

Syntax

BOOL WINAPI CryptEncrypt(
  __in     HCRYPTKEY hKey,
  __in     HCRYPTHASH hHash,
  __in     BOOL Final,
  __in     DWORD dwFlags,
  __inout  BYTE *pbData,
  __inout  DWORD *pdwDataLen,
  __in     DWORD dwBufLen
);

Parameters

hKey [in]

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

The key specifies the encryption algorithm used.

hHash [in]

A handle to a hash object. 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 is updated with the plaintext passed in. This option is useful when generating signed and encrypted text.

Before calling CryptEncrypt, the application must obtain a handle to the hash object by calling the CryptCreateHash function. After the encryption is complete, the hash value can be obtained by using the CryptGetHashParam function, or the hash can be signed by using the CryptSignHash function.

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

Final [in]

A Boolean value that specifies whether this is the last section in a series being encrypted. Final is set to TRUE for the last or only block and to FALSE if there are more blocks to be encrypted. For more information, see Remarks.

dwFlags [in]

The following dwFlags value is defined but reserved for future use.

ValueMeaning
CRYPT_OAEP

Use Optimal Asymmetric Encryption Padding (OAEP) (PKCS #1 version 2). This flag is only supported by the Microsoft Enhanced Cryptographic Provider with RSA encryption/decryption.

Windows 2000:  This flag is not supported.

 

pbData [in, out]

A pointer to a buffer that contains the plaintext to be encrypted. The plaintext in this buffer is overwritten with the ciphertext created by this function.

The pdwDataLen parameter points to a variable that contains the length, in bytes, of the plaintext. The dwBufLen parameter contains the total size, in bytes, of this buffer.

If this parameter contains NULL, this function will calculate the required size for the ciphertext and place that in the value pointed to by the pdwDataLen parameter.

pdwDataLen [in, out]

A pointer to a DWORD value that , on entry, contains the length, in bytes, of the plaintext in the pbData buffer. On exit, this DWORD contains the length, in bytes, of the ciphertext written to the pbData buffer.

If the buffer allocated for pbData is not large enough to hold the encrypted data, GetLastError returns ERROR_MORE_DATA and stores the required buffer size, in bytes, in the DWORD value pointed to by pdwDataLen.

If pbData is NULL, no error is returned, and the function stores the size of the encrypted data, in bytes, in the DWORD value pointed to by pdwDataLen. This allows an application to determine the correct buffer size.

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 parameter is TRUE.

dwBufLen [in]

Specifies the total size, in bytes, of the input pbData buffer.

Note that, depending on the algorithm used, the encrypted text can be larger than the original plaintext. In this case, the pbData buffer needs to be large enough to contain the encrypted text and any padding.

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

Return value

If the function succeeds, the function returns nonzero (TRUE).

If the function fails, it returns zero (FALSE). For extended error information, call GetLastError.

The error codes prefaced by NTE are generated by the particular CSP being used. Some possible error codes follow.

ValueDescription
ERROR_INVALID_HANDLE

One of the parameters specifies a handle that is not valid.

ERROR_INVALID_PARAMETER

One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.

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 not valid. 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 a handle that is not valid.

NTE_BAD_HASH_STATE

An attempt was made to add data to a hash object that is already marked "finished."

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.

 

Remarks

If a large amount of data is to be encrypted, it can be done in sections by calling CryptEncrypt repeatedly. The Final parameter must be set to TRUE on the last call to CryptEncrypt, so that 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 is padded to a multiple of the block size of the cipher. If the data length equals the block size of the cipher, one additional block of padding is appended to the data. To find the block size of a cipher, use CryptGetKeyParam to get the KP_BLOCKLEN value of the key.
  • If the cipher is operating in a chaining mode, the next CryptEncrypt operation resets the cipher's feedback register to the KP_IV value of the key.
  • If the cipher is a stream cipher, the next CryptEncrypt resets the cipher to its initial state.

There is no way to set the cipher's feedback register to the KP_IV value of the key without setting the Final parameter to TRUE. If this is necessary, as in the case where you do not want to add an additional padding block or change the size of each block, you can simulate this by creating a duplicate of the original key by using the CryptDuplicateKey function, and passing the duplicate key to the CryptEncrypt function. This causes the KP_IV of the original key to be placed in the duplicate key. After you create or import the original key, you cannot use the original key for encryption because the feedback register of the key will be changed. The following pseudocode shows how this can be done.

// Set the IV for the original key. Do not use the original key for 
// encryption or decryption after doing this because the key's 
// feedback register will get modified and you cannot change it.
CryptSetKeyParam(hOriginalKey, KP_IV, newIV)

while(block = NextBlock())
{
    // Create a duplicate of the original key. This causes the 
    // original key's IV to be copied into the duplicate key's 
    // feedback register.
    hDuplicateKey = CryptDuplicateKey(hOriginalKey)

    // Encrypt the block with the duplicate key.
    CryptEncrypt(hDuplicateKey, block)

    // Destroy the duplicate key. Its feedback register has been 
    // modified by the CryptEncrypt function, so it cannot be used
    // again. It will be re-duplicated in the next iteration of the 
    // loop.
    CryptDestroyKey(hDuplicateKey)
}

The Microsoft Enhanced Cryptographic Provider supports direct encryption with RSA public keys and decryption with RSA private keys. The encryption uses PKCS #1 padding. On decryption, this padding is verified. The length of plaintext data that can be encrypted with a call to CryptEncrypt with an RSA key is the length of the key modulus minus eleven bytes. The eleven bytes is the chosen minimum for PKCS #1 padding. The ciphertext is returned in little-endian format.

Examples

For examples that use this function, see Example C Program: Encrypting a File and Example C Program: Decrypting a File.

Requirements

Minimum supported client

Windows 2000 Professional

Minimum supported server

Windows 2000 Server

Header

Wincrypt.h

Library

Advapi32.lib

DLL

Advapi32.dll

See also

Data Encryption and Decryption Functions
CryptCreateHash
CryptDecrypt
CryptGenKey
CryptGetHashParam
CryptGetKeyParam
CryptImportKey
CryptMsgOpenToEncode
CryptSignHash

 

 

Send comments about this topic to Microsoft

Build date: 3/6/2012

Did you find this helpful?
(1500 characters remaining)
Community Content Add
Annotations FAQ
Wierd
I am observing wierd behaviour of this function, the string that I want to encrypt contains 14 bytes, if I use the function to send lenght of buffer = 14, it fails ("an internal error" - very descriptive and most helpful error code), but it works when the buffer length (and the buffer itself) is 128 bytes large.

I overcame this problem by making a size 128 byte array and I copied the 14 bytes from the plain text (that I wish to encrypt),

When I decrypt those bytes, I must once again give the function the whole 128 byte array (which now has every byte encrypted, even the ones from #13-#127 (which I guess is to be expected)). Luckily for me the first 14 bytes get decrypted as they should, the rest is gibberish.

I would like to know why the encrypt method fails if the incoming buffer isnt 128 byte large, and also why decrypt function also requires a 128 byte array, is it some padding thing?

This is how I call the encrypt function:

System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();  // encoding type
byte[] buff = new byte[128];     // this is my buffer array, instantiated and initiated
string String2Encrypt = "Testing";      // this is the string I need encrypted
byte[] tempo = encoding.GetBytes(String2Encrypt);   // getting bytes from string
Buffer.BlockCopy(tempo, 0, buff, 0, tempo.Length);    // copying the small array into the large one
uint inputlength = Convert.ToUInt32(tempo.Length);   // getting the size of the small array


bool DidIt = UnsafeNativeMethods.CryptEncrypt(MyKey, IntPtr.Zero, 1, 0, buff, ref inputlength, outputdatalength);     // calling the function

// in this case, the MyKey is pointer to a crypto key, 2nd argument is null, 3rd is "true" (no more data), no flags, buffer byte array  (128), Testing.Length in this case it is 7, 128



This is how I decrypt it:

IntPtr UserKeyLocal = MyUserKey;     // taking an argument (MyUserKey) and "filling" the local variable, not really relevant
byte[] dataCopy = new byte[buff.Length];   // init and insta the datacopy array (128 byte)
Buffer.BlockCopy(buff, 0, dataCopy, 0, (int)buff.Length);   // copying the argument array into a local version (I used this for testing to go around another problem), irrelevant
uint locinputlength = inputlength;  // another argument made local
bool DidIT = UnsafeNativeMethods.CryptDecrypt(UserKeyLocal, IntPtr.Zero, true, 0, dataCopy, ref locinputlength);     // calling the function

The result would look like this:
Testing?R????7?q???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
Its almost working as intended but I need to be able to get ONLY the "Testing" part of the string without using tricks like substringing.

What I am trying to do (maybe there is an alternative way) is this; I have a binary (file) that has in it "Testing" encrypted by a public key I got from a certificate which I exported form a SmartCard.
I need to verify (decrypt) this file by using my SmartCard (I am using its propriety CSP) with the private key. As you can see, it ALMOST works.


Thanks in advance.
CryptEncrypt and thread safety
This statement from the page above:

Important  The CryptEncrypt function is not guaranteed to be thread safe and may return incorrect results if invoked simultaneously by multiple callers.

, doesn't make any sense, unless you meant to say that CryptEncrypt isn't thread safe when invoked by multiple callers with the same hKey or hHash or pbData or pwdDataLen or any combination of these. As written, it sounds like there may be only one encryption going on at any given time within a process.

Question
How function determines what need to encrypted when pbData is NULL?

If this parameter contains NULL, this function will calculate the required size for the ciphertext and place that in the value pointed to by the pdwDataLen parameter.