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)