Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# stream reader ReadToEnd() missing last character

I am trying to decrypt a string in C# using AES:

public static string AesDecrypt(byte[] cipherText, byte[] Key, byte[] IV)
{
    string plaintext = null;

    // Create an Aes object with the specified key and IV
    using Aes aesAlg = Aes.Create();
    aesAlg.Padding = PaddingMode.Zeros;
    aesAlg.Key = Key;
    aesAlg.IV = IV;

    // Create a decryptor to perform the stream transform
    ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);

    // Create the streams used for decryption
    using MemoryStream msDecrypt = new MemoryStream(cipherText);
    using CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);
    using StreamReader srDecrypt = new StreamReader(csDecrypt);

    // Read the decrypted bytes from the decrypting stream and place them in a string
    plaintext = srDecrypt.ReadToEnd();
    return plaintext;
}

The encoded data is JSON, but when I decrypt it, I get all the right data except that the closing } of the JSON content is missing.

I think that the AES itself is not my problem here. I have doubts in the

plaintext = srDecrypt.ReadToEnd();

since only the last character is missing.

I don't know if I am supposed to flush any of the streams explicitly, but in any case it's a very curious problem.

Here's the full code for the encryption:

public static string AesEncrypt(string plainText, byte[] Key, byte[] IV)
{
    // Create an Aes object with the specified key and IV
    using Aes aesAlg = Aes.Create();
    aesAlg.Padding = PaddingMode.Zeros;
    aesAlg.Key = Key;
    aesAlg.IV = IV;

    // Create an encryptor to perform the stream transform
    ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

    // Create the streams used for encryption
    using MemoryStream msEncrypt = new MemoryStream();
    using CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
    using StreamWriter swEncrypt = new StreamWriter(csEncrypt);

    // Write all data to the stream
    swEncrypt.Write(plainText);
    swEncrypt.Flush();

    return Convert.ToBase64String(msEncrypt.ToArray());
}

And this is how I call the decryption method:

public static AuthenticationData ParseAuthenticationToken(string token)
{
    byte[] tokenBytes = Convert.FromBase64String(token);
    string json = AesEncryption.AesDecrypt(tokenBytes, aes.Key, aes.IV);
    return JsonConvert.DeserializeObject<AuthenticationData>(json);
}
like image 844
Eutherpy Avatar asked Mar 04 '23 02:03

Eutherpy


1 Answers

The problem is in your encryption code. Although you're calling seEncrypt.Flush(), you're not calling csEncrypt.FlushFinalBlock(). That automatically happens when the stream is disposed, but you're not doing that until after you've called msEncrypt.ToArray(). I would rewrite that code as:

MemoryStream msEncrypt = new MemoryStream();
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
    using StreamWriter swEncrypt = new StreamWriter(csEncrypt);
    swEncrypt.Write(plainText);
    // swEncrypt is disposed here, flushing it. Then csEncrypt is disposed,
    // flushing the final block.
}
return msEncrypt.ToArray();
like image 72
Jon Skeet Avatar answered Mar 10 '23 22:03

Jon Skeet