Please do not use the .NET 2.0 HMACSHA512 and HMACSHA384 Classes

 

We’ve recently discovered a bug in the HMACSHA512 and HMACSHA384 classes which shipped in the .NET Framework 2.0.  This bug will cause these algorithms to produce incorrect results which are not consistent with other implementations of HMAC-SHA-512 and HMAC-SHA-384.  Unfortunately, we did not discover this bug until recently, and the shipping .NET Framework 2.0 on all platforms is affected by it.  The only two affected algorithms are the HMAC-SHA-512 and HMAC-SHA-384; other HMAC algorithms do produce correct values.

The next service pack to the .NET Framework will contain a fix for this bug, which will cause the HMACSHA384 and HMACSHA512 classes to produce correct HMAC values.  However, this will cause their output to be inconsistent with the output of the unserviced .NET Framework 2.0 classes.  In order to allow applications running on serviced framework to interact with applications running on the unserviced version, we will introduce two compatibility switches in the service pack.

First, both the HMACSHA512 and HMACSHA384 classes will have a new Boolean property, ProduceLegacyHmacValues.  By setting this property to true, the object will produce values which match what the unserviced .NET Framework would have produced.  You should set this property only once after you’ve created your HMAC object, and you will need to reset your key afterwards:

    public static void Test()

    {

        HMACSHA512 hmac = new HMACSHA512();

        hmac.ProduceLegacyHmacValues = true;

        hmac.Key = // ... get the hmac key

 

        // ...

        // use the hmac algorithm

        // ...

    }

 

In order to help applications where it is expensive or impossible to change the code, we’ve added a new configuration switch for the application’s .exe.config file which will cause all HMAC objects created within the application to use the unserviced calculation.

<configuration>

    <runtime>

        <legacyHMACMode enabled="1" />

    </runtime>

</configuration>

 

Finally, in order to help debug any issues that arise when upgrading to the service pack, the first time an instance of either class is created, we will log a warning message to the event log and to any attached debugger.  The message text (which will hopefully help to point search engine results here as well) will be:

"This application is using the HMAC-SHA-384 or HMAC-SHA-512 keyed hash algorithm. The implementation of these algorithms were updated in service pack 1 of .NET Framework 2.0 and by default do not produce results consistent with the unserviced versions of the classes. For more information about the changes to the algorithms and how to disable this warning message please see the release notes for service pack 1."

 

This warning will only be produced the first time an instance of either object is created in a process.  If the configuration switch to enable process-wide legacy mode is set, then we will suppress the message.  We’ve also provided a second configuration switch which will let you manually suppress the warning message for your application.

<configuration>

    <runtime>

        <legacyHMACWarning enabled="0" />

    </runtime>

</configuration>

 

If you need a replacement class for HMACSHA512 before the next service pack ships, then you can roll your own relatively easily.  Some code to do this would look like this:

internal sealed class MyHmacSha512 : System.Security.Cryptography.HMAC

{

    public MyHmacSha512(byte[] key)

    {

        if (key == null)

            throw new ArgumentNullException("key");

 

        HashName = "SHA512";

        HashSizeValue = 512;

        BlockSizeValue = 128;

        Key = key;

    }

}

 

Similarly, a substitute class can be derived for HMACSHA384:

internal sealed class MyHmacSha384 : System.Security.Cryptography.HMAC

{

    public MyHmacSha384(byte[] key)

    {

        if (key == null)

            throw new ArgumentNullException("key");

 

        HashName = "SHA384";

        HashSizeValue = 384;

        BlockSizeValue = 128;

        Key = key;

    }

}

 

This change will start to appear in future CTPs.  Again, I personally, and the CLR security team in general, are very sorry for any problems this may have caused in your applications.  Please feel free to ask any questions in the comments for this post, and I’ll make sure that they get answered as soon as possible.