This multi-part article answers common questions about assemblies, the basic building blocks of .NET applications. This Part 3 discusses assembly security using strong names, signing and public-private key pairs.
What is a strong name?
A strong name is a .NET assembly name combined with its version number and other information to uniquely identify the assembly. This allows multiple versions of the same assembly to peacefully co-exist in the global assembly cache, where shared assemblies are typically stored.
A strong name consists of five parts:
- Simple Name – Usually the name of the file (without the extension) that contains the assembly
- Public Key – RSA cryptographic public key that helps verify the assembly’s authenticity
- Version – Four-part version number, in the form of Major.Minor.Build.Revision
- Culture – Target audience for the assembly, such as “neutral” (default audience), “en-us” (English – United States) or “fr” (France) etc.
- Processor Architecture – Defines the assembly’s format, such as MSIL (intermediate language) or x86 (binary for Intel x86 processors)
An example strong name is “Mini-Launcher, Version=0.3.612.24542, Culture=neutral, PublicKeyToken=ffa52ed9739048b4, ProcessorArchitecture=MSIL”.
Why use strong names?
Strong names are required to store shared assemblies in the global assembly cache (GAC). This is because the GAC allows multiple versions of the same assembly to reside on your system simultaneously, so that each application can find and use its own version of your assembly. This helps avoid DLL Hell, where applications that may be compiled to different versions of your assembly could potentially break because they are all forced to use the same version of your assembly.
Another reason to use strong names is to make it difficult for hackers to spoof your assembly, in other words, replace or inject your assembly with a virus or malicious code.
What is a strong name key file?
A strong name key file has a .snk extension and contains a unique public-private key pair. You use the strong name key file to digitally sign your assembly (see below). Note that this type of file is not secure, as the private key in a .snk file can be easily compromised.
For added protection, Visual Studio can encrypt a strong name key file, which produces a file with the .pfx (Personal Information eXchange) extension. The .pfx file is more secure because whenever someone attempts to use the encrypted key, she will be prompted for the password.
How do I create a strong name key file for a .NET assembly?
Visual Studio 2005 makes it easy to create a strong name key file:
- Select your assembly project in the Visual Studio Solution Explorer.
- Click the Properties button. The project properties will appear in the main window.
- Select the Signing tab:
- Check the Sign the assembly checkbox.
- In the Choose a strong name key file drop-down, select New. The “Create Strong Name Key” dialog appears:
- In the Key file name text box, type the desired key name. Typically this is the name of your assembly but can be anything. Visual Studio will automatically append the proper file extension.
- If desired, you can protect the strong name key file with a password. To do so, check the Protect my key file with a password checkbox, then enter and confirm the password.
- Click the OK button.
Now when you compile your project, Visual Studio will automatically sign your assembly with the new strong name key you have just created.
Or if you prefer to use the command-line, you can create a key pair file with the strong name utility sn.exe in the .NET SDK, for example:
sn -k MyKey.snk
Then you reference that key file to when compiling your code with the C# compiler csc.exe:
csc /keyfile:MyKey.snk MyCodeFile.cs
What does it mean to sign an assembly?
.NET uses digital signatures to verify the integrity of an assembly. The signatures are generated and verified using public key cryptography, specifically the RSA public key algorithm and SHA-1 hash algorithm. The developer uses a pair of cryptographic keys: a public key, which everyone can see, and a private key, which the developer must keep secret.
To create a strong-named assembly, the developer signs the assembly with his private key when building the assembly. When the system later loads the assembly, it verifies the assembly with the corresponding public key.
How do I sign an assembly?
When you compile your assembly with a strong name key file, the compiler digitally signs the assembly:
- The compiler calculates the cryptographic digest (a hash) of your assembly contents. This is known as the compile-time digest. Modifying just a single byte of your assembly will change this hash value.
- The compiler encrypts the digest using the 1024-bit private key from your public-private key pair file.
- The compiler then stores the encrypted digest and public key into the assembly.
How does the system verify a signed assembly?
Sometime later, when an application attempts to load your signed assembly:
- The .NET assembly loader calculates the cryptographic digest of the current assembly contents. This is known as the run-time digest.
- The loader extracts the stored compile-time digest and public key from the assembly.
- The loader uses the public key to decrypt the compile-time digest.
- The loader then compares the run-time digest with the decrypted compile-time digest to ensure they match. If not, then the assembly has been modified since you compiled it, and the assembly load fails.
This process is different when loading shared assemblies from the GAC. Because assemblies are verified when they are first installed into the GAC–and they cannot be modified while in the GAC–the .NET assembly loader does not verify an assembly when loading it from the GAC. This can improve the startup speed of your application if you load many shared assemblies.
What is delay signing?
Delay signing is signing an assembly with its strong name public key, which is freely distributable, instead of using the private key as usual. This allows developers to use and test a strong-named assembly without access to the private key. Then at a later stage (typically just before shipping the assembly), a manager or trusted keyholder must sign the assembly with the corresponding private key. (more)
How do I protect my private keys?
Private keys must remain secret. A hacker with your private key could spoof your signed assemblies by replacing or injecting them with a virus or other malicious code. There are a few strategies you can use to protect your private keys:
- Password Protection. As shown above, Visual Studio will allow you to protect your strong name key file with a password.
- Delay Signing. As mentioned above, delay signing enables your development team to build and test your assembly without access to the private key.
- Cryptographic Container. One of the most secure ways to protect your strong name key is to store it in a secure cryptographic container (see sidebar “Protecting Your Keys” in this article).
How many private keys should I have?
There are three main strategies for how many private keys a developer should use:
- One private key for all your applications and assemblies
- One private key for each application (an application may have multiple assemblies)
- One private key for each assembly
Which option to use depends on your security situation and risk tolerance. With option 1, it’s easier to keep a single key secure, but if your one private key is compromised, then all of your assemblies are compromised. With option 3, there are more keys to manage and hence lose, but if one key is compromised, then only one of your many assemblies is compromised. I recommend option 2 or 3 to reduce your overall exposure.
Are there problems with using strong names?
Strong names are not perfect. There are some issues to consider when using strong names:
- Requires Exact Match. If you use strong names, your application or library must load the assembly with the exact strong name that you specify, including version and culture. Note that you can bypass this requirement with a publisher policy (to be discussed in a future article).
- Cannot Lose Private Key. If your private key is lost or stolen, the security of your assembly is compromised. You will be forced to re-issue a new assembly signed with a new public-private key pair.
- Cannot Stop Full Replacement. Strong names cannot prevent a hacker from removing the strong name signature, maliciously modifying your assembly, re-signing it with his own key, and then passing off his assembly as yours. The user must have some way to ensure the public key they have from your assembly is valid and truly came from you. Note that you can use more sophisticated signing schemes (such as Authenticode) to help with this issue.
.NET Assembly FAQ – Part 1
.NET Assembly FAQ – Part 2 – Attributes
.NET Assembly FAQ – Part 4 – Global Assembly Cache
Using C#, is there any way to find out programmatically if an assembly is strongly-named or not ?
Re: Using C#, is there any way to find out programmatically if an assembly is strongly-named or not?
Yes, excellent question. Here is the answer:
http://www.devtopics.com/determine-if-a-loaded-net-assembly-is-signed/
Great ! Thanks a lot for the answer !
Does anyone could have a look at the part 2 of this series? If yes, please mail it to me since the webpage containing part two does not show any content on my browser.
Thanks,
Neeraj
Hi Neeraj,
Part 2 can be found at this link:
https://www.csharp411.com/net-assembly-faq-part-2-attributes/
If you cannot see it, perhaps check out the Google cache:
http://209.85.173.104/search?q=cache:xrcILNnWxsAJ:www.csharp411.com/net-assembly-faq-part-2-attributes/+.NET+Assembly+FAQ+-+Part+2+-+Attributes&hl=en&ct=clnk&cd=1&gl=us&client=firefox-a
I have strongly named assembly. I am using reflection to access the assembly and its methods. I have changed one of the constructors of the assembly. Now if I try to create the instance of the a particular class in the assembly, it say constructor on the .. type not found.
I have searched on the net, they say the changes are not reflected in the strong key
How do you make these changes to be reflected in the strong key
Regards
-Rama G-
You have to recompile your assembly and re-sign it again with your strong key.
I have recompiled the assembly and resigned.
When I use GetConstructors(..) I can see all the latest changes made to the constructor. Error comes only when I create the instance of the class
In fact I removed the strong key, and gave a new strong key and rebuild the assembly. Even now the problem persists
Hi timm,
I am still very confused about which is the private key. Is the file created by Visual Studio with the pfx extension the private key? Or is the private key created by Visual Studio and stored in that pfx file?
Is there any way to actually see the private key?
Thank you in advance for your help! And wonderful article!
There are two types of signing (it’s unfortunate both use the same name). There’s “signing” to give the assembly a strong assembly name, as described above, and there’s “signing” to verify the application hasn’t been tampered with. The former uses .snk files. The latter uses .pvk, .cer, and .pfx files.
* A public key (.cer file) is given by a Certificate Authority (trusted third party)
* A private key (.pvk file) you generate and keep confidential
* A Personal Information Exchange (pfx file) contains a public key and a private key.
Here is an article that contrasts the two types of signing:
http://www.robrich.org/archive/2006/11/29/Code-Signing-two-worlds-defined.aspx
I have two questions about the pfx file that Visual Studio creates: 1. If the code for an assembly that I originally created and signed with a password protected pfx file, is recompiled by another developer on their machine with my pfx file does the dll contain the same strong name as the one compile on my machine? 2. If I forget the password for a pfx file is there any way to decrypt the pfx file to obtain the password?
Thanks!
Gnordstrom:
1. I don’t know for sure, but I would say yes. You’ll have to test it and let us know what you find.
2. No, once you lose your pfx password, there is no recovery. You will be forced to re-issue a new assembly signed with a new public-private key pair.
I have a question about Assembly Versions.
What I have to do in order to use in my application old assembly with new version number? Should I remove the reference and insert it again every time the version is changed? Is there another way?
You can store hash (ex. in MD5) of your public key and compare it with hashes from loading assemblies before application starts. To create MD5 hash of the public key of loading assembly you can use:
currentAssembly.GetName().GetPublicKey() and MD5 class.
Now you know if loading assembly contains your public key or not.
[…] Сборки .NET можно подписать ключем, и позволять инклудинг только по публичному ключу. Но это никакая не защита, а простой выход убедится, что версия библиотеки правильная для конкретного приложения. Это также позволяет убедится в целостности приложения. Подробней на английском можно почитать здесь. […]
how can i use x509 certificate created from CA to strong name the code ?
Thanks for this detailed article. I am not clear about the point you mentioned.
“Requires Exact Match. If you use strong names, your application or library must load the assembly with the exact strong name that you specify, including version and culture. Note that you can bypass this requirement with a publisher policy (to be discussed in a future article).”
I have added a signed dll (test.dll) with version 1.0.1.0 in my exe (test.exe). I built test.dll again with version 1.0.2.0 then I simply copy past the dll to test.exe program it still get executed can please help in this. What I believe or get understood by your above point is that it should not get executed.
Thanks
[…] solutions are signed with a strong name. (Don’t know what strong name signing is? Follow this […]
[…] solutions are signed with a strong name. (Don’t know what strong name signing is? Follow this […]
If a malicious user can just do a full replacement, what is the point of signing an assembly?
@bvd: Though it’s not clear from my article, a malicious user would have to replace both the signed assembly, as well as recompile all the assemblies that use it. For example, let’s say we sign an assembly called utility.dll to use in our program called myapp.exe. A pirate could remove and resign utility.dll, but then myapp.exe and all other applications would fail to bind to the utility.dll because of a signature mismatch. Also, once utility.dll is installed in the GAC, it cannot be modified or re-signed. Finally, you can use Authenticode or similar certification to prevent re-signing.
@ timm: Thanks for the quick and helpful response. I think I see what you’re saying – it’s not really possible to do full replacement since they’d have to recompile -everything-. However, now I’m slightly confused about how a malicious user might tamper with an unsigned DLL, because if he/she tampers with it, won’t he/she also have to recompile everything again?
Thanks so much for your help.
@bvd: That’s the crux of why assembly signing is important. If the utility.dll from my example is unsigned and then modified by a pirate, the assemblies that reference utility.dll do not need to be recompiled and hence are unaware that it has been hacked.
What makes signed assemblies required to be recompiled?
@bvd: Using our example, when myapp.exe calls a method in the utility.dll assembly that has been signed, myapp.exe references not only the method and library names, but the full library signature including the public key token, for example: “Utility, Version=2.0.3855.22908, Culture=neutral, PublicKeyToken=eba64b46725f21db”. Therefore, utility.dll must be resigned with the same private key, else the binding will fail, and myapp.exe will throw an exception.
Really Very Informative,
But I have Confused with this that If I know the password then what I have to do for use that dll in another Project
Thank You.
Amit Tank
[…] to Find SN.exe Posted by timm No Comments » SN.exe is a Strong Name tool that can sign assemblies, manage strong name keys, and generate and verify signatures. You will typically find it […]
Remarkable guidance. Upload files to file hosting internet sites to share them with virtually anyone completely free.
Wonderful guidance. Upload files to file hosting sites to share them with someone without cost.
Thank you the articles. They are very helpful.
I believe that the sentence “Because assemblies are verified when they are first installed into the GAC–and they cannot be modified while in the GAC” is true. But my experience tells it is not. So, I’m searching what I have missed. There are steps to reproduce (VS 2005 with some SPs, Win XP SP3):
1. Create the first solution with MyApp, MyDLL. The DLL will contain a method returning a string “correct DLL”. MyApp’s main will call the method and will display the result.
2. Sign both project by project’s properties on “Signing” tab with key file MyKey.pfx. The pfx file is listed in the solution tree.
3. Create the second solution on different location MyDLL (to ensure the same name of DLL). The DLL will contain the same method as above, but returning a string “hacked DLL”.
4. Build the first solution. Result is that both MyApp.exe and MyDLL.dll are located in the directory Release. Run MyApp – result is expected: “correct DLL” message.
5. Build the second solution. Copy the hacked MyDLL.dll to the Release directory of MyApp. Run MyApp – result is expected:
Unhandled Exception: System.IO.FileLoadException: Could not load file or assembly ‘MyDLL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a796f58fb87e0486’ or one of its dependencies. The located assembly’s manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
File name: ‘MyDLL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a796f58fb87e
0486’
at MyApp.Program.Main(String[] args)
At this point is everything OK. But there is no GAC. So, I have continued.
6. Rebuild the first solution again. Register MyDLL.dll to GAC (C:Program FilesMicrosoft Visual Studio 8SDKv2.0Bingacutil.exe /if MyDLL.dll). Remove MyDLL.dll from the Release directory of MyApp. Run MyApp – result is expected: “correct DLL” message.
It is still OK.
7. Use a file manager (Total Commander, Servant Salamander, etc., but NO WINDOWS EXPLORER) and navigate to the GAC directory, in my case to c:WINDOWSassemblyGAC_MSILMyDLL1.0.0.0__a796f58fb87e0486. Replace MyDLL.dll by the hacked version. Run MyApp – result IS NOT expected: “hacked DLL” message.
Please, what I have missed?
Thank you for any response,
Richard
PS: Yes, I’m in the local Administrators group.
I can’t access parts 1, 2 & 4 of this series. Please fix.
@Archer: Links fixed, thanks for the tip!
You are a treasure – thanks for the guidance
@Richard Sima: excellent find. Let’s hope that timm finds the time to answer this..
Richard,
Did you ever get an answer to your question?
Really this is a good article, which helps a lot for beginners as me as well as developer. I’ve read another article over internet which explained very well about Strong Name in Assembly, please check this url…
http://www.mindstick.com/Articles/4fbdb862-6fe6-41d6-b17a-b6bec0d1dcae/?What%20is%20Strong%20Name%20in%20Assembly?
Can we assign a strong name key to multiple assemblies in a project?
Thank you, I waited this long!
Hi, i already assign my assembly using the signing tab in the properties but whenever i execute sgen to generate xml serializer, i always get a message saying the assembly is not signed.
Tnx!