This topic has not yet been rated - Rate this topic

CryptDecryptMessage function

Applies to: desktop apps only

The CryptDecryptMessage function decodes and decrypts a message.

Syntax

BOOL WINAPI CryptDecryptMessage(
  __in         PCRYPT_DECRYPT_MESSAGE_PARA pDecryptPara,
  __in         const BYTE *pbEncryptedBlob,
  __in         DWORD cbEncryptedBlob,
  __out_opt    BYTE *pbDecrypted,
  __inout_opt  DWORD *pcbDecrypted,
  __out_opt    PCCERT_CONTEXT *ppXchgCert
);

Parameters

pDecryptPara [in]

A pointer to a CRYPT_DECRYPT_MESSAGE_PARA structure that contains decryption parameters.

pbEncryptedBlob [in]

A pointer to a buffer that contains the encoded and encrypted message to be decrypted.

cbEncryptedBlob [in]

The size, in bytes, of the encoded and encrypted message.

pbDecrypted [out, optional]

A pointer to a buffer that receives the decrypted message.

To set the size of this information for memory allocation purposes, this parameter can be NULL. A decrypted message will not be returned if this parameter is NULL. For more information, see Retrieving Data of Unknown Length.

pcbDecrypted [in, out, optional]

A pointer to a DWORD that specifies the size, in bytes, of the buffer pointed to by the pbDecrypted parameter. When the function returns, this variable contains the size, in bytes, of the decrypted message copied to pbDecrypted.

Note  When processing the data returned in the pbDecrypted buffer, applications must use the actual size of the data returned. The actual size can be slightly smaller than the size of the buffer specified in pcbDecrypted on input. On input, buffer sizes are usually specified large enough to ensure that the largest possible output data will fit in the buffer. On output, the DWORD is updated to the actual size of the data copied to the buffer.

ppXchgCert [out, optional]

A pointer to a CERT_CONTEXT structure of a certificate that corresponds to the private exchange key needed to decrypt the message. To indicate that the function should not return the certificate context used to decrypt, set this parameter to NULL.

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.

Note  Errors from calls to CryptImportKey and CryptDecrypt might be propagated to this function.

The GetLastError function returns the following error codes most often.

Return codeDescription
ERROR_MORE_DATA

If the buffer specified by the pbDecrypted parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code, and stores the required buffer size, in bytes, in the variable pointed to by pcbDecrypted.

E_INVALIDARG

Invalid message and certificate encoding types. Currently only PKCS_7_ASN_ENCODING and X509_ASN_ENCODING_TYPE are supported. Invalid cbSize in *pDecryptPara.

CRYPT_E_UNEXPECTED_MSG_TYPE

Not an enveloped cryptographic message.

NTE_BAD_ALGID

The message was encrypted by using an unknown or unsupported algorithm.

CRYPT_E_NO_DECRYPT_CERT

No certificate was found having a private key property to use for decrypting.

 

If the function fails, GetLastError may return an Abstract Syntax Notation One (ASN.1) encoding/decoding error. For information about these errors, see ASN.1 Encoding/Decoding Return Values.

Remarks

When NULL is passed for pbDecrypted, and pcbDecrypted is not NULL, NULL is returned for the address passed in ppXchgCert; otherwise, a pointer to a CERT_CONTEXT is returned. For a successfully decrypted message, this pointer to a CERT_CONTEXT points to the certificate context used to decrypt the message. It must be freed by calling CertFreeCertificateContext. If the function fails, the value at ppXchgCert is set to NULL.

Examples

For an example that uses this function, see Example C Program: Using CryptEncryptMessage and CryptDecryptMessage.

Requirements

Minimum supported client

Windows 2000 Professional

Minimum supported server

Windows 2000 Server

Header

Wincrypt.h

Library

Crypt32.lib

DLL

Crypt32.dll

See also

Simplified Message Functions
CryptDecryptAndVerifyMessageSignature

 

 

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
CryptDecryptMessage fails with NTE_BAD_KEY - 80090003 - -2146893821

If a certificate is generated without the Key Encipherment and/or Data Encipherment bits in the Key Usage, then you may get strange behaviour when trying to decrypt a message. A short description:

Process A Encrypts a piece of data for Process B and signs with a certificate. Process B decrypts the encrypted data, reads the signature, and encrypts a message to return to Process A (using the key from the signature and signing with the decryption key). The return packet is transmitted to Process A, which attempts to decrypt. The first call to CryptDecryptMessage works fine and sets the buffer size (set pbDecrypted to null and ppXchgCert to null). Once you have a valid buffer to receive the decrypted data and recipient certificate, however, the second call to CryptDecryptMessage fails with NTE_BAD_KEY.

There are a few reasons for this discussed in various forums. In my case it was because I was not setting the Key Encipherment and Data Encipherment bits on the Key Usage in the request. If you are using XEnroll or CERTENROLL, both default to leaving these bits off (CERTENROLL also leaves off NonRepudiation). In order to set these, I offer two code snippets as clues.

For XEnroll (Win2K, XP, Server 2003) in C# (Assuming you have a reference for XENROLLLib):


XENROLLLib.ICEnroll4 control = new XENROLLLib.CEnroll();
//See Xenroll.h in the SDK or certrqma.asp in a certsrv folder for a definition of these types of constants.
const int AT_KEYEXCHANGE = 1;
const int CERT_FRIENDLY_NAME_PROP_ID = 11;
const int XECP_STRING_PROPERTY = 1;
const int XECR_CMC = 3;
control.GenKeyFlags = CRYPT_EXPORTABLE;
if (mCommonName != null)
control.addBlobPropertyToCertificate(CERT_FRIENDLY_NAME_PROP_ID, XECP_STRING_PROPERTY, mCommonName + " " + System.DateTime.Today.ToShortDateString());
if (mIntendedUse == IntendedUses.ServerAuthentication)
control.RequestStoreFlags = CERT_SYSTEM_STORE_LOCAL_MACHINE;

//These next two are the lines in question.
control.KeySpec = AT_KEYEXCHANGE;
control.LimitExchangeKeyToEncipherment = 0;
result = control.createRequest(XECR_CMC, mSubject, mIntendedUse);

For CERTEnroll (Vista, Server 2008) in C# (Assuming you have a reference for CERTENROLLLib):

//There is a lot of code missing here to create the entire request...



CERTENROLLLib.CX509CertificateRequestPkcs10 pkcs10request = new CERTENROLLLib.CX509CertificateRequestPkcs10();

CERTENROLLLib.CX509ExtensionKeyUsage baseKeyUsage = new CERTENROLLLib.CX509ExtensionKeyUsage();


baseKeyUsage.InitializeEncode(CERTENROLLLib.X509KeyUsageFlags.XCN_CERT_DATA_ENCIPHERMENT_KEY_USAGE
| CERTENROLLLib.X509KeyUsageFlags.XCN_CERT_DIGITAL_SIGNATURE_KEY_USAGE
| CERTENROLLLib.X509KeyUsageFlags.XCN_CERT_NON_REPUDIATION_KEY_USAGE
| CERTENROLLLib.X509KeyUsageFlags.XCN_CERT_KEY_ENCIPHERMENT_KEY_USAGE);

pkcs10request.X509Extensions.Add((CERTENROLLLib.CX509Extension)baseKeyUsage);