State Street Gang
.NET, straight up

A NET Cryptography Primer, Part 3

April 16, 2008 12:09 by Will

Part one covered the background, part two went into detail about cryptographic hashes.  Part three covers the most easily understood type of encryption, though you wouldn't know it by its name:  symmetric encryption.

Symmetric Cryptographic Algorithms

Sometimes referred to as "shared secret" cryptography, Symmetric cryptographic algorithms encrypt and decrypt data using a trivial key.  Its name comes from the fact that encryption and decryption both rely upon the same key. 

A common example of symmetric cryptography in action is the common zip file.  You have the option to add a password to the zip file when creating it.  You must, in turn, provide the same password when the file is decrypted.  In order for your secret stash to stay hidden from your mom's eyes, you have to keep the key secret.  For example, you shouldn't write it on a post-it note pasted to your monitor.

Types of Symmetric Algorithms

There are five different types of symmetric algorithms available in System.Security.Cryptography.  They are DES (Data Encryption Standard), TripleDES, RC2, and Rijndael/AES (Advanced Encryption Standard). 

DES and TripleDES

DES is an older standard, originating from government requirements back in the 70's.  Since it was designed for the computing power available at that time, it is considered very weak today.  It can be brute-force cracked in under a day's worth of computation at today's power.  DES has been superceded by both TripleDES, which runs data through the DES encryption algorithm three times (why not QuadDES?  I dunno.), and Rijndael/AES.

RC2

