Created
July 4, 2014 13:34
-
-
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).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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