Strong Naming

How to Find the Public Key Token for a Strongly-Named Assembly

Posted on Updated on

In another post, we discussed why you should strongly name assemblies and how to do it via the Strong Name Tool (sn.exe). In this quick post we will consider another scenario – how to get the public key token string value of a strongly named assembly (dll).

This is easily accomplished by using the Strong Name Tool as well by simply using the -T switch and specifying the path and name of the dll for which to retrieve the public key token. It can also be done in code using the System.Reflection.Assembly class. We will take a quick look at each approach.

Using the Strong Name Tool

To use the Strong Name Tool (sn.exe), simply open the Microsoft Visual Studio Developer Command Prompt and use the following syntax:

sn.exe -T <assembly path and name>

For this example, we will retrieve the public key token for an assembly named SampleClassLibrary.dll that is located in the c:\Temp folder.

Get Public Key Token of Strongly Named Assembly using Strong Name Tool

For this example, the public key token is ba27e13c07659075.

Using the System.Reflection.Assembly Class – Getting the Public Key Token in Code

The manner in which we get the public key token for an assembly depends upon our point of reference. For example, we can do it for the currently executing assembly, do it for a specific assembly based on a file path, or do it for one or all assemblies that have been loaded within the current AppDomain.

Let’s consider two of these scenarios:

Getting the Public Key Token for the Currently Executing Assembly

To demonstrate this approach, I have created a simple method in a sample class:

public void GetPublicKeyTokenForThisAssembly()
{
    byte[] token = Assembly.GetExecutingAssembly().GetName().GetPublicKeyToken();
}

Now, if we execute this code, and place a breakpoint on the line that gets the byte array, we can use Visual Studio debugging to view the results of our token retrieval.

PublicKeyTokenDebuggerView

Since the return type is a byte array, the results are exactly as we would expect. So how do we convert that to the same string that we saw when we did it through the Strong Name Tool?

We write a little bit of C# code to do this as shown below:

byte[] token = Assembly.GetExecutingAssembly().GetName().GetPublicKeyToken();

StringBuilder sb = new StringBuilder();

for (int i = 0; i < token.GetLength(0); i++)
{
     sb.Append(String.Format("{0:x2}", token[i]));
}

string publicKeyToken = sb.ToString();

The result of this is the public key token that we retrieved using the Strong Name Tool above.

If you are wondering what the “{0:x2}” formatter does, this is something known as Composite Formatting. The hexadecimal format specifier (X) converts a number to a string of hexadecimal digits. The “2” instructs the runtime to produce a string with a length of 2.

Getting the Public Key Token for Assemblies in the Current AppDomain

Though the point of this post is not to discuss Reflection or how to use the methods of the Assembly class, it is beneficial to take a look at how this same logic could be applied to all assemblies loaded within the current AppDomain.

To do this, we merely have to change our code to get the assemblies and iterate through them to retrieve the public key tokens.

byte[] token;

StringBuilder publicKeyTokens = new StringBuilder();
Assembly[] loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();

foreach (Assembly assembly in loadedAssemblies)
{
    token = assembly.GetName().GetPublicKeyToken();
    StringBuilder sb = new StringBuilder();

    for (int i = 0; i < token.GetLength(0); i++)
    {
        sb.Append(String.Format("{0:x2}", token[i]));
    }

    publicKeyTokens.AppendLine("The public key token for assembly " + assembly.FullName + " is:  " + sb.ToString());
}

string allPublicKeyTokens = publicKeyTokens.ToString();

The output of our StringBuilder is as follows:

The public key token for assembly mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 is:  b77a5c561934e089
The public key token for assembly Microsoft.VisualStudio.HostingProcess.Utilities, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a is:  b03f5f7f11d50a3a
The public key token for assembly System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 is:  b77a5c561934e089
The public key token for assembly System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a is:  b03f5f7f11d50a3a
The public key token for assembly System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 is:  b77a5c561934e089
The public key token for assembly Microsoft.VisualStudio.HostingProcess.Utilities.Sync, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a is:  b03f5f7f11d50a3a
The public key token for assembly Microsoft.VisualStudio.Debugger.Runtime, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a is:  b03f5f7f11d50a3a
The public key token for assembly vshost32, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a is:  b03f5f7f11d50a3a
The public key token for assembly System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 is:  b77a5c561934e089
The public key token for assembly System.Xml.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 is:  b77a5c561934e089
The public key token for assembly System.Data.DataSetExtensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 is:  b77a5c561934e089
The public key token for assembly Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a is:  b03f5f7f11d50a3a
The public key token for assembly System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 is:  b77a5c561934e089
The public key token for assembly System.Deployment, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a is:  b03f5f7f11d50a3a
The public key token for assembly System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 is:  b77a5c561934e089
The public key token for assembly WindowsFormsApplication2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null is:
The public key token for assembly SampleClassLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ba27e13c08759075 is:  ba27e13c08759075