RC2 was a follow-up to DES developed for Lotus Notes with the goal of being more secure but legal for export overseas.  There are also more secure versions with longer keys, but they are all called RC2 in .NET; only the key length is changed (this isn't exactly true; research it if you want more info).  RC2 is most famous for being the encryption used by WEP (with a 40 bit key).  If you're running your wireless access point with WEP, somebody is right now connected to your network chatting up 13 year olds on MySpace.  You should go home immediately, rip out your router by the power cord, and slam it into the wall.  RC2 in its default form is NOT considered secure and should not be used when better alternatives are available.  WEP2, by the way, uses AES for encryption.

Rijndael/AES

Rijndael is considered the most secure of the crop of symmetric algorithms available to .NET programs.  I'm not sure what the differences between them are, but supposedly AES is the official, NSA approved version of Rijndael.  They are both different enough to be implemented separately.  If you have a choice among all symmetric algorithms, you should always use one or the other as they are the most secure and are projected to be secure for another 20 or so years. 

Initialization Vectors and You

Symmetric algorithms introduce a new requirement that must be understood:  The Initialization Vector, or IV.  Very simply, the symmetric algorithm must start somewhere, and that is the job of the IV.  Symmetric algorithms usually use "block chaining" to add an additional layer of randomness to the cypher.  This is done by logically XOR-ing the current block with the previously processed block.  This process is reversible, so it works well and is fast.  However, to fully encrypt the first block of text you need a previous block to XOR it with.  That is the purpose of the IV, to be the starting point of this process.  Because it does impact the rest of the cypher, the same IV must be used to decrypt as was used to encrypt.  Usually, in order to avoid having to memorize a random series of bytes along with your password, the IV is generated from the password itself.

CODE ALREADY!

The pseudocode for encrypting is:

  1. Convert the string to encrypt into a byte array
  2. Generate our IV from our password
  3. Create our encryption provider (Rijndael in this example)
  4. Get an encryptor using our password and initialization vector
  5. Encrypt our string to encrypt
  6. Return the encrypted data as an encoded string

 

The pseudocode for decrypting is:

  1. Decode our encrypted data into a byte array
  2. Create our provider with the same configuration
  3. Generate an IV from the given password
  4. Get a decryptor using our password and IV
  5. Decrypt the encrypted bytes
  6. Convert the byte array into a string

A Word About IV Generation

The current, cryptographically secure, deterministic and non obsolete way to generate our IV from our password is to use the class Rfc2898DeriveBytes.  This is a replacement for the PasswordDeriveBytes class that you'll see in most examples on the net.  This class takes a password and a salt and provides a method called GetBytes which provides an easy way to get your key and IV for use by your symmetric algorithm provider.  If you use the same password and same salt, you are guaranteed to get the same bytes, and these bytes are generated in a secure manner. 

Generally, you don't want to require users to remember a random salt along with their password, so its best to base it off of your password.  In this example, I use the following method, which will generate a salt that's different for each password, but is always the same for the same password:

private byte[] GenerateSalt(string password)
{
    return Encoding.Default.GetBytes(
        "A salt must always be the same"
        + "for Rfc2898DeriveBytes to give you"
        + "the same password bytes and IV for"
        + "each password, or in this case: "
        + password);
}

 

Encrypting

The encryption method demonstrates how to use the Rfc2898DeriveBytes class to generate a key and IV from your password and salt:

private string Encrypt(string password, 
                       string toEncrypt)
{
    Rijndael rinedal = null;
    byte[] toEncBytes = null;
    try
    {
        toEncBytes = Encoding.Default
                             .GetBytes(toEncrypt);
 
        Rfc2898DeriveBytes pdb = new 
            Rfc2898DeriveBytes(
            password,
            GenerateSalt(password));
 
        rinedal = Rijndael.Create();
        rinedal.Padding = PaddingMode.ISO10126;
 
        ICryptoTransform tx = rinedal
            .CreateEncryptor(
            pdb.GetBytes(32), // our key
            pdb.GetBytes(16)); // our IV
        byte[] encrypted = 
            tx.TransformFinalBlock(
            toEncBytes, 
                0, 
                toEncBytes.Length);
 
        return Convert.ToBase64String(encrypted);
    }
    finally
    {
        // this clears out any secret data
        if (rinedal != null)
            rinedal.Clear();
        // zeroes out our array
        if (toEncBytes != null)
            for (int i = 0; i < toEncBytes.Length; 
                i++)
                toEncBytes[i] = 0;
    }
}

 

We use the default system encoding to convert the text to a byte array.  Next, we use our GenerateSalt method, along with the given password, to instantiate our Rfc2898blahblah object.  We get the implementation of the Rijndael algorithm configured on the system next, and specify what type of padding mode to use. 

Symmetric algorithms work on fixed sizes of data, or blocks, so when data doesn't fill up a block the remaining space must be padded somehow.  Default padding modes may differ between systems, so being specific here is better than not.

Next, we get our encryptor from the provider, passing in bytes for our key and initialization vector.  Key and IV lengths must be certain lengths, depending on the flavor of algorithm you are using.  For instance, Rijndael allows for a maximum key length of 256 bits, or 32 bytes.  Consult the docs for your algorithm to find out what sizes are acceptable.

Once encrypted, we convert the encrypted byte array into a string that can be easily stored and retrieved.  And in our finally block we do a little house cleaning, sweeping up all our secret data (or as much as we can do easily). 

Decrypting

The decryption method is just the reverse of the previous:

private string Decrypt(string password, string toDecrypt)
{
    Rijndael rinedal = null;
    byte[] toDecBytes = Convert
                        .FromBase64String(toDecrypt);
    try
    {
        Rfc2898DeriveBytes pdb = new 
            Rfc2898DeriveBytes(
                password, 
                GenerateSalt(password));
 
        rinedal = Rijndael.Create();
        rinedal.Padding = PaddingMode.ISO10126;
 
        ICryptoTransform tx = rinedal
            .CreateDecryptor(
                pdb.GetBytes(32),
                pdb.GetBytes(16));
 
        byte[] decrypted = tx.TransformFinalBlock(
            toDecBytes, 0, toDecBytes.Length);
 
        return Encoding.Default.GetString(decrypted);
    }
    finally
    {
        if (rinedal != null)
            rinedal.Clear();
    }
}

 

Summary

Symmetric cryptographic algorithms use a key, commonly referred to as a password, to encrypt and decrypt data.  There are lots of different versions available, but Rijndael and AES are the current industry standards.  You'll need to generate an initialization vector (IV) using the Rfc2898DeriveBytes object.  The bytes you use as the key and IV must be the correct length for the algorithm you use. 

Part Four Preview

In part four we go over (or maybe just start to go over; its pretty complex) asymmetric cryptographic algorithms.  These use public/private key pairs to perform one-way encrypting and data signing, and is some pretty heavy and useful stuff.  Could somebody else write that one for me, please?  This stuff is getting complex!

kick it on DotNetKicks.com
Tags:
Categories: Cryptography | Security | Tips
Actions: E-mail | Permalink | Comments (7) | Comment RSSRSS comment feed

Ouch

April 14, 2008 09:08 by will

I love BlogEngine.NET, but damn!

Patched, btw. 

And a quick fix to keep files secure on a website is to give them extensions that IIS/ASP.NET won't send, such as .config or .cs or other code file extensions.


Tags:
Categories: Nuts | Security | Tips
Actions: E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed

A NET Cryptography Primer, Part Two

April 11, 2008 11:52 by Will

By now you should better understand managed vs. unmanaged classes in System.Security.Cryptography namespace and how to move from strings to byte arrays and back again.

This post covers storing passwords in a secure manner using salty hash.  Yum.

Cryptographic Hashing

A paragraph or two about cryptographic hashes before covering the secure storage of passwords.  We all know what hash functions are; every object in the .NET platform contains the method GetHashCode(), which returns an integer representation of an object.  A cryptographic hash is an algorithm that takes a string of any length and returns a fixed size, highly random yet deterministic string.  For a cryptographic hash to be considered secure, it must produce the same output for the same string, yet vastly different outputs for two very similar strings.  This makes it easy to verify yet hard to crack.

Probably the most important thing to understand is that secure cryptographic hashes are very difficult, if not impossible, to reverse.  That means, once data passes through the hash algorithm, you cannot reverse the hash function and get the original data back out.  Obviously, this limits the scenarios where cryptographic hashes are useful.  But, because cryptographic hashes are simple, secure, and don't require any kind of "shared secret" to be hidden in the source code, they are widely used.  With the application of the proper patterns, they can be extremely useful for keeping data secure.

Hash Without Salt is Bland

One of the weaknesses of cryptographic hashing is that it is deterministic, meaning that string A will always produce hash B when using the same hash algorithm.  This allows attackers an avenue to crack a hash:  Guess the original string, A.  This weakness is very evident in password storage.  A hacker, with a list of all password hashes in a database, can gain access to accounts using a lookup table.  This table has, for a given hash algorithm, pre-calculated hashes for certain combinations of characters.  Simple ones contain hashes for words in the dictionary.  That seems a bit complex and large, but considering a password of length 8 consisting of the 48 characters readily available to you on your keyboard has approximately 377 million combinations (I hope I got my stats correct), its actually the simplest thing to do.

To combat this, a random string of characters is added to the password, either to the front or the back.  This increases the overall length of the password, making random character lookup tables exponentially more difficult to use.  It also breaks dictionary attacks as, even though the salt is eventually stored in the database along with the hash, you must re-create the dictionary lookup table with each stored salt, a monumental task in and of itself.

I Thought You Were Emphasizing Code

Right.  Now we know what to do, we can generate some pseudocode to identify our password hashing code's inputs and outputs.  To store passwords securely using a cryptographic hash, we must:

  1. Take a user identifier and a password from the user
  2. Create a salt of random characters
  3. Concatenate the given password with the generated salt (in a standardized way)
  4. Use a cryptographic hash algorithm to encrypt this string
  5. Store the encrypted string, the hash, and the unencrypted user identifier

 

To verify a password, we must:

  1. Take a user identifier and a password from the user
  2. Look up the encrypted string and hash using the given user identifier
  3. Combine the retrieved hash and the given password in the standard way
  4. Use the cryptographic hash algorithm to encrypt this string
  5. Compare the newly encrypted string with the one retrieved from the database
  6. If they match, return positive, otherwise return negative

 

The Salt

Salts must be random.  More random that System.Random can provide.  The .NET platform provides a means to create a random enough salt via RNGCryptoServiceProvider.  Here's the code:

private static string CreateSalt(int saltStrength)
{
    byte[] temp = new byte[saltStrength];
    RNGCryptoServiceProvider.Create().GetBytes(temp);
    return Encoding.Default.GetString(bytes);
}

because I'm concatenating the salt to a string, I'm converting the byte array of random bytes into a Unicode string using the system's default code page.  Be careful in this step; if you convert the array into a hex string, for example, you significantly reduce the randomness of the salt (255 possibilities for n characters vs. 16 possibilities for n characters).  Keeping the salt big and encoding it as Unicode (or not encoding it at all) is the best way to go.

The Hash Method

Now that we can generate our salt, we can continue with the hash method.  The only weird thing about this method is that it takes the name of the hash algorithm implementation as a string.  I've included statics for the names of the most common hash algorithms.

public const string SHA1HashName = "SHA1";
public const string SHA256HashName = "SHA256";
public const string SHA512HashName = "SHA512";
public const string MD5HashName = "MD5";
 
public static string HashPassword(string hashName, 
            string password, 
            out string salt, 
            int saltStrength)
{
    HashAlgorithm ha = 
        HashAlgorithm.Create(hashName);
    if (ha == null)
        throw new InvalidOperationException(
            "Cannot map name " + hashName + 
            " to a hash algorithm.");
 
    salt = CreateSalt(saltStrength);
    byte[] temp = Encoding.Default.GetBytes(
                             password + salt);
    temp = ha.ComputeHash(temp);
 
    return Convert.ToBase64String(temp);
}

Pretty simple and straight forward.  This method converts the encrypted byte array into a base64 string for ease of storage.  You could, of course, store it as binary data or encode it differently.  At this point, it mostly doesn't matter; all you're doing is substituting length for complexity, resulting in equally secure crypts.

Note the salt argument is an out parameter.  This is because not only will you store the return value of this method, but also the salt generated.  Not as elegant as a F# tuple, but it works.

The Verify Method

When a user comes to us and claims to be someone known to the system, they give us a user identifier (aka user name) and password as proof.  We can use the following method to compare the two.  Please note, prior to this method being called, you must retrieve the salt and encrypted password from your repository (file, database, etc) for the given user identifier.

public static bool Verify(
    string hashName, 
    string password, 
    string encryptedPassword,
    string salt)
{
    HashAlgorithm ha = 
        HashAlgorithm.Create(hashName);
    if (ha == null)
        throw new InvalidOperationException(
            "Cannot map name " + hashName + 
            " to a hash algorithm.");
 
    byte[] temp = Encoding.Default.GetBytes(
                        password + salt);
    temp = ha.ComputeHash(temp);
 
    string toTest = Convert.ToBase64String(temp);
 
    return encryptedPassword.Equals(
        toTest, 
        StringComparison.Ordinal);
}

This method is very similar to the first, except that we return the result of an Ordinal Equals comparison.  Note that we are converting to a base64 string, just like in the encrypt method.  Also note the comparison is ordinal.  This is because Convert.ToBase64String returns a string encoding that includes only simple ASCII characters, and is not affected by the language or culture that this code is running under.  I think.  I can't guarantee this will pass the Turkey test.  If you're expecting your hashes to run in different cultures, a little more investigation into the encoding is warranted.

Summary

Hashing is a one way business.  And hash is not all that good without a healthy dose of salt.  But a nice salty hash is great for encrypting and storing passwords without having to hard-code a password into your source code, which is dumb.

Part Three Preview

In part three, we will be covering symmetric, or "shared secret", encryption.  Every time a developer hard-codes a password in their source code, God kills a kitten.  Please, think of the kittens!

kick it on DotNetKicks.com
Tags:
Categories: Cryptography | Security | Tips
Actions: E-mail | Permalink | Comments (7) | Comment RSSRSS comment feed

InternalsVisibleToAttribute and Strong Named Assemblies Step by Step

April 9, 2008 12:17 by Will

One of the hassles with testing is that best practices and OO design often makes it very difficult to thoroughly test your code.  We should be marking classes internal to our assemblies unless we specifically wish them to be part of the public API of our DLL's.  This means to test these internal classes we have to use proxy classes that can instantiate and invoke members of these internal classes via reflection.  Visual Studio provides for some auto-generated code for this, but it can be a bit unwieldy and is not available in all versions of VS.  It would be easier if we could specify a test assembly as having access to all these internal classes.

Another case where we might want to make our internal classes available to specific outside callers is for security purposes.  If we don't want anyone but ourselves to use a specific DLL, we would want to mark all classes internal to the DLL and specify only those assemblies with our strong name have access to them.

The InternalsVisibleToAttribute allows us to do this.  According to the documentation, the syntax is pretty easy:

[assembly: InternalsVisibleTo("MyTestsLol")]

This would allow assembly MyTestsLol.DLL access to the internal classes of the assembly where this attribute is located.  And this works great.  For unsigned assemblies only.  When you sign the assembly you wish to mark with this attribute, things get more complex.

Lets say you have two assemblies, My.DLL and MyTestsLol.DLL.  You add the above attribute to the AssemblyInfo.cs file within the My.DLL project.  Everything works great; you can access and test all internal classes in My from within MyTestsLol.  But you're moving to a production oriented environment and you decide that you should be signing your assemblies, because you've read that's what professional .NET developers do.  So you sign My.DLL and build the project:

Friend assembly reference 'MyTestsLol' is invalid. Strong-name signed assemblies must specify a public key in their InternalsVisibleTo declarations.

Now you're screwed.  And if you Google this, you'll still be screwed because most of the information about InternalsVisibleTo and strong named assemblies is either wrong or too cryptic to understand.  If you find yourself at this point, here is the step-by-step procedure how to get this working again.

Gimme three steps to fix

image First, you will need to sign every assembly you wish to grant access to your internals.  Open up the properties editor for the assembly you wish to give access to, in this case MyTestsLol.DLL, and select the Signing tab.

I'd suggest creating a new, throw-away key pair for test assemblies.  For assemblies you are going to distribute you should use your regular key pair.

Second, you must extract the public key from the public/private key pair, then display the public key.  This is a two-part process that is necessary in order to get the correctly encoded version of the public key. 

Open the Visual Studio command prompt (All Programs -> Visual Studio 2005/8 -> Visual Studio Tools).  Browse to the directory where the new public/private key pair is located.  At the prompt, enter the following command (the name of the key pair (.snk) may be different if you chose a different name for the strong name key file):

sn -p fortestsonly.snk publickey.pub

This creates a file, called publickey.pub, that contains the public key portion of the public/private key pair in binary format.  Next, you need to view the public key in an encoded format (I believe its Base64) that you can use.  Do this via the following command:

sn -tp publickey.pub

This displays both the full public key and the public key token, which is a much smaller hash of the full public key.  You'll need the full public key (the token will not work), so select it and copy it out of the console.  Consoles suck, so you'll have to remove all the newline's when you paste it into your assembly. 

Finally, adjust your InternalsVisibleTo argument to add the public key (the public key should reside on a single line and be roughly three hundred something characters long):

[assembly: InternalsVisibleTo("MyTestsLol, 
    PublicKey=0024...8db5")]

The ellipsis is just to keep the key from blowing up my blog's layout. 

This will now work, and you can reference internal types from the MyTestsLol assembly.  Unfortunately, there isn't an equivalent attribute you can place on a type to allow its internals be visible to another type or another assembly, which would have made unit testing private methods a snap.  I'm not sure exactly why we don't have this kind of facility in the .NET platform.  Maybe in 4? 

kick it on DotNetKicks.com
Tags:
Categories: CLR | Testing | Tips
Actions: E-mail | Permalink | Comments (4) | Comment RSSRSS comment feed

Can't save results of the run since ResultFilePath is null.

February 21, 2008 11:12 by will

I've been hit by this lovely error a number of times over the past year when attempting to run unit tests in Visual Studio 2005.  I always end up searching for the answer, encountering the fifty or so different "solutions" that fail horribly.  So now I save it here.

The fix is to reset your environment in Visual Studio.  You can do this by opening a Visual Studio Command Prompt (MS Visual Studio 2005 -> Visual Studio Tools from the start menu) and run the following command (PLEASE READ ON prior to running this!  Important stuff comes later!):

devenv /resetuserdata

This brings Visual Studio back to the primordial stage.  Unfortunately, you lose all your settings.  That includes all your tricky VS fonts and colors customizations.  You won't lose your Add-ins, however.  So if you want to save and then reload all your UI customizations, you'd better save them first. 

For some info about saving color and font settings, you can check out this post over at CodingHorror.


Tags:
Categories: Debug | Testing | Tips
Actions: E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed