473,396 Members | 2,016 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

CryptoAPI from C# (long code part)

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
Nov 15 '05 #1
3 9876
Gionni,
private struct CRYPT_SIGN_MESSAGE_PARA
{
public UInt32 cbSize;
public UInt32 dwMsgEncodingType;
public CERT_CONTEXT pSigningCert;
pSigningCert should be a pointer to a CERT_CONTEXT, i.e. IntPtr.

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
private struct PCERT_EXTENSION
The struct is actually just called CERT_EXTENSION. PCERT_EXTENSION
indicates a pointer to a CERT_EXTENSION...
public PCERT_EXTENSION rgExtension;
.... so this should also be an IntPtr.

[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
);
You can save yourself some work by changing the pSignPara parameter
type to ref CRYPT_SIGN_MESSAGE_PARA and directly pass in your
sigParams variable.

pSignerCert = (CERT_CONTEXT)
Marshal.PtrToStructure(pCertContext,Type.GetType( "TestCryptoAPI.Class1+CERT_CONTEXT"));
I suggest you use the typeof operator rather than Type.GetType where
possible

pSignerCert = (CERT_CONTEXT)
Marshal.PtrToStructure(pCertContext, typeof(CERT_CONTEXT));

IntPtr pSigParams;
pSigParams = Marshal.AllocCoTaskMem(Marshal.SizeOf(Type.GetType ("TestCryptoAPI.Class1+CRYPT_SIGN_MESSAGE_PARA"))) ;
You never seem to free the memory you allocate here and elsewhere in
the code.

byte[] bytePlainMessage = Encoding.Default.GetBytes("Test string to
sign");
char[] plainMessage = Encoding.Default.GetChars (bytePlainMessage);
These two steps are more easily done with

char[] plainMessage = "Test string to sign".ToCharArray();

Plus you don't have any data loss due to the encoding.

if (CryptSignMessage (pSigParams, false, 1, pPPlainMessage,
pMessageSize, IntPtr.Zero, ref signedMsgLen))


Your declaration of CryptSignMessage had the fourth parameter declared
as string[] but here you're passing it pPPlainMessage which is an
IntPtr. That shouldn't even compile.

Mattias

--
Mattias Sjögren [MVP] mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.
Nov 15 '05 #2
Mattias Sjögren <ma********************@mvps.org> wrote in message news:<Of**************@TK2MSFTNGP11.phx.gbl>...

Mattias, thanks for your suggestions.
I changed some definitions, but I still have some problems. I don't
how to translate some types, as you will see after.
You can save yourself some work by changing the pSignPara parameter
type to ref CRYPT_SIGN_MESSAGE_PARA and directly pass in your
sigParams variable.
I hope I have understood well . The definition now is this:

[DllImport("Crypt32.dll", EntryPoint="CryptSignMessage")]
private static extern bool CryptSignMessage
(
ref CRYPT_SIGN_MESSAGE_PARA pSignPara,
bool fDetachedSignature,
UInt32 cToBeSigned,
IntPtr rgpbToBeSigned,
IntPtr rgcbToBeSigned,
out IntPtr pbSignedBlob,
ref UInt32 pcbSignedBlob
);

Question: is there any general criterion to map the C types to the C#
ones?
Your declaration of CryptSignMessage had the fourth parameter declared
as string[] but here you're passing it pPPlainMessage which is an
IntPtr. That shouldn't even compile.
Yes, you are right. Copy and paste error.
Now with your suggestion the code is this (I snipped the definitions):

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 pCertContext;
int certContextSize = Marshal.SizeOf (typeof(CERT_CONTEXT));
int cryptSignMessageParaSize = Marshal.SizeOf (typeof
CRYPT_SIGN_MESSAGE_PARA));
CERT_CONTEXT signerCert;
CERT_INFO pCertInfo;
CRYPTOAPI_BLOB subject;
CRYPT_SIGN_MESSAGE_PARA sigParams;

IntPtr SIGNER_NAME = Marshal.StringToBSTR (certId);
if (hStoreHandle != IntPtr.Zero)
{
pCertContext = CertFindCertificateInStore(hStoreHandle, MY_TYPE, 0,
CERT_FIND_SUBJECT_STR, SIGNER_NAME, IntPtr.Zero);
signerCert = (CERT_CONTEXT) Marshal.PtrToStructure(pCertContext,
typeof(CERT_CONTEXT));

sigParams = new CRYPT_SIGN_MESSAGE_PARA();
sigParams.cbSize = (UInt32) cryptSignMessageParaSize;
sigParams.dwMsgEncodingType = MY_TYPE;
IntPtr pSignerCert = Marshal.AllocCoTaskMem (certContextSize);
Marshal.StructureToPtr (signerCert, pSignerCert, true);
IntPtr pPSignerCert =
Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(IntPt r)));
Marshal.WriteIntPtr (pPSignerCert, pSignerCert);
sigParams.pSigningCert = pPSignerCert;
sigParams.HashAlgorithm.pszObjId = Marshal.StringToBSTR
(szOID_RSA_MD5);
sigParams.HashAlgorithm.Parameters.cbData = 0;
sigParams.cMsgCert = 1;
sigParams.rgpMsgCert = Marshal.AllocCoTaskMem (certContextSize);
Marshal.StructureToPtr (signerCert, sigParams.rgpMsgCert, true);
sigParams.cAuthAttr = 0;
sigParams.dwInnerContentType = 0;
sigParams.cMsgCrl = 0;
sigParams.cUnauthAttr = 0;
sigParams.dwFlags = 0;
sigParams.pvHashAuxInfo = IntPtr.Zero;
sigParams.rgAuthAttr = IntPtr.Zero;

