Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / XML

RFC3394 Key-wrapping Algorithm in C#

4.80/5 (9 votes)
31 Oct 2008Public Domain3 min read 1   1.7K  
An implementation of the RFC3394 AES key-wrapping algorithm.

Introduction

This article presents a C# implementation of the RFC3394 key-wrapping algorithm. The attached assembly provides two simple operations: one to wrap key data, and another to unwrap the key data. This code also includes a fairly comprehensive unit test library which, among other things, ensures that the implementation is verified against the test vectors provided in RFC3394.

Background

Key wrapping is the process of encapsulating one or more encryption keys using a cryptographic algorithm in concert with a key-encryption key. Additional general information on key wrapping is available at Wikipedia.

RFC3394 specifies a symmetric key encapsulation algorithm also known as the AES Key Wrap Specification. As stated in the RFC, it was designed with the following goal in mind:

Design a cryptographic algorithm called a Key Wrap that uses the Advanced Encryption Standard (AES) as a primitive to securely encrypt plaintext key(s) with any associated integrity information and data, such that the combination could be longer than the width of the AES block size (128-bits). Each ciphertext bit should be a highly non-linear function of each plaintext bit, and (when unwrapping) each plaintext bit should be a highly non-linear function of each ciphertext bit. It is sufficient to approximate an ideal pseudorandom permutation to the degree that exploitation of undesirable phenomena is as unlikely as guessing the AES engine key.

This algorithm involves a small number of iterations, over which an AES operation, an XOR operation, and a bit of rotation alter the input. The following picture from Wikipedia illustrates the process nicely:

RFC3394 Algorithm

Note that this standard specifically requires AES as the encapsulation mechanism and, therefore, a valid AES key as the key-encryption key.

Documentation

The attached assembly contains only one public class, KeyWrapAlgorithm. This class has the following members:

Static methods
  • public static byte[] WrapKey(byte[] kek, byte[] plaintext)
  • public static byte[] UnwrapKey(byte[] kek, byte[] ciphertext)

These methods are the primary interface to the class. WrapKey performs, in a single call, the full key-wrapping operation, while UnwrapKey, as one might expect, performs the full key-unwrapping operation.

Argument information:

  • kek - the key-encryption key, a valid AES key of either 128, 192, or 256 bits.
  • plaintext, ciphertext - the key data to encapsulate or unencapsulate. As specified in the RFC, this must be made up of n 64-bit blocks, where n is at least 2.

Returns:

Encapsulated or unencapsulated key data depending on whether we are calling WrapKey or UnwrapKey, respectively.

Constructor
C#
public KeyWrapAlgorithm(byte[] kek)

Constructing a KeyWrapAlgorithm class is not usually necessary, but the object will store a key-encryption key in case we are, for example, performing many key wrap operations with the same key.

Argument information:

  • kek - the key-encryption key, a valid AES key of either 128, 192, or 256 bits.
Non-static methods
  • public byte[] WrapKey(byte[] plaintext)
  • public byte[] UnwrapKey(byte[] ciphertext)

These methods are alternatives to the static methods, above. The calls perform key-wrapping operations using the key specified during construction.

Argument information:

  • plaintext, ciphertext - the key data to encapsulate or unencapsulate. As specified in the RFC, this must be made up of n 64-bit blocks, where n is at least 2.

Returns:

Encapsulated or unencapsulated key data depending on whether we are calling WrapKey or UnwrapKey, respectively.

Examples

Using the class is straightforward, as most users will only ever need two lines of code. In the unit tests, I created quick methods to convert from the hex strings present in the RFC test vectors to byte[] for easy consumption by the RFC3394 library.

C#
private void StaticWrap(string kek, string pt, string ct, string test)
{
   // Convert hex strings to byte[]s.
   byte[] key = SoapHexBinary.Parse(kek).Value;
   byte[] input = SoapHexBinary.Parse(pt).Value;

   // Static call to the RFC3394 library is here.
   byte[] output = KeyWrapAlgorithm.WrapKey(key, input);

   // Verify the test passes.
   Assert.AreEqual(ct, new SoapHexBinary(output).ToString(), test);
}

[Test]
public void Wrap_128key_128kek_Static()
{
   // Test vectors from RFC3394.
   string kek = "000102030405060708090A0B0C0D0E0F";
   string pt = "00112233445566778899AABBCCDDEEFF";
   string ct = "1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5";

   // Call the above method to perform the key wrap.
   StaticWrap(kek, pt, ct, "Wrap_128key_128kek_Static");
}

Using UnwrapKey works, of course, very similarly.

(Note the use of SoapHexBinary to convert hex strings to byte[]s. You can find this handy class in the unfortunately named System.Runtime.Remoting.Metadata.W3cXsd2001 namespace.)

History

  • 2008, October 31: Initial release.

License

This article, along with any associated source code and files, is licensed under A Public Domain dedication