If you notice the assembly for my sample WinForms assembly shows a PublicKeyToken that is null. Why is this? Because I did not strongly name that assembly! Also, notice that in our code we extracted the FullName value for each assembly. This is an important point when talking about strong naming because the FullName shows us the name, version, public key token, and culture information.

In this simple little sample, I utilized a solution with two projects: a WinForms project and a class library that is referenced by the WinForms project. In this sample, the class library is strongly named and the WinForms project is not. This is okay, but the opposite scenario is not. Suppose that we strongly name the WinForms assembly but remove the strong name from the class library. The compiler will bark at us then we try to build the solution because as we said before, a strongly named assembly requires all referenced assemblies to be strongly named as well. The output below is generated when we try to build under the second scenario:

strongnamedcompilererror

 

 

Strong-Named Assemblies – Why and How

Posted on Updated on

Overview

In this short post, I will discuss strong-named assemblies in .NET and cover why and how you should use strong naming within your .NET projects.

First, there seems to be a misconception among many developers with whom I’ve worked that strong naming is a security measure. That is not the intent of strong naming! Instead, strong naming provides a means of uniquely identifying assemblies and providing evidence that the assembly to be loaded is indeed the one intended. A strong name consists of the following things:

  • The assembly’s simple text name
  • The assembly’s full version number
  • The assembly’s culture information
  • A Public Key
  • A Digital Signature

Why Use Strong-Named Assemblies?

Based on your scenario, there are some distinct reasons why assemblies should be strongly named.

  • If you plan to deploy your assembly to the Global Assembly Cache (GAC), the assembly MUST be strongly named. This is necessary because the GAC allows multiple versions of the same assembly to coexist simultaneously. Anyone who has been around long enough to remember Windows development in the past, especially prior to .NET remember the term “DLL Hell”. I know this term all too well and learned very quickly a long time ago what a pain it can be. Those are bad memories, so I will move on! I will discuss the Global Assembly Cache in another article.
  • Strong names protect the version lineage of an assembly. If an assembly is strongly named, the assemblies it references must also be strongly named.

Strong naming relies upon asymmetric cryptography. Although the purpose of this article is strong naming, a very quick discussion of asymmetric cryptography is warranted. I will only take a shallow dive into asymmetric cryptography because this purpose of this article is to briefly discuss strong-named assemblies and not encryption.

Asymmetric Cryptography (Public Key Cryptography)

Public Key Cryptography (PKC) is a form of cryptography that requires two “keys” – a public key and a private key. The public key is known to all and the private key is only known to the individual. In a very simple example of PKC, if I decide to send an encrypted message to one of my friends, I use my friend’s public key to encrypt the message, then he uses his private key to decrypt it. If he then decides to send me an encrypted message, he uses my public key to encrypt it then I use my private key to decrypt. Makes sense, right? It is important to note that with PKC, only the public key can be used to encrypt, and only the corresponding private key can be used to decrypt.

How to Create a Strong Name Key Pair

Before strongly naming an assembly, you must first have a public/private key pair file. The key pair is used by the compiler to create the strong-named assembly.

Creating a strong name key pair is made very simple by Microsoft through use of the Strong Name Tool (sn.exe). To create a key pair using this tool, simply follow these steps:

  1. From the Start menu, select your version of Visual Studio in the All Programs menu, click Visual Studio Tools, then select the Visual Studio Developer Command Prompt menu. See the following image.
  2. When the Visual Studio Command Prompt window opens, invoke the Strong Name Tool using the following syntax: sn -k KeyFileName.snk. The Strong Name Tool has numerous switches that can be used with its invocation. The -k switch instructs the tool to create the public/private key pair with the name that you specify. You can specify the path to which the .snk file should be created. In the example below, I create a key pair named MyKeyPair and I write it to the c:\Temp folder.sn_result
  3. When the key pair has been created, the next step is to use it to strongly-name an assembly. This is easily accomplished within Visual Studio by right-clicking the project to be signed and selecting the Properties menu. The example below shows the Properties window for a sample class library that I have created.SigningTabBrowse
  4. Browse to the .snk file and click Ok. The .snk is then associated with the project and when built, the resulting assembly will be strongly-named.

That’s it! Pretty simple. In the next article we take a look at how to extract the PublicKeyToken from a strongly-named assembly.