The Secrets of Strong Naming
by Mike Gunderloy04/28/2003
If you've been working with .NET for any length of time, you've probably run
across the concept of a strong name. No, that doesn't mean that your
assemblies should have names like MyCompany.Gorilla.Biceps. The
strength of a strong name lies in the protection that it offers your assemblies.
The .NET Framework uses strong names to identify assemblies and to protect them
from tampering. In this article, I'll show you how strong names are constructed
and demonstrate the mechanics of working with strong names in .NET.
Hashes and Signing
To grasp the way that strong names work, you first need to understand a pair of cryptographic concepts: hashing and digital signatures.
Hashing is used to create a unique, compact value for a plaintext message. "Message" is a very broad term here; in terms of assemblies, the message is the assembly itself. The message is used as an input to the hash algorithm (in the case of strong naming, the SHA1 algorithm is used). Figure 1 diagrams the process.
|
| Figure 1. How hashing works |
Hashing is a one-way street: you can't decrypt the hash value once it has been computed. However, hashing is very useful for comparing values. If two assemblies produce the same hash value, you can assume that the assemblies are the same. Conversely, if hashing an assembly produces a value that doesn't match a previously-calculated hash, you know that something in the assembly has been changed.
Knowing the hash value for an assembly lets you check that no one has tampered with the assembly. But how do you prevent someone from tampering with the hash value? That's where digital signing comes in. While the mathematics of digital signatures are complex, the concept is fairly simple. A digital signature depends on a pair of related numbers, the public key and the private key. When data is encrypted with the public key, it can only be decrypted with the private key (and vice versa), as shown in Figure 2.
|
| Figure 2. Using key pairs |
Strong Naming for Assembly Identity
The combination of hashing and digital signing allows .NET to protect your assemblies from tampering. Here's how it works. First, a hash value is created from the assembly. Then, the hash value is encrypted with your private key and placed, along with your public key, in the assembly itself. Figure 3 shows this process schematically.
|
| Figure 3. Placing a strong name in an assembly |
The CLR validates assemblies at runtime by comparing two sets of hash values. First, the public key is used to decrypt the encoded version of the hash. Second, a new hash is computed from the current contents of the assembly. If the two hashes match, all is well. Figure 4 shows this process.
|
| Figure 4. Checking the strong name in an assembly |
What happens if an assembly has been tampered with after it was signed? In this case, the new hash value calculated at runtime won't match the stored hash value that was encrypted with your private key. Under those circumstances, the CLR will refuse to load the assembly.
Note that the strong name guarantees the integrity of the assembly, not necessarily its safety! There's nothing to prevent someone from creating a malicious assembly and signing it with a strong name. You can use a strong name to verify that an assembly came from a particular source, and that it wasn't tampered with after it was signed. It's up to you to decide, based on whatever information you choose, whether to trust code from that source.
What's in a (Strong) Name?
|
Related Reading
.NET Framework Essentials |
In addition to a hash derived from the assembly's contents, the strong name includes three other pieces of information:
- The simple text name of the assembly
- The version number of the assembly
- The culture code (if any) of the assembly
All of this information works together to supply a unique identity for each assembly. The CLR uses this information when deciding whether a particular assembly is the one called for by a reference from another assembly. When you set a reference from one assembly to another, the calling assembly stores a representation of the called assembly's public key. At runtime, the CLR can use this to check that the referenced assembly comes from the correct vendor. In addition, the other information in the strong name is used to determine whether a particular assembly fills the binding policy requirements for the reference (see my article "Binding Policy in .NET" for further details).
The Mechanics of Strong Naming
Both the .NET Framework SDK and Visual Studio .NET provide tools for
assigning strong names. That makes sense, because using Visual Studio .NET to
create assemblies is completely optional. Before you can sign anything, you need
to create a key pair (consisting of a public key and a private key).
Typically, you'll store your key pair in a file with the extension .snk. To do
this, you use the strong name tool, sn.exe:
sn -k MyKeyFile.snk
If you're using the command-line compilers (vbc.exe or csc.exe), you can
specify the key pair to use in your command line to the assembly linker, al.exe.
For example, you might sign MyFile.dll with the key pair in MyKeyFile.snk with
this command line:
al /out:MyFile.dll MyFile.netmodule /keyfile:MyKeyFile.snk
If you're using Visual Studio .NET, you'll still generate your key pair at
the command line. After generating it, you can include it in your assembly by
specifying the AssemblyKeyFile attribute in the assembly information file
(AssemblyInfo.vb or AssemblyInfo.cs). In a C# project, for example, you can
include a key file and produce a signed assembly with this attribute:
[assembly: AssemblyKeyFile("..\\..\\MyKeyFile.snk")]
The filename in the AssemblyKeyFile attribute should include the full
relative path from the compiled assembly to the key file.
Keeping Secrets with Delay Signing
Protecting your private key is obviously very important; if a nefarious person gets your private key, they can produce assemblies that appear to have been signed by you. Because of this, you may wish to keep your private key a closely-guarded secret, known only to a few people in the company. But then, how can you handle assembly signing? It would be tedious if you were the only person who knew the private key, and you had to sign every build of every assembly produced by every developer in your company.
Fortunately, .NET provides a way around this problem: delay signing. With delay signing, you can build and test an assembly knowing only the public key. The private key can be applied later if the assembly is actually shipped to customers. Here is a summary of the delay signing process:
- Extract the public key from the public/private key pair. To extract
the public key from a file that is storing the public/private key pair, you can
use the strong name tool with a slightly different command line:
sn.exe -p MyKeyFile.snk MyPublicKeyFile.snk - Distribute the file containing only the public key to all of the developers in the company, and store the file containing both keys securely.
- Include the public key file in your assembly information file, and
specify delay signing:
[assembly: AssemblyDelaySign(true)] [assembly: AssemblyKeyFile("..\\..\\MyPublicKeyFile.snk")]If you're using the assembly linker tool rather than Visual Studio .NET, use the
/delaysigncommand-line switch to indicate delay signing. - Turn off verification for the assembly if you're storing the assembly
in the GAC. By default, the GAC verifies the strong name of each assembly. If
the assembly is not signed by using the private key, this verification fails. So,
for development and testing purposes, you can relax this verification for an
assembly by issuing the following command:
sn.exe -Vr MyFile.dll - At this point, you can use the assembly freely in testing and development.
- When you're ready to deploy a delay-signed assembly, you need to sign it
with your private key:
sn.exe -R MyFile.dll MyKeyFile.snk - Finally, you can instruct the GAC to resume verification for an assembly
by issuing the following command:
sn.exe -Vu MyFile.dll
Trustworthy Computing
You've undoubtedly heard of Microsoft's "Trustworthy Computing" initiative, which involves intensive security reviews of all shipping Microsoft products. Microsoft is slowly but surely moving towards a world in which all of their software is secure by default. If you know what you're doing, you can relax the security of software such as Windows Server 2003, but it's designed to make it hard to make yourself vulnerable by accident.
When you assign strong names to your assemblies, you're doing your part for trustworthy computing. Shipping your code with strong names makes it much less likely to be used as a carrier for a trojan horse or other attack on someone's machine. The .NET Framework and Visual Studio .NET provide the tools to make it easy for you to protect the integrity of your shipping code. I strongly urge you to make use of these tools, and by doing so, make the computing world just that tiny bit safer.
Mike Gunderloy is the lead developer for Larkware and author of numerous books and articles on programming topics.
Return to ONDotnet.com
Showing messages 1 through 6 of 6.
-
Tampering how?
2007-10-28 22:22:50 SrisailReddy [View]
The article says , .Net framework uses the strong naming to protect assemblies from tampering. Can you please explain me what exactly you mean by tampering . An example would be great. -
Tampering how?
2008-06-02 03:28:35 Bernd Wechner [View]
Two obvious paths come to mind:
1) I find out what the interface spec to the DLL is (which I may be able to extract from the DLL itself given enough talent and the right tools), then I right whatever coded I want that meets this spec. That is I provide classes and methods that the program loading the DLL expects, but behind them I do whatever I jolly well want. I then replace the original DLL i the distribution with my DLL and redistribute it. You acquire it somehow and run the program you trust and you're running my code when you do that. Not something you want to do because my code may well be scanning your PC for all sort of handy info to compromise your system and/or just spread a chest beating "I've done it" virus or any other kind of thing I want to do which you ran because you thought you were running some program you trusted.
2) I open the DLL in a hex editor and employing y extensive knowledge of the internal structure of DLLs identify a neat code entry point where in patch directly, knowing the encoding used in the DLL the binary code for a snippet of machine code I've written which does something snide and trivial yet undesirably to you, to or on your PC.
These boil down essentially to two scales of tampering.
1) replacing the DLL completely with my cleverly written yet disguised DLL.
2) Modifying the existing DLL with my code with my patches to it.
That should just about cover the tampering options. The rest is detail and a fair bit of low level knowledge on how this works. That is, no-one needing to read this article probably knows how ;-). People who tamper with DLLs already know stuff like how strong naming works and a heck of a lot more about how .NET and DLLs all hang together!
-
Can we use the same process with COM
2003-05-20 12:19:40 anonymous2 [View]
How can we delay sign a COM Component, will the above process also work?
-
Figure 3 should say private key
2003-05-19 09:30:25 anonymous2 [View]
Figure 3 should say private key rather than public key (the text above the diagram is correct, its just the diagram that is wrong) -
Figure 3 is correct
2003-05-22 23:49:07 anonymous2 [View]
Including the private key in the assembly would make the whole process pointless. The private key is used to encrypt the hash. The encrypted hash and public key are stored in the assembly. That is what the text above the figure says and the figure correctly reflects the text. -
Figure 3 is correct
2003-07-27 20:28:48 anonymous2 [View]
The point the previous poster tried to make was that the arrow from the hash to the public key and then into the assembly makes it look like the hash is modified with the public key and stored in the assembly.









