1

A few years ago I wrote a simple wrapper based on MSDN - AesManaged Class code, to obscure values saved in registry (simply to prevent manual tampering with these, nothing more):

public static string    Encrypt( string s, byte[] key, byte[] iv )
{
    byte[]  enc;

    using(  AesManaged aes =    new AesManaged( )  )
    {
        ICryptoTransform    ict =   aes.CreateEncryptor( key, iv );

        using(  MemoryStream ms= new MemoryStream( )  )
        using(  CryptoStream cs= new CryptoStream( ms, ict, CryptoStreamMode.Write )  )
        using(  StreamWriter sw= new StreamWriter( cs )  )
        {
            sw.Write( s );      enc =   ms.ToArray( );
        }
    }
    return  Convert.ToBase64String( enc );
}

public static string    Decrypt( string p, byte[] key, byte[] iv )
{
    string  s=  null;

    using(  AesManaged aes =    new AesManaged( )  )
    {
        ICryptoTransform    ict =   aes.CreateDecryptor( key, iv );

        using(  MemoryStream ms= new MemoryStream( Convert.FromBase64String( p ) )  )
        using(  CryptoStream cs= new CryptoStream( ms, ict, CryptoStreamMode.Read )  )
        using(  StreamReader sr= new StreamReader( cs )  )
        {
            s=  sr.ReadToEnd( );
        }
    }
    return  s;
}

These methods worked perfectly all this time .. until yesterday, when Encrypt produced a null result on a valid string. Changing key and iv does not make any difference. Tried executing on several machines - same result. No exceptions are thrown. However, decryption still works fine!

Why does Encrypt( ) suddenly fail? Is there some Windows Update that changed the play-field?

Astrogator
  • 1,041
  • 11
  • 27
  • 1
    You need to call the `FlushFinalBlock` method of cryptostream prior to calling `ms.ToArray()`. It doesn't matter if it used to work because if you did it this way it was always wrong. You were just lucky before, now you're not so lucky. – President James K. Polk Apr 22 '15 at 23:02
  • Thank you @GregS! Only did it this way 'cause MSDN page doesn't even mention that method. Indeed, after adding that call `ms` now has a value (=> so does `enc`). But then `Decrypt( )` does not reverse it back to original string?! Is there smth missing too? And in general, is it possible to be *that lucky* for 3 years without a single issue? I still want to find out the exact root cause, any ideas? – Astrogator Apr 23 '15 at 15:57
  • Wait a sec, upon closer examination now (i.e. with added call `cs.FlushFinalBlock( );`) value returned by `Encrypt(..)` is the same for any input, provided key and iv are same. As soon as i change either key or iv, result changes! But it ignores the input!? Also, length of the encrypted result was somewhat proportional to length of the input, now it is 24 chars exactly and doesn't change.. What is going on? – Astrogator Apr 23 '15 at 16:32

1 Answers1

3

After finding and studying several similar questions (Aes decryptor gives empty string; Using AES encryption in .NET - CryptographicException saying the padding is invalid and cannot be removed; “Padding is invalid and cannot be removed” using AesManaged; Padding is invalid and cannot be removed Exception while decrypting string using “AesManaged” C#) and looking at my code again, I noticed the difference with MSDN sample. Indeed, i made an optimization and that is, what broke the execution! The code must be spelled this way:

public static string    Encrypt( string s, byte[] key, byte[] iv )
{
    byte[]  enc;

    using(  AesManaged aes =    new AesManaged( )  )
    {
        ICryptoTransform    ict =   aes.CreateEncryptor( key, iv );

        using(  MemoryStream ms= new MemoryStream( )  )
        {
            using(  CryptoStream cs= new CryptoStream( ms, ict, CryptoStreamMode.Write ) )
            {
                using(  StreamWriter sw= new StreamWriter( cs )  )
                {
                    sw.Write( s );
                }
            }
            enc =   ms.ToArray( );
        }
    }

    return  Convert.ToBase64String( enc );
}

Notice the presence of curly braces after each using(..)! Yes, that means the CryptoStream is closed - and therefore flushed - before i attempt to use the buffer, making this approach safe.

No idea, why solution by @GregS and @HansPassant did not do it, but since the code works now (reverted to original version :), my issue is closed. Thank god for version control! :))

Thank you guys for guiding me to the solution!

Community
  • 1
  • 1
Astrogator
  • 1,041
  • 11
  • 27