HomeDigital EditionSearch Dotnet Cd
ASP.NET C# Certification Exams The CLI Data Access Editorials Extending .NET Fundamentals Interoperability Interviews Migrate Mobile .NET Mono .NET Interface Object-Oriented Programming Open Source Optimization Product/Book Reviews Security Source Code UML Visual Studio .NET

By now you've probably already created your first "Hello World" application using one of the languages in the .NET Framework such as C# or VB.NET ­ or perhaps you've even managed VC++. The .NET Framework allows all kinds of different languages to utilize code written in various other languages and by other vendors. But there's a downside: how do you make sure your code isn't used by unauthorized clients?

There's been an enormous amount of marketing and publicity surrounding the .NET Framework and all the wonderful things it can do for you. If you browse the Web at all, you simply can't escape the onslaught of advertising and marketing related to how XML Web services will change the future of programming and the future of the Web.

One of the features that Microsoft uses as a selling point for their adventurous new framework is the concept of Code Access Security (CAS). Every piece of code executed by the Common Language Runtime (CLR) runs within a security context. Such code is granted permissions based on various identifying factors that are also the elements that contribute to the strong name of an assembly. They are:

  • Filename: The filename of the assembly itself (such as MyAssembly.DLL or MyProgram .EXE)
  • Culture: The target culture of the assembly (such as en, fr, or fr-CA)
  • Version: The version number of the assembly
  • Public Key: A key that's assigned to your assembly when you build it against an RSA signature file

    It is the last of these, the public key, that we'll focus on in this article.

    Keeping Out Unauthorized Users
    Administrators can execute a security policy that grants or revokes permissions at various levels throughout the enterprise to assemblies based on any of the above identifying characteristics. This allows an administrator to prevent a given assembly from contacting hosts on the Internet or from deleting files from the local hard drive.

    It's fine that administrators can control what code is allowed to do ­ and what it's not allowed to do ­ on their own machines. But problems arise when the developers and the administrators have a conflict of interest.

    Take the following scenario: you're the publisher of some software that reads and writes its data in an encrypted, proprietary format. This is advantageous to you because only your software can read and write this data. Now, along comes .NET and you convert your software to .NET and distribute it. Let's say you have a class library that manages all of the I/O with regard to your proprietary file type. Well, with command-line utilities like ILDASM.EXE and programmatic tools using Reflection, anyone can simply examine the metadata for that assembly and get a detailed description of all methods and their arguments. It would take a programmer only a few minutes to determine how to use your assembly to manipulate your proprietary files.

    Obviously, you don't want this to happen. There are countless other scenarios in which companies need to protect their own interests by preventing their APIs and classes from being executed by unauthorized users.

    Strong-Naming an Assembly
    It might look bad, but you do have an option. Earlier, we mentioned that you can strong-name an assembly by signing it with an RSA signature file. This creates a public/private key pair and stores that pair in a file. All assemblies built using this signature file will expose the same public key, which allows them to be identified as coming from the same publisher. No one can produce an assembly with the same public key unless they manage to get access to your RSA signature file.

    To create this RSA signature file, open up a command prompt (preferably the one Visual Studio .NET provides, which automatically configures your path settings) and type the following:

    SN ­k SecureProducts.snk For our examples, we're going to work with a fictitious company called Secure Products, Inc. They produce APIs they want to restrict so only code written by Secure Products, Inc., can use them.

    I mentioned earlier that signing all your assemblies with the same signature file effectively marks them as having come from the same publisher. Let's create a sample assembly and sign it with the SecureProducts.snk file.

    To do this, open up Visual Studio .NET and create a new Class Library project (in C#). Call the project SecureAssembly and leave the default namespace and filename alone. Then open up the AssemblyInfo.cs, set the version number to 1.0.0.0, and modify the AssemblyKeyFile attribute to point to the file we created.

    You should end up with two attribute lines that look like this:

    [assembly: AssemblyVersion("1.0.0.0")]
    [assembly: AssemblyKeyFile(@"..\..\SecureProducts.snk")]

    This gives the linker enough information to properly strong-name your assembly. Make sure you copy the SecureProducts.snk file to the root directory of the SecureAssembly project; otherwise, VS.NET won't compile it.

    Now we have an assembly that's strongly named and, theoretically, digitally signed as having come from Secure Products, Inc. Let's remove the default Class1.cs class and add our own. We'll call it SecuredClass.

    Add a method to SecuredClass called GetTopSecretInformation (not very original, but it'll do for our purposes). Here's the code for that method:

    public class SecuredClass
    {
    public SecuredClass()
    {

    }

    public string GetTopSecretInformation()
    {
    return "The neon blue eagle " +
    "flies at dawn. The turtle has landed.";
    }
    }

    We don't want the contents of this string to fall into enemy hands. Therefore, we need to use a feature of CAS to demand that only code with the public key belonging to Secure Products, Inc., can instantiate this class or use it in any way.

    To do this, we need to obtain the full public key for Secure Products, Inc. In order to do that, we'll use another command-line utility called secutil. This allows us to extract security information from already compiled assemblies. Get your command prompt, go to the SecureAssembly\obj\ debug directory, and type the following:

    Secutil ­hex ­strongname SecureAssembly.dll > secutiloutput.txt

    This will create a text file that looks a little like this:

    Microsoft (R) .NET Framework SecUtil 1.0.3512.0
    Copyright (C) Microsoft Corporation 1998-2001. All rights reserved.

    Public Key =
    0x00240000048000009400000006020000002400005253
    41310004000001000100EB8C810B9B
    24A636F7FFCA28693AB03DA926839C0FCC5C2B4F0A94CE
    0C94EB9690F519AC71AAC3C38F9AAD
    AD460DEC33BFD8678B8199322BDC586F757339E6CE88DD
    ED22B03466F8AB2205C75E8406A0F4
    0C33F7FC11F06C73A43C95B21DD9E9ABD27C5B994605423
    3FF5C6B37D89690696CCDB41D7E74
    F8B59E66FB5EA1059E
    Name =
    SecureAssembly
    Version =
    1.0.0.0
    Success

    Now we're going to highlight the entire public key hex string (except the prefix of 0x, which is redundant since we know the string is in hex) and copy it to the clipboard.

    Then, we'll use the public key we copied to place the following attribute at the top of our SecuredClass class definition, as follows:

    [StrongNameIdentityPermission(SecurityAction.LinkDemand,
    PublicKey="002400000480000094000000
    06020000002400005"+
    "25341310004000001000100EB8C810B9B2
    4A636F7FFCA28693"+
    "AB03DA926839C0FCC5C2B4F0A94CE0C94E
    B9690F519AC71AAC"+
    "3C38F9AADAD460DEC33BFD8678B8199322
    BDC586F757339E6C"+
    "E88DDED22B03466F8AB2205C75E8406A0F
    40C33F7FC11F06C7"+
    "3A43C95B21DD9E9ABD27C5B9946054233F
    F5C6B37D89690696"+
    "CCDB41D7E74F8B59E66FB5EA1059E")]
    public class SecuredClass

    What we're doing here is informing the CLR that any attempt to access this class (both static and object instances) must have the public key we specify (hence the LinkDemand enumeration value).

    If not, the CLR will throw an exception. There's no way to create an assembly that has this public key without possessing the private key belonging to it ­ and that resides in our SecureProducts.snk file. Therefore, keep your signature files secure.

    Security Test
    Now, to prove my point and to make sure this is more than just smoke and mirrors, I'll create a console application that references this assembly. I'll use it to create an instance of the SecuredClass class and try to print out the contents of the top-secret string. Here's my basic code for the console application:

    static void Main(string[] args)
    {
    //
    // TODO: Add code to start application here
    // SecureAssembly.SecuredClass
    secClass = new SecureAssembly.SecuredClass();
    Console.WriteLine("Top Secret Information is: {0}",

    secClass.GetTopSecretInformation());
    }

    I build the project as-is (without digitally signing it!) and run it. Figure 1 is a screenshot of the output. As you can see, the results aren't pretty and we don't get a chance to execute the method we wanted.

    Figure 1

    Now I'll create another console application, but this time I'll make sure that the AssemblyInfo.cs file contains the following:

    [assembly: AssemblyKeyFile
    (@"..\..\..\SecureAssembly\SecureProducts.snk")]

    Using my directory structure, this attribute points directly to the SecureProducts.snk file used to sign the SecureAssembly. Setting my version to 1.0.0.0 and building, I then run the application and receive the output shown in Figure 2.

    Figure 2

    The moral of the story is that while the .NET Framework allows all kinds of different languages to utilize code written in various other languages and by other vendors, there is a downside. If you want to make sure that your code doesn't get used by unauthorized clients, then you'll need to do something similar to what I've done here.

    Security Loophole?
    The other thing you should be concerned with is the visibility of constant strings in your code. For example, bring up your command prompt, go to the \SecureAssembly\obj\debug directory, and type:

    ILDASM SecureAssembly.dll

    With a little bit of navigation and clicking, we get to the method definition in IL (Intermediate Language) shown in Figure 3.

    Figure 3

    Well, isn't that handy? Our super-secret private information is there in plain view for everyone to see. Why would we need the public key or digital signature if we can just peel the information right out of it with ILDASM, a tool that ships for free to anyone who wants it?

    Unfortunately there's no easy answer here. If you're worried about constants in your code being visible to the wrong people, you'll need to encrypt or obfuscate those constants. The innards of all of your assemblies should be considered open books to those who know how to open them.

    Summary
    Hopefully, the information I've given you here will help you maintain some semblance of security on your assemblies. By using the technique of demanding a public key to execute your code, and additionally encrypting or obfuscating all the string literals in your code, you should be able to produce extremely tamper-proof, secure assemblies.

    Author Bio
    Kevin Hoffman has been programming since he was 10 and has written everything from DOS shareware to n-tier, enterprise Web applications in VB, C++, Delphi, and C. kevin_hoffman@cch-lis.com

    All Rights Reserved
    Copyright ©  2004 SYS-CON Media, Inc.

      E-mail: info@sys-con.com