CLR Inside Out
New Library Classes in "Orcas"
Mike Downen and Inbar Gazit and Justin Van Patten


Contents


F
or the next version of the Microsoft .NET Framework (which will ship with the next release of Visual Studio® currently code-named "Orcas"), its assemblies have been divided into two groups, internally referred to as "red bits" and "green bits." The red bits include all the libraries that shipped before as part of the .NET Framework 2.0 and 3.0 (such as mscorlib.dll and system.dll). To maintain a high assurance of backward compatibility for Visual Studio "Orcas," changes in the red bits have been greatly limited.

The green bits assemblies are the brand new libraries with additional classes that work on top of the red bits assemblies. Most of the classes listed in this column are in the green bits assemblies (such as system.core.dll), with a few involving limited changes in the red bits assemblies. For more background information, check out Soma Somasegar's blog and Jason Zander's blog.

The classes described in this column are available as part of the January 2007 Visual Studio "Orcas" Community Technology Preview (CTP). The CLR's contributions to the new libraries include:

In this column, we'll discuss the new Suite B cryptography features, big integer support, the set class, and the pipes capabilities.


Suite B Support

One of our major goals for Visual Studio "Orcas" was to add support for the Suite B set of cryptographic algorithms. In order to support Suite B, a platform has to support:

More information about Suite B is available in the overview published by the NSA at www.nsa.gov/ia/industry/crypto_suite_b.cfm.

In addition to these criteria, we also wanted to support Federal Information Processing Standard (FIPS) certified implementations of these algorithms. We've had support for AES (via our RijndaelManaged class) and SHA-256 and SHA-384 (using our SHA256Managed and SHA384Managed classes) since version 1.0 of the .NET Framework, but our implementations were not FIPS-certified.

As a first step, we added managed code wrappers for the FIPS-certified AES, SHA-256, and SHA-384 implementations in Windows. In Visual Studio "Orcas," these appear as the new AesCryptoServiceProvider, SHA256CryptoServiceProvider, and SHA384CryptoServiceProvider classes. All of these are located in the System.Security.Cryptography namespace.

These algorithms are available on all platforms on which the underlying Windows Crypto Service Providers are available-Windows XP and later for AES, and Windows Server® 2003 and later for the SHA algorithms. They generally work exactly like their managed equivalents, so developers should typically be able to swap them in without noticing any changes in behavior. The one difference is that, per the AES specification, AesCryptoServiceProvider only supports a fixed block size of 128 bits.

The CngKey Class

To support our new CNG-based managed cryptography classes, we've added a CngKey class to abstract the storage and usage of CNG keys. CNG keys work similarly to key containers in today's Crypto API (CAPI)—they allow you to store a key pair or a public key securely and refer to it using a simple string name. You can use CngKey objects when working with the ECDsaCng and ECDiffieHellmanCng classes.

You can also use the CngKey class directly to perform many operations, including opening, creating, deleting, and exporting keys. If we don't have a managed API for the operation you want, you can get to the underlying key handle to use when calling Win32® APIs directly.



Elliptic Curve Cryptography

Then we added classes for ECDSA and ECDH. These classes wrap the new Crypto Next Generation (CNG) implementations of these algorithms in Windows Vista™. (For more details on how we support CNG classes, see the sidebar "The CngKey Class.") Elliptic curve cryptography is asymmetric, meaning it uses a public and private key pair for operations, similar to RSA. But elliptic curve algorithms are generally more efficient computationally than traditional public key cryptography algorithms, especially as key sizes grow larger. In fact, the NSA recommends an RSA key size of 15,360 bits to protect a symmetric key of 256 bits, whereas it recommends just a 521-bit elliptic curve key to protect the same 256-bit symmetric key.

More information on the benefits of elliptic curve cryptography is available in the NSA's article "The Case for Elliptic Key Cryptography".


ECDSA

ECDSA works like most signing algorithms: you sign with a private key and verify with a public key. The new ECDsaCng class contains our implementation of ECDSA and follows the same pattern as other managed cryptography classes. Say you want to sign some data, assuming your key pair is stored in a CNG key named MyKey:

// Returns the signature
byte[] SignMyData (byte[] data)
{
   ECDsaCng signingAlg = new ECDsaCng(CngKey.Open("MyKey"));
   return signingAlg.SignData(data);
}

Now, say you want to verify a signature from Jane and her public key is stored in a CNG key named JanesKey. You would do the following:

// Returns whether or not the signature could be verified
bool VerifyJanesSignature(byte[] data, byte[] signature)
{
   ECDsaCng signingAlg = new ECDsaCng(CngKey.Open("JanesKey"));
   return signingAlg.VerifyData(data, signature);
}

The ECDsaCng class also lets you set different options when signing or verifying, mostly through properties on the class. For example, by default the ECDsaCng class uses the SHA-256 hashing algorithm during signing and verification. If you want to use a different algorithm, you simply change the HashAlgorithm property before signing. Let's say you choose to use SHA-512. The signing example for MyKey would now look like this:

// Returns the signature
byte[] SignMyData (byte[] data)
{
   ECDsaCng signingAlg = new ECDsaCng(CngKey.Open("MyKey"));
   signingAlg.HashAlgorithm = CngAlgorithm.Sha512;
   return signingAlg.SignData(data);
}

And the verification example for JanesKey would be this:

// Returns whether or not the signature could be verified
bool VerifyJanesSignature(byte[] data, byte[] signature)
{
   ECDsaCng signingAlg = new ECDsaCng(CngKey.Open("JanesKey"));
   signingAlg.HashAlgorithm = CngAlgorithm.Sha512;
   return signingAlg.VerifyData(data, signature);
}


ECDH

ECDH is a key exchange algorithm, sometimes referred to as a secret agreement algorithm. This algorithm is used to derive a secret key-often used for encryption or decryption with a symmetric algorithm-by exchanging a public key with another party. For example, say two users, Alice and Bob, want to derive a secret key. They both already have an elliptic curve key pair (both public and private keys). In order to derive a secret key using ECDH, they would perform the following steps:

  1. Alice sends her public key to Bob. He must be sure he's really getting the key from Alice and that the key has not been modified, but the key does not have to be sent confidentially.
  2. Bob sends his public key to Alice. Likewise, Alice must be absolutely sure that she's really getting the key from Bob and that the key has not been modified, but again the key does not have to be sent confidentially.
  3. Alice and Bob can now generate the same secret value, given that they each have the other party's public key and their own key pair. This secret value can then be used to generate a secret key for a symmetric algorithm.

The code for this is pretty simple. The following example generates a 256-bit key for Alice, assuming that her key pair is stored in a CNG key named MyKey:

// Returns a 256 bit secret key that is shared with the other party
bool Generate256BitKey(string otherParty)
{
   ECDiffieHellmanCng keyExchAlg =
      new ECDiffieHellmanCng(CngKey.Open("MyKey"));
   byte [] myPublicKey = keyExchAlg.PublicKey.ToByteArray();
   ... // send myPublicKey to other party
   byte[] otherPartysPublicKeyBytes = ...; // get other party's key
   ECDiffieHellmanCngPublicKey otherPartysPublicKey =
      ECDiffieHellmanCngPublicKey.FromByteArray(
         otherPartysPublicKeyBytes, CngKeyBlobFormat.EccPublicBlob);
   return keyExchAlg.DeriveKeyMaterial(otherPartysPublicKey);
}

Alice now has a 256-bit symmetric key that can be used with the other party (Bob) to encrypt and communicate confidential data. I'll stress again, however, that it's important to make sure you're really getting the genuine public key from the other party in a situation like the example above, not from an imposter. This typically requires some form of authentication.

Like the ECDsaCng class, the ECDiffieHellmanCng class used here can be customized through properties. For example, you can use different key derivation functions specifying all of the parameters for the key derivation functions using these properties.


Big Integer Support

Support for integers that can represent very large numbers is another customer request that we have implemented in the next version of the .NET Framework. Have you ever needed a really huge number, one that is so big that it just couldn't fit into any other base-type in the .NET Framework? Now you can use the new BigInteger type, which allows you to use integers of any arbitrary size, up to the limits of available memory. To begin, let's take a look at some scenarios in which you might need to use a really big number.

Astronomical calculations that involve distances in space require the ability to calculate extremely large numbers. Astronomers often calculate the distance in light-years in order to avoid using really big numbers. That's because a light-year is about 5,878,625,373,183.61 miles (or 9,460,730,472,580.8 kilometers) and so the actual number of miles between stars (not to mention feet or inches) is larger than what can be represented with 64 bits.

Big integers are also used in statistics and number theory. While not all mathematicians are necessarily working with integers of this size, consider the Law of Truly Large Numbers (which states that with a sample size large enough, any outrageous thing is likely to happen) and some of the writings by John Edensor Littlewood.

Furthermore, many cryptographic algorithms require the use of very large prime numbers. These numbers are much larger than can be represented by base types today.

The new BigInteger class is in the new System.Numeric namespace. It supports most of the operators you'd expect of a standard numeric type, such as addition (+), subtraction (-), and multiplication (*). The sample code in Figure 1 shows how to do a factorial computation using the BigInteger class. Figure 2 shows an example of the output if you enter 1000.

BigInteger supports many other mathematical operations through static methods on the class. These include:

We will be posting more information on using and extending the BigInteger class on the BCL Team's blog at blogs.msdn.com/bclteam.

We should note that there are currently some design trade-offs in BigInteger. It was very important to get this new numeric type into the .NET Framework for Visual Studio "Orcas." Moreover, it was important that this new base-type be available early enough for other green bits features to make use of it. So we decided for this release not to fully support all the printing, formatting, and parsing that the other numeric types support. Thus, only the decimal (D), general (G), and hexadecimal (X) formats are supported.

