I'm trying to sign a message using CrytpoAPI (I can't use CAPICOM
because I have Biztalk could verify this sign).
I'm traslating the example in MSDN library at
http://msdn.microsoft.com/library/de..._signature.asp
I tried this:
// CERT_CONTEXT
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
private struct CERT_CONTEXT
{
public int dwCertEncodingType;
public IntPtr pbCertEncoded;
public int cbCertEncoded;
public IntPtr pCertInfo;
public IntPtr hCertStore;
}
// CRYPT_ALGORITHM_IDENTIFIER
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
private struct CRYPT_ALGORITHM_IDENTIFIER
{
public IntPtr pszObjId;
public CRYPTOAPI_BLOB Parameters;
}
// CRYPTOAPI_BLOB
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
private struct CRYPTOAPI_BLOB
{
public int cbData;
public IntPtr pbData;
}
// CRYPTO_SIGN_MESSAGE_PARA
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
private struct CRYPT_SIGN_MESSAGE_PARA
{
public UInt32 cbSize;
public UInt32 dwMsgEncodingType;
public CERT_CONTEXT pSigningCert;
public CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm;
public IntPtr pvHashAuxInfo;
public UInt32 cMsgCert;
public IntPtr rgpMsgCert;
public UInt32 cMsgCrl;
public IntPtr rgpMsgCrl;
public UInt32 cAuthAttr;
public IntPtr rgAuthAttr;
public UInt32 cUnauthAttr;
public IntPtr rgUnauthAttr;
public UInt32 dwFlags;
public UInt32 dwInnerContentType;
public CRYPT_ALGORITHM_IDENTIFIER HashEncryptionAlgorithm;
public IntPtr pvHashEncryptionAuxInfo;
}
// CERT_PUBLIC_KEY_INFO
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
private struct CERT_PUBLIC_KEY_INFO
{
public CRYPT_ALGORITHM_IDENTIFIER Algorithm;
public CRYPTOAPI_BLOB PublicKey;
}
// PCERT_EXTENSION
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
private struct PCERT_EXTENSION
{
public IntPtr pszObjId;
public bool fCritical;
public CRYPTOAPI_BLOB Value;
}
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
private struct CERT_INFO
{
public int dwVersion;
public CRYPTOAPI_BLOB SerialNumber;
public CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm;
public CRYPTOAPI_BLOB Issuer;
public FILETIME NotBefore;
public FILETIME NotAfter;
public CRYPTOAPI_BLOB Subject;
public CERT_PUBLIC_KEY_INFO SubjectPublicKeyInfo;
public CRYPTOAPI_BLOB IssuerUniqueId;
public CRYPTOAPI_BLOB SubjectUniqueId;
public int cExtension;
public PCERT_EXTENSION rgExtension;
}
[DllImport("Crypt32.dll", EntryPoint="CertOpenStore")]
private static extern IntPtr CertOpenStore
(
IntPtr lpszStoreProvider,
UInt32 dwEncodingType,
IntPtr hCryptProv,
UInt32 dwFlags,
byte[] pvPara
);
[DllImport("Crypt32.dll", EntryPoint="CertFindCertificateInStore")]
public static extern IntPtr CertFindCertificateInStore
(
IntPtr hCertStore,
UInt32 dwCertEncodingType,
UInt32 dwFindFlags,
UInt32 dwFindType,
IntPtr pvFindPara,
IntPtr pPrevCertContext
);
[DllImport("Crypt32.dll", EntryPoint="CryptSignMessage")]
private static extern bool CryptSignMessage
(
IntPtr pSignPara,
bool fDetachedSignature,
UInt32 cToBeSigned,
string[] rgpbToBeSigned, //IntPtr rgpbToBeSigned,
int[] rgcbToBeSigned, //IntPtr rgcbToBeSigned,
IntPtr pbSignedBlob,
ref UInt32 pcbSignedBlob
);
public static void Test ()
{
const string CERT_STORE_NAME= "MY";
const int CERT_STORE_PROV_SYSTEM = 10;
const int CERT_SYSTEM_STORE_CURRENT_USER = 0x1 << 16;
const int MY_TYPE = (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING);
const int CERT_FIND_SUBJECT_STR = 458759;
const string certId = "ncd ncd";
const string szOID_RSA_MD5 = "1.2.840.113549.2.5";
IntPtr hStoreHandle;
hStoreHandle = CertOpenStore ((IntPtr) CERT_STORE_PROV_SYSTEM, 0,
IntPtr.Zero, CERT_SYSTEM_STORE_CURRENT_USER,
Encoding.Unicode.GetBytes(CERT_STORE_NAME));
IntPtr pCtx = IntPtr.Zero;
IntPtr pCertContext;
CERT_CONTEXT pSignerCert;
CERT_INFO pCertInfo;
CRYPTOAPI_BLOB subject;
IntPtr SIGNER_NAME = Marshal.StringToBSTR (certId);
if (hStoreHandle != IntPtr.Zero)
{
pCertContext = CertFindCertificateInStore(hStoreHandle, MY_TYPE, 0,
CERT_FIND_SUBJECT_STR, SIGNER_NAME, pCtx);
pSignerCert = (CERT_CONTEXT)
Marshal.PtrToStructure(pCertContext,Type.GetType(" TestCryptoAPI.Class1+CERT_CONTEXT"));
CRYPT_SIGN_MESSAGE_PARA sigParams = new CRYPT_SIGN_MESSAGE_PARA();
sigParams.cbSize = (UInt32) Marshal.SizeOf
(Type.GetType("TestCryptoAPI.Class1+CRYPT_SIGN_MES SAGE_PARA"));
sigParams.dwMsgEncodingType = MY_TYPE;
sigParams.pSigningCert = pSignerCert;
Marshal.StringToBSTR (szOID_PKCS_7);
sigParams.HashAlgorithm.pszObjId = Marshal.StringToBSTR
(szOID_RSA_MD5);
sigParams.HashAlgorithm.Parameters.cbData = 0;
sigParams.HashAlgorithm.Parameters.pbData = IntPtr.Zero;
sigParams.pvHashAuxInfo = IntPtr.Zero;
sigParams.cMsgCert = 1;
sigParams.rgpMsgCert =
Marshal.AllocHGlobal(Marshal.SizeOf(Type.GetType(" TestCryptoAPI.Class1+CERT_CONTEXT")));
Marshal.StructureToPtr (pSignerCert, sigParams.rgpMsgCert, false);
sigParams.cMsgCrl = 0;
sigParams.rgpMsgCrl = IntPtr.Zero;
sigParams.cAuthAttr = 0;
sigParams.rgAuthAttr = IntPtr.Zero;
sigParams.cUnauthAttr = 0;
sigParams.rgAuthAttr = IntPtr.Zero;
sigParams.dwFlags = 0;
sigParams.rgAuthAttr = IntPtr.Zero;
sigParams.dwInnerContentType = 0;
sigParams.pvHashEncryptionAuxInfo = IntPtr.Zero;
IntPtr pSigParams;
pSigParams = Marshal.AllocCoTaskMem(Marshal.SizeOf(Type.GetType ("TestCryptoAPI.Class1+CRYPT_SIGN_MESSAGE_PARA"))) ;
Marshal.StructureToPtr (sigParams, pSigParams, false);
byte[] bytePlainMessage = Encoding.Default.GetBytes("Test string to
sign");
char[] plainMessage = Encoding.Default.GetChars (bytePlainMessage);
IntPtr pPPlainMessage =
Marshal.AllocCoTaskMem(Marshal.SizeOf(Type.GetType
("System.IntPtr")));
int messageSize = plainMessage.Length;
IntPtr pPlainMessage = Marshal.AllocCoTaskMem (messageSize + 1);
Marshal.Copy (plainMessage, 0, pPlainMessage, messageSize);
Marshal.WriteIntPtr (pPPlainMessage, pPlainMessage);
char[] test = new char[messageSize];
Marshal.Copy (pPlainMessage, test, 0, messageSize);
IntPtr pMessageSize = Marshal.AllocCoTaskMem(4);
Marshal.WriteInt32 (pMessageSize, messageSize);
UInt32 signedMsgLen = 0;
try
{
if (CryptSignMessage (pSigParams, false, 1, pPPlainMessage,
pMessageSize, IntPtr.Zero, ref signedMsgLen))
}
catch (Exception ex)
{
Console.WriteLine (ex.Message);
}
}
else
{
return;
}
}
It fails at the CryptSignMessage with this error: Object reference not
set to an instance of an object.
Thanks in advance, Gionni