How to call CryptEncodeObject in .NET (C#)


Hi all,

The other day a colleague of mine was having some issues to call CryptEncodeObject from C#. In order to assist, I created this sample for him:

using System;

using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

public const int X509_ASN_ENCODING = 0x00000001;
public const int PKCS_7_ASN_ENCODING = 0x00010000;
public const int X509_ENHANCED_KEY_USAGE = 36;

[StructLayout(LayoutKind.Sequential)]
private struct CERT_ENHKEY_USAGE
{
public int cUsageIdentifier;
public IntPtr rgpszUsageIdentifier;
}

[DllImport("crypt32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
private static extern bool CryptEncodeObject(
int dwCertEncodingType,
int lpszStructType,
ref CERT_ENHKEY_USAGE pvStructInfo,
byte[] pbEncoded,
ref int pcbEncoded
);

private void button1_Click(object sender, EventArgs e)
{
// Variables
CERT_ENHKEY_USAGE usage = new CERT_ENHKEY_USAGE();
IntPtr OID = IntPtr.Zero;
int blobSize = 0;
byte[] blob = null;

try
{
// Prepare data to encode (CERT_ENHKEY_USAGE struct)
OID = Marshal.StringToHGlobalAnsi("1.3.6.1.4.1.311.101.11");
usage.rgpszUsageIdentifier = Marshal.AllocHGlobal(Marshal.SizeOf(OID));
Marshal.WriteIntPtr(usage.rgpszUsageIdentifier, OID);
usage.cUsageIdentifier = 1;

// Get size of encoded data
if (!CryptEncodeObject(
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
X509_ENHANCED_KEY_USAGE,
ref usage,
null,
ref blobSize
))
{
int error = Marshal.GetLastWin32Error();
throw new Win32Exception(error);
}

// Get encoded data
blob = new byte[blobSize];
if (!CryptEncodeObject(
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
X509_ENHANCED_KEY_USAGE,
ref usage,
blob,
ref blobSize
))
{
int error = Marshal.GetLastWin32Error();
throw new Win32Exception(error);
}

// Everything went well
MessageBox.Show("We got " + blob.Length.ToString() + " encoded bytes");
}
catch (Exception ex)
{
// Errors?
MessageBox.Show(ex.Message);
}
finally
{
// Clean up
if (!OID.Equals(IntPtr.Zero)) { Marshal.FreeHGlobal(OID); }
if (!usage.rgpszUsageIdentifier.Equals(IntPtr.Zero)) { Marshal.FreeHGlobal(usage.rgpszUsageIdentifier); }
}
}
}
}

I hope this helps.

Note I didn't have the opportunity to test it much, so if you have any issues with it, please let me know. Thx!

Regards,

 

Alex (Alejandro Campos Magencio)

Comments (4)

  1. MarioFraga says:

    hi,

    I testing you code e got it one problem,

    the date of sigin = 1899-12-30

    this is a default date of system, what modify to current date?

    tanks Mário

  2. Sorry, but what date are you talking about? Are you talking about the CryptEncodeObject sample? I'm not using dates in there…

    Thx,

    Alex

  3. Shashank Kadge says:

    Great article. Do you have any code snippet on X509_ALTERNATE_NAME extension using the CryptEncodeObject or CryptEncodeObjectEx API? thank you. shashank

  4. Hi Shashank,

    I'm afraid what I got is what I posted. If you need assistance with this, please don't hesitate to open a support case with us so we can help you.

    Thank you.

    Alex

Skip to main content