Astrogator
Astrogator

Reputation: 1061

Where does System.Security.Cryptography.RijndaelManaged..ctor() call come from (HASP-wrapped DLL)?

Some settings' values in our .NET-4 application are stored encrypted [in registry].  Initial code used AesManaged class for that (similar to this).  When 6 years ago we discovered that managed implementation is not FIPS-compliant, it was replaced by AesCryptoServiceProvider class.

We employ Thales / Gemalto / Sentinel / Alladin HASP "wrapping" for copy protection and licensing.  As a result, if/when exception happens in wrapped code, its stacktrace does not expose neither original object names nor line numbers, making it rather difficult to unravel - unless certain discipline is followed when writing original code (like e.g. making methods short and simple).  Encryption /decryption methods are located within one of HASP-wrapped libraries.

Everything was hunky-dori until recent wrapped build failed launching(!) in FIPS-enabled environment.  Even more surprise:  as I'm trying older wrapped builds (with FIPS enabled), they all fail.
Granted, this may be a result of QA team skipping these paths during usual validation (bad, but I'm not in charge of that), but here's an unexpected observation:  unwrapped code executes perfectly fine in the same FIPS-enabled OS!  Huh??

Now, even more bizzare is the stacktrace, written to Windows Event Log by my UnhandledExceptionEventHandler( ):

System.TypeInitializationException: The type initializer for 'XYZ.Main.Utils' threw an exception.
    ---> System.InvalidOperationException:
        This implementation is not part of the Windows Platform FIPS validated cryptographic algorithms.
    at System.Security.Cryptography.RijndaelManaged..ctor()
    at 150694719.150694754.714439608(String 146425350)
    at XYZ.Main.Utils..cctor()
    --- End of inner exception stack trace ---
    at XYZ.Main.Utils.SetModuleTitle(FileVersionInfo fvi)
    at XYZ.AppSuite.Program.Main(String[] saArg) in G:\DEV\XYZ\XYZ.AppSuite\Program.cs:line 316

This exception is very similar to one mentioned here, but indicated code does not even touch any encryption whatsoever:

/// <summary>Provides common and auxiliary objects and methods</summary>
public partial class    Utils
{
    /// ** Utils class is exposing global static methods and properties and does not have any constructors - at all! **
    ..

    /// <summary>Returns and sets <see cref="iBuild"/> and <see cref="dBuilt"/>, extracted from the version string (use on 'MM.NNN.*'-versioned assemblies)</summary>
    public static DateTime  GetBuildFromVersion( string sVersion )
    {
        Utils.sVersion =    sVersion;
        Utils.dBuilt =      new DateTime( 2000, 1, 1 );

        string[]    saVersion=  sVersion.Split( Utils.ccTokPeriod );

        if(  saVersion.Length == 4  )
        {
            Utils.iBuild =      Convert.ToInt32( saVersion[ 2 ], CultureInfo.InvariantCulture );
            int     iBuilt =    Convert.ToInt32( saVersion[ 3 ], CultureInfo.InvariantCulture );

            Utils.dBuilt =  Utils.dBuilt.AddDays( Utils.iBuild );
            Utils.dBuilt =  Utils.dBuilt.AddSeconds( iBuilt << 1 );

            if(  TimeZone.IsDaylightSavingTime( Utils.dBuilt, TimeZone.CurrentTimeZone.GetDaylightChanges( Utils.dBuilt.Year ) )  )
                Utils.dBuilt =  Utils.dBuilt.AddHours( 1 );
        }

        return  Utils.dBuilt;
    }

    /// <summary>Sets <see cref="Utils.sModInfo"/> and <see cref="Utils.sModTitle"/> strings, based on given assembly version data</summary>
    public static void      SetModuleTitle( FileVersionInfo fvi )
    {
        try
        {
            Utils.sMachine =    Dns.GetHostName( );
        }
        catch
        {
            Utils.sMachine =    Environment.MachineName;
        }

        Utils.sModInfo =    string.Format( Utils.scFmtModId, fvi.FileDescription, fvi.Comments, fvi.FileVersion, Utils.GetBuildFromVersion( fvi.FileVersion ) );
        Utils.sModTitle =   string.Format( Utils.scFmtModId1, fvi.FileDescription, fvi.Comments, fvi.FileVersion );
        Utils.sModStart =   string.Format( Utils.scFmtModId3, Utils.idModule, Utils.iBuild, Utils.sMachine );

        if(  Utils.bService  )
            Utils.sModTitle =   string.Format( Utils.scFmtModId4, Utils.idModule, Utils.iBuild );
    }
}

Is it possible, that HASP-wrapping invokes its own instance of System.Security.Cryptography.RijndaelManaged..ctor()? As much as I understand, AesCryptoServiceProvider class would certainly not call RijndaelManaged..ctor(), am I right?
Where does that call come from?

Upvotes: 0

Views: 107

Answers (1)

Corey
Corey

Reputation: 16584

I don't use HASP, so I can't give you a 100% answer here, but there are some standard clues that we can interpret.

The type initializer for 'XYZ.Main.Utils' threw an exception.

This type of error message occurs when the static initializer of a type - either a static class or a type with static members - throws an exception. Further supporting this is the following:

at XYZ.Main.Utils..cctor()

The cctor() member is the static constructor for a type, either an explicit one that you've written or an automatic static constructor created by the compiler to handle static member initialisation.

Following the trace back up the line we have a call to an obfuscated method 150694719.150694754.714439608() which attempts to construct an instance of System.Security.Cryptography.RijndaelManaged... which throws the InvalidOperationException.

What this says to me is that your HASP implementation is attempting to use RijndaelManaged to handle the decryption of the static data in your class. On a machine configured for FIPS compliance this will result in the InvalidOperationException you're seeing, since Rijndael is not a FIPS-compliant algorithm.

Your best option is to find an updated HASP implementation that is FIPS compliant.

Upvotes: 0

Related Questions