Decrypt my World

Cryptography, Security, Debugging and more!

P/Invoking CryptoAPI in .NET. Part 2 (C#)

P/Invoking CryptoAPI in .NET. Part 2 (C#)

  • Comments 2

Hi all,

Some time ago I posted the following sample How to call CryptMsg API in streaming mode (C#).Well, I continued working on that CryptMsg sample, and I got many consts, structs and API declarations that may help you if you need to p/invoke CryptoAPI in C#. You may also want to check this other post of mine: P/Invoking CryptoAPI in .NET (C# version), to see more CryptoAPI declarations.

using System;

using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
using System.ComponentModel;
using System.Security.Cryptography;

namespace LargeCMS
{
partial class Win32
{
#region "CONSTS"

internal const int X509_ASN_ENCODING = 0x00000001;
internal const int PKCS_7_ASN_ENCODING = 0x00010000;

internal const int CMSG_SIGNED = 2;
internal const int CMSG_ENVELOPED = 3;
internal const int CMSG_DETACHED_FLAG = 0x00000004;
internal const int CMSG_AUTHENTICATED_ATTRIBUTES_FLAG = 0x00000008;
internal const int CMSG_ENVELOPE_ALGORITHM_PARAM = 15;
internal const int CMSG_ENCODED_SIGNER = 8;
internal const int CMSG_ENCODED_MESSAGE = 29;
internal const int CMSG_CTRL_VERIFY_SIGNATURE = 1;
internal const int CMSG_CTRL_DECRYPT = 2;
internal const int CMSG_CTRL_VERIFY_SIGNATURE_EX = 19;
internal const int CMSG_CTRL_ADD_SIGNER = 6;
internal const int CMSG_CTRL_ADD_CERT = 10;
internal const int CMSG_SIGNER_COUNT_PARAM = 5;
internal const int CMSG_SIGNER_INFO_PARAM = 6;
internal const int CMSG_SIGNER_CERT_INFO_PARAM = 7;
internal const int CMSG_CERT_COUNT_PARAM = 11;
internal const int CMSG_CERT_PARAM = 12;
internal const int CMSG_RECIPIENT_COUNT_PARAM = 17;
internal const int CMSG_RECIPIENT_INFO_PARAM = 19;
internal const int CMSG_VERIFY_SIGNER_CERT = 2;
internal const int CMSG_RC4_NO_SALT_FLAG = 0x40000000;

internal const int AT_KEYEXCHANGE = 1;
internal const int AT_SIGNATURE = 2;

internal const String szOID_OIWSEC_rsaSign = "1.3.14.3.2.11";
internal const String szOID_OIWSEC_shaRSA = "1.3.14.3.2.15";
internal const String szOID_OIWSEC_sha = "1.3.14.3.2.18";
internal const String szOID_OIWSEC_sha1 = "1.3.14.3.2.26";
internal const String szOID_OIWSEC_sha1RSASign = "1.3.14.3.2.29";
internal const String szOID_RSA_RC4 = "1.2.840.113549.3.4";
internal const String szOID_RSA_DES_EDE3_CBC = "1.2.840.113549.3.7";
internal const String szOID_RSA_signingTime = "1.2.840.113549.1.9.5";

internal const int X509_NAME = 7;

internal const int CERT_STORE_PROV_MSG = 1;
internal const int CERT_CLOSE_STORE_FORCE_FLAG = 1;
internal const int CERT_KEY_PROV_INFO_PROP_ID = 2;
internal const int CERT_STORE_PROV_SYSTEM = 10;

internal const int CERT_SYSTEM_STORE_CURRENT_USER = 1 << 16;

#endregion

#region "STRUCTS"

[StructLayout(LayoutKind.Sequential)]
internal struct CRYPT_ALGORITHM_IDENTIFIER
{
public string pszObjId;
public BLOB Parameters;

public void Dispose()
{
Parameters.Dispose();
}
}

[StructLayout(LayoutKind.Sequential)]
internal struct CERT_ID
{
public int dwIdChoice;
public BLOB IssuerSerialNumberOrKeyIdOrHashId;
}

[StructLayout(LayoutKind.Sequential)]
internal struct CRYPT_ATTRIBUTE
{
public string pszObjId;
public int cValue;
public IntPtr rgValue;

public void Dispose()
{
if (!rgValue.Equals(IntPtr.Zero)) { Marshal.FreeHGlobal(rgValue); }
}
}

[StructLayout(LayoutKind.Sequential)]
internal struct CMSG_SIGNER_ENCODE_INFO
{
public int cbSize;
public IntPtr pCertInfo;
public IntPtr hCryptProvOrhNCryptKey;
public int dwKeySpec;
public CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm;
public IntPtr pvHashAuxInfo;
public int cAuthAttr;
public IntPtr rgAuthAttr;
public int cUnauthAttr;
public IntPtr rgUnauthAttr;
public CERT_ID SignerId;
public CRYPT_ALGORITHM_IDENTIFIER HashEncryptionAlgorithm;
public IntPtr pvHashEncryptionAuxInfo;

public void Dispose()
{
if (!hCryptProvOrhNCryptKey.Equals(IntPtr.Zero)) { Win32.CryptReleaseContext(hCryptProvOrhNCryptKey, 0); }
if (!rgAuthAttr.Equals(IntPtr.Zero)) { Marshal.FreeHGlobal(rgAuthAttr); }
if (!rgUnauthAttr.Equals(IntPtr.Zero)) { Marshal.FreeHGlobal(rgUnauthAttr); }
}
}

[StructLayout(LayoutKind.Sequential)]
internal struct CERT_CONTEXT
{
public int dwCertEncodingType;
public IntPtr pbCertEncoded;
public int cbCertEncoded;
public IntPtr pCertInfo;
public IntPtr hCertStore;
}

[StructLayout(LayoutKind.Sequential)]
internal struct BLOB
{
public int cbData;
public IntPtr pbData;

public void Dispose()
{
if (!pbData.Equals(IntPtr.Zero)) { Marshal.FreeHGlobal(pbData); }
}
}

[StructLayout(LayoutKind.Sequential)]
internal struct CRYPT_BIT_BLOB
{
public int cbData;
public IntPtr pbData;
public int cUnusedBits;
}

[StructLayout(LayoutKind.Sequential)]
internal struct CMSG_SIGNED_ENCODE_INFO
{
public int cbSize;
public int cSigners;
public IntPtr rgSigners;
public int cCertEncoded;
public IntPtr rgCertEncoded;
public int cCrlEncoded;
public IntPtr rgCrlEncoded;
public int cAttrCertEncoded;
public IntPtr rgAttrCertEncoded;

public void Dispose()
{
if (!rgSigners.Equals(IntPtr.Zero)) { Marshal.FreeHGlobal(rgSigners); }
if (!rgCertEncoded.Equals(IntPtr.Zero)) { Marshal.FreeHGlobal(rgCertEncoded); }
if (!rgCrlEncoded.Equals(IntPtr.Zero)) { Marshal.FreeHGlobal(rgCrlEncoded); }
if (!rgAttrCertEncoded.Equals(IntPtr.Zero)) { Marshal.FreeHGlobal(rgAttrCertEncoded); }
}
}

[StructLayout(LayoutKind.Sequential)]
internal struct CRYPT_ATTRIBUTES
{
public int cAttr;
public IntPtr rgAttr;
}

[StructLayout(LayoutKind.Sequential)]
internal struct CMSG_SIGNER_INFO
{
public int dwVersion;
public BLOB Issuer;
public BLOB SerialNumber;
public CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm;
public CRYPT_ALGORITHM_IDENTIFIER HashEncryptionAlgorithm;
public BLOB EncryptedHash;
public CRYPT_ATTRIBUTES AuthAttrs;
public CRYPT_ATTRIBUTES UnauthAttrs;
}

[StructLayout(LayoutKind.Sequential)]
internal struct CMSG_STREAM_INFO
{
public int cbContent;
public StreamOutputCallbackDelegate pfnStreamOutput;
public IntPtr pvArg;
}

[StructLayout(LayoutKind.Sequential)]
internal struct CERT_PUBLIC_KEY_INFO
{
public CRYPT_ALGORITHM_IDENTIFIER Algorithm;
public CRYPT_BIT_BLOB PublicKey;
}

[StructLayout(LayoutKind.Sequential)]
internal struct FILETIME
{
public int dwLowDateTime;
public int dwHighDateTime;
}

[StructLayout(LayoutKind.Sequential)]
internal struct CERT_INFO
{
public int dwVersion;
public BLOB SerialNumber;
public CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm;
public BLOB Issuer;
public FILETIME NotBefore;
public FILETIME NotAfter;
public BLOB Subject;
public CERT_PUBLIC_KEY_INFO SubjectPublicKeyInfo;
public CRYPT_BIT_BLOB IssuerUniqueId;
public CRYPT_BIT_BLOB SubjectUniqueId;
public int cExtension;
public IntPtr rgExtension;
}

[StructLayout(LayoutKind.Sequential)]
internal struct CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA
{
public int cbSize;
public IntPtr hCryptProv;
public int dwSignerIndex;
public int dwSignerType;
public IntPtr pvSigner;
}

[StructLayout(LayoutKind.Sequential)]
internal struct CMSG_ENVELOPED_ENCODE_INFO
{
public int cbSize;
public IntPtr hCryptProv;
public CRYPT_ALGORITHM_IDENTIFIER ContentEncryptionAlgorithm;
public IntPtr pvEncryptionAuxInfo;
public int cRecipients;
public IntPtr rgpRecipients;
public IntPtr rgCmsRecipients;
public int cCertEncoded;
public IntPtr rgCertEncoded;
public int cCrlEncoded;
public IntPtr rgCrlEncoded;
public int cAttrCertEncoded;
public IntPtr rgAttrCertEncoded;
public int cUnprotectedAttr;
public IntPtr rgUnprotectedAttr;

public void Dispose()
{
ContentEncryptionAlgorithm.Dispose();
if (!pvEncryptionAuxInfo.Equals(IntPtr.Zero)) { Marshal.FreeHGlobal(pvEncryptionAuxInfo); }
if (!rgpRecipients.Equals(IntPtr.Zero)) { Marshal.FreeHGlobal(rgpRecipients); }
}
}

[StructLayout(LayoutKind.Sequential)]
internal struct CMSG_RC4_AUX_INFO
{
public int cbSize;
public int dwBitLen;
}

[StructLayout(LayoutKind.Sequential)]
internal struct CMSG_CTRL_DECRYPT_PARA
{
public int cbSize;
public IntPtr hCryptProvOrNCryptKey;
public int dwKeySpec;
public int dwRecipientIndex;
}

[StructLayout(LayoutKind.Sequential)]
internal struct CRYPT_KEY_PROV_INFO
{
[MarshalAs(UnmanagedType.LPWStr)]public string pwszContainerName;
[MarshalAs(UnmanagedType.LPWStr)]public string pwszProvName;
public int dwProvType;
public int dwFlags;
public int cProvParam;
public IntPtr rgProvParam;
public int dwKeySpec;
}

#endregion

#region "DELEGATES"

internal delegate Boolean StreamOutputCallbackDelegate(IntPtr pvArg, IntPtr pbData, int cbData, Boolean fFinal);

#endregion

#region "API"

[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern Boolean CryptAcquireContext(
out SafeCSPHandle hProv,
string pszContainer,
string pszProvider,
int dwProvType,
int dwFlags
);

[DllImport("crypt32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
internal static extern bool CryptEncodeObject(
int dwCertEncodingType,
string lpszStructType,
ref long pvStructInfo,
SafeNTHeapHandle pbEncoded,
ref int pcbEncoded
);

[DllImport("crypt32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
internal static extern Boolean CryptDecodeObject(
int dwCertEncodingType,
string lpszStructType,
IntPtr pbEncoded,
int cbEncoded,
int dwFlags,
out long pvStructInfo,
ref int pcbStructInfo
);
[DllImport("crypt32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
internal static extern Boolean CryptDecodeObject(
int dwCertEncodingType,
int lpszStructType,
IntPtr pbEncoded,
int cbEncoded,
int dwFlags,
StringBuilder pvStructInfo,
ref int pcbStructInfo
);

[DllImport("Crypt32.dll", SetLastError = true)]
internal static extern SafeMsgHandle CryptMsgOpenToEncode(
int dwMsgEncodingType,
int dwFlags,
int dwMsgType,
ref CMSG_SIGNED_ENCODE_INFO pvMsgEncodeInfo,
string pszInnerContentObjID,
ref CMSG_STREAM_INFO pStreamInfo
);
[DllImport("Crypt32.dll", SetLastError = true)]
internal static extern SafeMsgHandle CryptMsgOpenToEncode(
int dwMsgEncodingType,
int dwFlags,
int dwMsgType,
ref CMSG_ENVELOPED_ENCODE_INFO pvMsgEncodeInfo,
string pszInnerContentObjID,
ref CMSG_STREAM_INFO pStreamInfo
);

[DllImport("Crypt32.dll", SetLastError = true)]
internal static extern SafeMsgHandle CryptMsgOpenToDecode(
int dwMsgEncodingType,
int dwFlags,
int dwMsgType,
IntPtr hCryptProv,
IntPtr pRecipientInfo,
ref CMSG_STREAM_INFO pStreamInfo
);
[DllImport("Crypt32.dll", SetLastError = true)]
internal static extern SafeMsgHandle CryptMsgOpenToDecode(
int dwMsgEncodingType,
int dwFlags,
int dwMsgType,
IntPtr hCryptProv,
IntPtr pRecipientInfo,
IntPtr pStreamInfo
);

[DllImport("Crypt32.dll", SetLastError = true)]
internal static extern Boolean CryptMsgClose(
IntPtr hCryptMsg
);

[DllImport("Crypt32.dll", SetLastError = true)]
internal static extern Boolean CryptMsgUpdate(
IntPtr hCryptMsg,
Byte[] pbData,
int cbData,
Boolean fFinal
);

[DllImport("Crypt32.dll", SetLastError = true)]
internal static extern Boolean CryptMsgUpdate(
IntPtr hCryptMsg,
IntPtr pbData,
int cbData,
Boolean fFinal
);

[DllImport("Crypt32.dll", SetLastError = true)]
internal static extern Boolean CryptMsgGetParam(
SafeMsgHandle hCryptMsg,
int dwParamType,
int dwIndex,
SafeNTHeapHandle pvData,
ref int pcbData
);
[DllImport("Crypt32.dll", SetLastError = true)]
internal static extern Boolean CryptMsgGetParam(
SafeMsgHandle hCryptMsg,
int dwParamType,
int dwIndex,
out int pvData,
ref int pcbData
);

[DllImport("Crypt32.dll", SetLastError = true)]
internal static extern Boolean CryptMsgControl(
SafeMsgHandle hCryptMsg,
int dwFlags,
int dwCtrlType,
IntPtr pvCtrlPara
);
[DllImport("Crypt32.dll", SetLastError = true)]
internal static extern Boolean CryptMsgControl(
SafeMsgHandle hCryptMsg,
int dwFlags,
int dwCtrlType,
ref CMSG_SIGNER_ENCODE_INFO pvCtrlPara
);
[DllImport("Crypt32.dll", SetLastError = true)]
internal static extern Boolean CryptMsgControl(
SafeMsgHandle hCryptMsg,
int dwFlags,
int dwCtrlType,
ref BLOB pvCtrlPara
);
[DllImport("Crypt32.dll", SetLastError = true)]
internal static extern Boolean CryptMsgControl(
SafeMsgHandle hCryptMsg,
int dwFlags,
int dwCtrlType,
ref CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA pvCtrlPara
);
[DllImport("Crypt32.dll", SetLastError = true)]
internal static extern Boolean CryptMsgControl(
SafeMsgHandle hCryptMsg,
int dwFlags,
int dwCtrlType,
ref CMSG_CTRL_DECRYPT_PARA pvCtrlPara
);

[DllImport("advapi32.dll", SetLastError = true)]
internal static extern Boolean CryptReleaseContext(
IntPtr hProv,
int dwFlags
);

[DllImport("Crypt32.dll", SetLastError = true)]
internal static extern SafeCertContextHandle CertCreateCertificateContext(
int dwCertEncodingType,
SafeNTHeapHandle pbCertEncoded,
int cbCertEncoded
);

[DllImport("Crypt32.dll", SetLastError = true)]
internal static extern Boolean CertFreeCertificateContext(
IntPtr pCertContext
);

[DllImport("Crypt32.dll", SetLastError = true)]
internal static extern SafeStoreHandle CertOpenStore(
int lpszStoreProvider,
int dwMsgAndCertEncodingType,
IntPtr hCryptProv,
int dwFlags,
SafeMsgHandle pvPara
);

[DllImport("Crypt32.dll", SetLastError = true)]
internal static extern SafeStoreHandle CertOpenSystemStore(
IntPtr hprov,
string szSubsystemProtocol
);

[DllImport("Crypt32.dll", SetLastError = true)]
internal static extern SafeCertContextHandle CertGetSubjectCertificateFromStore(
SafeStoreHandle hCertStore,
int dwCertEncodingType,
SafeNTHeapHandle pCertId
);

[DllImport("Crypt32.dll", SetLastError = true)]
internal static extern IntPtr CertCloseStore(
IntPtr hCertStore,
int dwFlags
);

[DllImport("Crypt32.dll", SetLastError = true)]
internal static extern bool CertGetCertificateContextProperty(
SafeCertContextHandle pCertContext,
int dwPropId,
SafeNTHeapHandle pvData,
ref int pcbData
);

[DllImport("msvcrt.dll", EntryPoint = "memset", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
internal static extern IntPtr MemSet(
IntPtr ptr,
int value,
int num
);

#endregion
}
}

I hope this helps.

Regards,

 

Alex (Alejandro Campos Magencio)

  • Hi Alejandro,

    Would you kindly present a solution, where you can retrieve certain attributes of signed executable using P/Invoking. I'm particulary interested how to retrieve Countersignature TimeStamp property and convert it to DateTime object using C#.

    Thanks.

  • Hi Martin,

    I would love to do that, but that is out of the scope of this blog. Have you checked this post of mine, where I do all kind of things with these APIs?

    How to call CryptMsg API in streaming mode - LargeCMS full sample

    blogs.msdn.com/.../how-to-call-cryptmsgapi-in-streaming-mode-largecms-full-sample.aspx

    I hope that helps. If not, you may open a support case with us so we can assist you with that task.

    Regards,

    Alex

Page 1 of 1 (2 items)
Leave a Comment
  • Please add 7 and 2 and type the answer here:
  • Post
Translate This Page