string testString = "Test string to sign";
char[] plainMessage = testString.ToCharArray ();
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);
IntPtr pMessageSize = Marshal.AllocCoTaskMem(4);
Marshal.WriteInt32 (pMessageSize, messageSize);

IntPtr pSignedMsg = new IntPtr ();
UInt32 signedMsgLen = 0;
try
{
if (CryptSignMessage (ref sigParams, false, 1, pPPlainMessage,
pMessageSize, out pSignedMsg, ref signedMsgLen))
{
Marshal.FreeCoTaskMem (pPPlainMessage);
Marshal.FreeCoTaskMem (pPlainMessage);
Marshal.FreeCoTaskMem (pMessageSize);
Console.WriteLine ("Message signed");
}
else
Console.WriteLine ("Error in signing");
}
catch (Exception ex)
{
Console.WriteLine (ex.Message);
}
}
else
{
return;
}
}

It fails again with the same error: Object reference not set to an
instance of an object.
Mattias


Thanks again, Gionni
Nov 15 '05 #3
I hope I have understood well . The definition now is this:

[DllImport("Crypt32.dll", EntryPoint="CryptSignMessage")]
private static extern bool CryptSignMessage
(
ref CRYPT_SIGN_MESSAGE_PARA pSignPara,
bool fDetachedSignature,
UInt32 cToBeSigned,
IntPtr rgpbToBeSigned,
IntPtr rgcbToBeSigned,
out IntPtr pbSignedBlob,
ref UInt32 pcbSignedBlob
);

Yes, that's pretty much what I had in mind. But I see you changed some
other parameter types as well. pbSignedBlob should be an IntPtr passed
by value like you had it before. You could also use a byte array to
put the output data into. rgpbToBeSigned and rgcbToBeSigned were also
better before when declared as arrays. I think the best declaration
would be

private static extern bool CryptSignMessage
(
ref CRYPT_SIGN_MESSAGE_PARA pSignPara,
bool fDetachedSignature,
UInt32 cToBeSigned,
string[] rgpbToBeSigned,
int[] rgcbToBeSigned,
byte[] IntPtr pbSignedBlob,
ref UInt32 pcbSignedBlob
);

And then you should be able to call it like this

string[] testStrings = {"Test string to sign"};
int[] sizes = {testStrings[0].Length};
int outBufferSize = /* some value */;
byte[] outputBuffer = new byte[outBufferSize];
if (CryptSignMessage (ref sigParams, false, 1, testStrings, sizes,
outputBuffer, ref outBufferSize))

and save yourself all the manual marshaling work.

Question: is there any general criterion to map the C types to the C#
ones?


For simple types yes, but for more complicated situations it takes
some experience to get it right. It's hard to summarize here.

Mattias

--
Mattias Sjögren [MVP] mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.
Nov 15 '05 #4

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: Andy Atherton | last post by:
When using SQL 2000 personal desktop (i.e MSDE) on win 98 Machine with our VB6 application we sometimes get this error CryptoAPI function 'CryptAcquireContext' failed. Error 0x8009001d:...
0
by: Kim HM | last post by:
I Have a .NET program sending mails using CDOEX. These mail I need to sign. I god a tip that i shoud use CAPICOM. That worked fine sending a mail with signature. BUT the problem is that I have...
4
by: Dave Bailey | last post by:
I have an application installed on a web server. When forst intalled it worked fine. The administrator rebooted the server and then when accessing the app the folowing error appears: CryptoAPI...
1
by: Greg Merideth | last post by:
I've finally got my client/server secure soap process working and I've just noticed that under the servers \NetworkService\AppData\MS\Crypto\RSA folder there are some 100+ paired sets of RSA keys....
0
by: no game | last post by:
I have a problem with signature using RSACryptoServiceProvider I use signature=privKey.SignData(byteData, new MD5CryptoServiceProvide), and get a byte array of signature. The other...
0
by: Bonj | last post by:
Hi i have a question regarding the CryptoAPI. I can seemingly call CryptAcquireContext, and if I pass any random string as the key container name and NULL as the provider name, with...
0
by: Mike P | last post by:
This is a very weird problem, when I boot my IIS server I get a CryptoAPI cryptographic service provider (CSP) for this implementation could not be acquired exception. However, once I access my...
0
by: =?Utf-8?B?VmVuZWRpY3Q=?= | last post by:
Hi All, I have a program written in VB6 which utilize CryptoAPI to encrypt bitmap file. I'm writting a new program in C# 2005 to decrypt those encrypted bitmap file by adding the CryptoAPI...
1
by: MichaelAni | last post by:
Hi, I have a requirement to develop an component in VC++ and .net for encryption/decryption. I am deriving a key from a password. But when i encrypt the data VC++(cryptoapi) component and .net...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.