The BigInteger class is an example of a new base type that we expect many other library types to consume for specialized applications. The next type we'll cover is a new collection that we added due to popular demand: a set class.


High-Performance Sets

The new HashSet class is a high-performance generic collection in the System.Collections.Generic namespace. It is an unordered collection that contains unique elements. HashSet implements all the standard collection methods (such as Add, Remove, and Contains) and provides several set operations (including union, intersection, and symmetric difference).

The following sample code demonstrates the use of HashSet with integers:

HashSet<int> set1 = new 
    HashSet<int>();
set1.Add(1);
set1.Add(3);
set1.Add(5);
set1.Add(3); // set1 already contains 3; it isn't added twice
// set1 contains 1,3,5

HashSet<int> set2 = new HashSet<int>(new int[] { 2, 4, 6 });
// set2 contains 2,4,6

set2.UnionWith(set1);
// set2 contains 1,2,3,4,5,6

Notice how after adding four items (1, 3, 5, and 3), set1 ends up containing only three elements (1, 3, and 5). This behavior is by design. HashSet contains only unique elements. Once an item has been added to the set, subsequent attempts to add the same item will not succeed. The Add method actually returns a Boolean value indicating whether or not the item was successfully added to the set. The example above could have been rewritten as follows:

HashSet<int> set1 = new HashSet<int>();
bool added = set1.Add(1); // added is true
added = set1.Add(3); // added is true
added = set1.Add(5); // added is true
added = set1.Add(3); // added is false
// set1 contains 1,3,5

In the first example, set2 is initialized by passing in an array of ints ({ 2, 4, 6}) to the HashSet constructor, which takes a generic IEnumerable as a parameter. If there are duplicate elements in the IEnumerable, they are ignored when initializing the HashSet. For example, if set2 had been initialized with an array containing 2, 4, 2, and 6, the set would still end up containing only three elements (2, 4, and 6) since duplicates are ignored.

The set operations provided by HashSet (UnionWith, IntersectWith, ExceptWith, and SymmetricExceptWith) don't just take another HashSet object as a parameter-they actually take a generic IEnumerable. This means that the set operations can be used with any other collection. Figure 3 shows how the set operations can work with any collection that implements the generic IEnumerable interface. As with the constructor overload that takes an IEnumerable, duplicates are ignored. (The behavior of UnionWith, IntersectWith, ExceptWith, and SymmetricExceptWith is outlined in Figure 4.)

HashSet provides more operations than just the methods noted in the table. These include IsSubsetOf, IsProperSubsetOf, IsSupersetOf, and IsProperSupersetOf. With these, HashSet supports most of the mathematical operations that can typically be performed on sets.

As you can see, getting started using this new collection is quite simple. HashSet fits in nicely with our other generic collections and fills one of the last remaining holes in our collection APIs.


Pipes

The last classes we're going to look at in this column are the pipe classes. For Visual Studio "Orcas," we've added support for both anonymous and named pipes to the .NET Framework. Pipes are used to achieve interprocess communication (IPC) between two or more processes on the same machine or over a network. The new types, which can be found in the System.IO.Pipes namespace, expose nearly all the pipe functionality provided by Windows.

Anonymous pipes are used for communication between a parent process and a child process. These one-way pipes are unnamed and must be used locally on the same machine. Figure 5 shows the code for sending a string from a parent process to a child process.

Named pipes provide much more functionality than anonymous pipes. For starters, they are full duplex and can be used over a network. Named pipes support multiple server instances of a single name, message-based communication, asynchronous I/O, and impersonation. Figure 6 shows how to send two strings from one process to another process using a named pipe.

Named pipes also support message-based communication (demonstrated in Figure 7). This allows a reading process to read varying-length messages sent by the writing process. In Figure 7, two string messages are sent from a server process to a client process. The example includes two helper classes-MessageWriter and MessageReader-that do the actual work of writing and reading string messages to and from the underlying named pipe streams.

As you can see, the new pipe types are first-class managed citizens, making it easy to achieve IPC from within managed code. Anyone familiar with streams should have no trouble getting started using pipes.


Conclusion

The classes discussed in this column are a sampling of the new green bits functionality available in Visual Studio "Orcas." Download the latest CTP at msdn2.microsoft.com/en-us/vstudio/aa700831.aspx to give these types a test drive. And stop by the BCL Team's blog to let us know what you think.


Send your questions and comments to  clrinout@microsoft.com.



Mike Downen is a Program Manager focusing on security and deployment on the CLR team. He can be reached via his blog at blogs.msdn.com/CLRSecurity.


Inbar Gazit is a Program Manger focusing on the base class libraries for the CLR team. He can be reached via e-mail at inbar@microsoft.com.


Justin Van Patten is a Program Manager for the base class libraries within the CLR team. He can be reached via the BCL team blog at blogs.msdn.com/bclteam.


© 2007 Microsoft Corporation and CMP Media, LLC. All rights reserved; reproduction in part or in whole without permission is prohibited.