Skip to content

Instantly share code, notes, and snippets.

@davecluderay
Created July 4, 2014 13:34
Show Gist options
  • Save davecluderay/9cfc6e98f47a9af70f15 to your computer and use it in GitHub Desktop.
Save davecluderay/9cfc6e98f47a9af70f15 to your computer and use it in GitHub Desktop.
Generate a public key token from an X.509 certificate (for use in ClickOnce manifests).
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
public static class PublicKeyToken
{
public static string FromCertificate(X509Certificate cert)
{
var publicKeyBlob = GetCspPublicKeyBlob(cert);
var publicKeyBlobPtr = Marshal.AllocHGlobal(publicKeyBlob.Length);
Marshal.Copy(publicKeyBlob, 0, publicKeyBlobPtr, publicKeyBlob.Length);
var cryptDataBlob = new Win32.CryptDataBlob { cbData = (uint)publicKeyBlob.Length, pbData = publicKeyBlobPtr };
var publicKeyTokenPtr = new IntPtr();
if (0 != Win32._AxlPublicKeyBlobToPublicKeyToken(ref cryptDataBlob, ref publicKeyTokenPtr))
throw new Win32Exception(Marshal.GetLastWin32Error());
Marshal.FreeHGlobal(publicKeyBlobPtr);
var publicKeyToken = Marshal.PtrToStringUni(publicKeyTokenPtr);
Win32.HeapFree(Win32.GetProcessHeap(), 0, publicKeyTokenPtr);
return publicKeyToken;
}
private static byte[] GetCspPublicKeyBlob(X509Certificate cert)
{
var asnEncodedPublicKey = cert.GetPublicKey();
uint requiredBytes = 0;
if (!Win32.CryptDecodeObject(Win32.Pkcs7AsnEncoding | Win32.X509AsnEncoding, Win32.RsaCspPublicKeyBlob, asnEncodedPublicKey, (uint)asnEncodedPublicKey.Length, 0, null, ref requiredBytes))
throw new Win32Exception(Marshal.GetLastWin32Error());
var publicKeyBlob = new byte[requiredBytes];
if (!Win32.CryptDecodeObject(Win32.Pkcs7AsnEncoding | Win32.X509AsnEncoding, Win32.RsaCspPublicKeyBlob, asnEncodedPublicKey, (uint)asnEncodedPublicKey.Length, 0, publicKeyBlob, ref requiredBytes))
throw new Win32Exception(Marshal.GetLastWin32Error());
return publicKeyBlob;
}
}
using System;
using System.Runtime.InteropServices;
public static class Win32
{
public const uint X509AsnEncoding = 0x00000001;
public const uint Pkcs7AsnEncoding = 0x00010000;
public const uint RsaCspPublicKeyBlob = 19;
[DllImport("clr.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int _AxlPublicKeyBlobToPublicKeyToken([In] ref CryptDataBlob pCspPublicKeyBlob, [In, Out] ref IntPtr ppwszPublicKeyToken);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public extern static IntPtr GetProcessHeap();
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public extern static bool HeapFree([In] IntPtr hHeap, [In] uint dwFlags, [In] IntPtr lpMem);
[DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptDecodeObject(uint certEncodingType, uint lpszStructType, byte[] pbEncoded, uint cbEncoded, uint flags, [In, Out] byte[] pvStructInfo, ref uint cbStructInfo);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct CryptDataBlob
{
internal uint cbData;
internal IntPtr pbData;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment