Knowledge is power. We love to share it.

News related to Mono products, services and latest developments in our community.

idrazic

Finding the public key token of a .Net assembly

05/03/2012

I was in a situation where I needed to find out the public key token of a file I had.   A simple enough task you might say, but is it? Since I wasn't aware of a way to get the public key token through the Visual Studio IDE, I searched the internet for help. 

Using the Strong Name Utility

   

The easiest solution is to use the Strong Name Utility from .Net SDK. Since I didn't have the SDK installed that meant downloading and installing the whole package.

You can download and install the .Net Framework SDK (which is contained in the Windows SDK) from:
Download Microsoft Windows SDK

Strong Name Utility

"c:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\sn.exe" -T myfile.dll

Microsoft (R) .NET Framework Strong Name Utility  Version 3.5.30729.1

Copyright (c) Microsoft Corporation.  All rights reserved.

Public key token is xxxxxxxxxxxxxxxx

Additionally, you can setup an external tool menu entry in Visual Studio IDE to automate this task. (Tools > External Tools > ) 

Using the code

Another solution might be to get the public key token from code. We can use the System.Reflection for that.

For the executing assembly:

Assembly.GetExecutingAssembly().GetName().GetPublicKeyToken();

Note: if you didn't sign your executable the public key token will be null
Go to { Project Properties > Signing } - to sign your executable.
signing

For all assemblies in the application domain:

Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
assemblies[i].GetName().GetPublicKeyToken()

For an external assembly file:

Assembly.LoadFrom("<executable path>").GetName().GetPublicKeyToken()

So what is the public key token exactly?

According to the CLI documentation (ECMA-335.pdf) the public key token is the last 8 bytes of the sha1 hash of the public key. "The low 8 bytes of the SHA-1 hash of the originator's public key."

(new SHA1CryptoServiceProvider()).ComputeHash(Assembly.GetExecutingAssembly().
GetName().GetPublicKey()).Reverse().Take(8).ToArray()
This should yield the same result as a call to GetPublicKeyToken().

Example source file:

using System;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
 
namespace PublicKeyTokenTest
{
    class Program
    {
        static void Main(string[] args)
        {
            // Get the executing assembly public key token
            var myAsm = Assembly.GetExecutingAssembly().GetName();
            Console.WriteLine(myAsm.Name);
            Console.WriteLine(myAsm.GetPublicKeyToken().ToStringBase16());
 
            // Domain assemblies tokens
            foreach (var asm in AppDomain.CurrentDomain.GetAssemblies().
OrderBy(a => a.GetName().Name))
            {
                Console.WriteLine(asm.GetName().Name);
                Console.WriteLine(asm.GetName().GetPublicKeyToken().ToStringBase16());
            }
 
            // Load from file (I used sqlite dll as an example)
            AssemblyName externalAssembly = 
                Assembly.LoadFrom("System.Data.SQLite.dll").GetName();
            Console.WriteLine(externalAssembly.Name);
            Console.WriteLine(externalAssembly.GetPublicKeyToken().ToStringBase16());
 
            Console.WriteLine();
            
            // So how is the public key token calculated?
            var pk = externalAssembly.GetPublicKey();
            // Is this file signed?
            if (pk != null && pk.Length > 0)
            {
                Console.WriteLine(pk.ToStringBase16());
                // From the ECMA-335 documentation:
                // "The low 8 bytes of the SHA1 hash of the originator's public key."
                Console.WriteLine((new SHA1CryptoServiceProvider()).ComputeHash(pk).
                                   Reverse().Take(8).ToArray().ToStringBase16());
            }
 
            Console.ReadKey();
        }
    }
 
    public static class Extensions
    {
        // A small helper extension for Byte-Array-To-Hex
        public static string ToStringBase16(this byte[] buffer)
        {
            return buffer.Aggregate(string.Empty, 
                   (result, item) => (result += item.ToString("X2")));
        }
    }
}
Rated 3.22, 9 vote(s).