C# - Problem with AES Decryption - always get null












1















I am trying to implement image steganography with LSB and everything works except decrypting.



There is my class responsible for encryption and decryption of strings below. Encrypting works fine but Decrypt method always returns null:



using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace WindowsFormsApp1
{
class Encryptor {
//text to encrypt or already decrypted
private String decryptedText = "";
//text to decrypt or already encrypted
private String encryptedText = "";
private String key = "";

public Encryptor setDecryptedText(String text)
{
decryptedText = text;

return this;
}

public Encryptor setEncryptedText(String text)
{
encryptedText = text;

return this;
}
public Encryptor setKey(String text)
{
key = text;

return this;
}

Byte getHash(Byte hash)
{
Byte newHash = new Byte[32];
for (int i = 0; i < 32; i++)
{
newHash[i] = hash[i];
}

return newHash;
}

Byte getIV(Byte hash)
{
Byte newHash = new Byte[16];
int j = 0;
for (int i = 32; i < 48; i++)
{
newHash[j++] = hash[i];
}

return newHash;
}

String EncryptAesManaged()
{
SHA512 shaM = new SHA512Managed();

Byte data = Encoding.UTF8.GetBytes(key);
Byte hash = shaM.ComputeHash(data);

try
{
return Encrypt(decryptedText, getHash(hash), getIV(hash));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}

return null;
}

String DecryptAesManaged()
{
SHA512 shaM = new SHA512Managed();
var data = Encoding.UTF8.GetBytes(key);
Byte hash = shaM.ComputeHash(data);
try
{
return Decrypt(Convert.FromBase64String(encryptedText), getHash(hash), getIV(hash));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return "";
}

String Encrypt(string plainText, byte Key, byte IV)
{
Byte encrypted;
using (RijndaelManaged aes = new RijndaelManaged())
{
aes.Mode = CipherMode.CBC;
aes.BlockSize = 128;
aes.KeySize = 256;
ICryptoTransform encryptor = aes.CreateEncryptor(Key, IV);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter sw = new StreamWriter(cs)) {
sw.Write(Encoding.UTF8.GetBytes(plainText));
cs.FlushFinalBlock();
encrypted = ms.ToArray();
}
}
}
aes.Clear();
}

return Convert.ToBase64String(encrypted);
}
string Decrypt(byte cipherText, byte Key, byte IV)
{
string plaintext = null;
using (RijndaelManaged aes = new RijndaelManaged())
{
aes.Mode = CipherMode.CBC;
aes.BlockSize = 128;
aes.KeySize = 256;
ICryptoTransform decryptor = aes.CreateDecryptor(Key, IV);
try
{
using (MemoryStream ms = new MemoryStream(cipherText))
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
using (StreamReader reader = new StreamReader(cs))
{
plaintext = reader.ReadToEnd(); //Here get null
}

aes.Clear();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}

return plaintext;
}

public String getEncrypted()
{
return EncryptAesManaged();

}

public String getDecrypted()
{
return DecryptAesManaged();

}
}
}


Why is Decrypt() returning null rather than the originally encrypted string?










share|improve this question




















  • 1





    (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read), this should using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write)

    – kelalaka
    Nov 17 '18 at 16:10








  • 1





    @kelalaka - CryptoStreamMode.Read is the correct mode to use in Decrypt(), since the decryption method requires read access to a cryptographic stream.

    – dbc
    Nov 17 '18 at 17:05
















1















I am trying to implement image steganography with LSB and everything works except decrypting.



There is my class responsible for encryption and decryption of strings below. Encrypting works fine but Decrypt method always returns null:



using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace WindowsFormsApp1
{
class Encryptor {
//text to encrypt or already decrypted
private String decryptedText = "";
//text to decrypt or already encrypted
private String encryptedText = "";
private String key = "";

public Encryptor setDecryptedText(String text)
{
decryptedText = text;

return this;
}

public Encryptor setEncryptedText(String text)
{
encryptedText = text;

return this;
}
public Encryptor setKey(String text)
{
key = text;

return this;
}

Byte getHash(Byte hash)
{
Byte newHash = new Byte[32];
for (int i = 0; i < 32; i++)
{
newHash[i] = hash[i];
}

return newHash;
}

Byte getIV(Byte hash)
{
Byte newHash = new Byte[16];
int j = 0;
for (int i = 32; i < 48; i++)
{
newHash[j++] = hash[i];
}

return newHash;
}

String EncryptAesManaged()
{
SHA512 shaM = new SHA512Managed();

Byte data = Encoding.UTF8.GetBytes(key);
Byte hash = shaM.ComputeHash(data);

try
{
return Encrypt(decryptedText, getHash(hash), getIV(hash));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}

return null;
}

String DecryptAesManaged()
{
SHA512 shaM = new SHA512Managed();
var data = Encoding.UTF8.GetBytes(key);
Byte hash = shaM.ComputeHash(data);
try
{
return Decrypt(Convert.FromBase64String(encryptedText), getHash(hash), getIV(hash));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return "";
}

String Encrypt(string plainText, byte Key, byte IV)
{
Byte encrypted;
using (RijndaelManaged aes = new RijndaelManaged())
{
aes.Mode = CipherMode.CBC;
aes.BlockSize = 128;
aes.KeySize = 256;
ICryptoTransform encryptor = aes.CreateEncryptor(Key, IV);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter sw = new StreamWriter(cs)) {
sw.Write(Encoding.UTF8.GetBytes(plainText));
cs.FlushFinalBlock();
encrypted = ms.ToArray();
}
}
}
aes.Clear();
}

return Convert.ToBase64String(encrypted);
}
string Decrypt(byte cipherText, byte Key, byte IV)
{
string plaintext = null;
using (RijndaelManaged aes = new RijndaelManaged())
{
aes.Mode = CipherMode.CBC;
aes.BlockSize = 128;
aes.KeySize = 256;
ICryptoTransform decryptor = aes.CreateDecryptor(Key, IV);
try
{
using (MemoryStream ms = new MemoryStream(cipherText))
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
using (StreamReader reader = new StreamReader(cs))
{
plaintext = reader.ReadToEnd(); //Here get null
}

aes.Clear();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}

return plaintext;
}

public String getEncrypted()
{
return EncryptAesManaged();

}

public String getDecrypted()
{
return DecryptAesManaged();

}
}
}


Why is Decrypt() returning null rather than the originally encrypted string?










share|improve this question




















  • 1





    (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read), this should using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write)

    – kelalaka
    Nov 17 '18 at 16:10








  • 1





    @kelalaka - CryptoStreamMode.Read is the correct mode to use in Decrypt(), since the decryption method requires read access to a cryptographic stream.

    – dbc
    Nov 17 '18 at 17:05














1












1








1








I am trying to implement image steganography with LSB and everything works except decrypting.



There is my class responsible for encryption and decryption of strings below. Encrypting works fine but Decrypt method always returns null:



using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace WindowsFormsApp1
{
class Encryptor {
//text to encrypt or already decrypted
private String decryptedText = "";
//text to decrypt or already encrypted
private String encryptedText = "";
private String key = "";

public Encryptor setDecryptedText(String text)
{
decryptedText = text;

return this;
}

public Encryptor setEncryptedText(String text)
{
encryptedText = text;

return this;
}
public Encryptor setKey(String text)
{
key = text;

return this;
}

Byte getHash(Byte hash)
{
Byte newHash = new Byte[32];
for (int i = 0; i < 32; i++)
{
newHash[i] = hash[i];
}

return newHash;
}

Byte getIV(Byte hash)
{
Byte newHash = new Byte[16];
int j = 0;
for (int i = 32; i < 48; i++)
{
newHash[j++] = hash[i];
}

return newHash;
}

String EncryptAesManaged()
{
SHA512 shaM = new SHA512Managed();

Byte data = Encoding.UTF8.GetBytes(key);
Byte hash = shaM.ComputeHash(data);

try
{
return Encrypt(decryptedText, getHash(hash), getIV(hash));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}

return null;
}

String DecryptAesManaged()
{
SHA512 shaM = new SHA512Managed();
var data = Encoding.UTF8.GetBytes(key);
Byte hash = shaM.ComputeHash(data);
try
{
return Decrypt(Convert.FromBase64String(encryptedText), getHash(hash), getIV(hash));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return "";
}

String Encrypt(string plainText, byte Key, byte IV)
{
Byte encrypted;
using (RijndaelManaged aes = new RijndaelManaged())
{
aes.Mode = CipherMode.CBC;
aes.BlockSize = 128;
aes.KeySize = 256;
ICryptoTransform encryptor = aes.CreateEncryptor(Key, IV);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter sw = new StreamWriter(cs)) {
sw.Write(Encoding.UTF8.GetBytes(plainText));
cs.FlushFinalBlock();
encrypted = ms.ToArray();
}
}
}
aes.Clear();
}

return Convert.ToBase64String(encrypted);
}
string Decrypt(byte cipherText, byte Key, byte IV)
{
string plaintext = null;
using (RijndaelManaged aes = new RijndaelManaged())
{
aes.Mode = CipherMode.CBC;
aes.BlockSize = 128;
aes.KeySize = 256;
ICryptoTransform decryptor = aes.CreateDecryptor(Key, IV);
try
{
using (MemoryStream ms = new MemoryStream(cipherText))
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
using (StreamReader reader = new StreamReader(cs))
{
plaintext = reader.ReadToEnd(); //Here get null
}

aes.Clear();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}

return plaintext;
}

public String getEncrypted()
{
return EncryptAesManaged();

}

public String getDecrypted()
{
return DecryptAesManaged();

}
}
}


Why is Decrypt() returning null rather than the originally encrypted string?










share|improve this question
















I am trying to implement image steganography with LSB and everything works except decrypting.



There is my class responsible for encryption and decryption of strings below. Encrypting works fine but Decrypt method always returns null:



using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace WindowsFormsApp1
{
class Encryptor {
//text to encrypt or already decrypted
private String decryptedText = "";
//text to decrypt or already encrypted
private String encryptedText = "";
private String key = "";

public Encryptor setDecryptedText(String text)
{
decryptedText = text;

return this;
}

public Encryptor setEncryptedText(String text)
{
encryptedText = text;

return this;
}
public Encryptor setKey(String text)
{
key = text;

return this;
}

Byte getHash(Byte hash)
{
Byte newHash = new Byte[32];
for (int i = 0; i < 32; i++)
{
newHash[i] = hash[i];
}

return newHash;
}

Byte getIV(Byte hash)
{
Byte newHash = new Byte[16];
int j = 0;
for (int i = 32; i < 48; i++)
{
newHash[j++] = hash[i];
}

return newHash;
}

String EncryptAesManaged()
{
SHA512 shaM = new SHA512Managed();

Byte data = Encoding.UTF8.GetBytes(key);
Byte hash = shaM.ComputeHash(data);

try
{
return Encrypt(decryptedText, getHash(hash), getIV(hash));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}

return null;
}

String DecryptAesManaged()
{
SHA512 shaM = new SHA512Managed();
var data = Encoding.UTF8.GetBytes(key);
Byte hash = shaM.ComputeHash(data);
try
{
return Decrypt(Convert.FromBase64String(encryptedText), getHash(hash), getIV(hash));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return "";
}

String Encrypt(string plainText, byte Key, byte IV)
{
Byte encrypted;
using (RijndaelManaged aes = new RijndaelManaged())
{
aes.Mode = CipherMode.CBC;
aes.BlockSize = 128;
aes.KeySize = 256;
ICryptoTransform encryptor = aes.CreateEncryptor(Key, IV);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter sw = new StreamWriter(cs)) {
sw.Write(Encoding.UTF8.GetBytes(plainText));
cs.FlushFinalBlock();
encrypted = ms.ToArray();
}
}
}
aes.Clear();
}

return Convert.ToBase64String(encrypted);
}
string Decrypt(byte cipherText, byte Key, byte IV)
{
string plaintext = null;
using (RijndaelManaged aes = new RijndaelManaged())
{
aes.Mode = CipherMode.CBC;
aes.BlockSize = 128;
aes.KeySize = 256;
ICryptoTransform decryptor = aes.CreateDecryptor(Key, IV);
try
{
using (MemoryStream ms = new MemoryStream(cipherText))
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
using (StreamReader reader = new StreamReader(cs))
{
plaintext = reader.ReadToEnd(); //Here get null
}

aes.Clear();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}

return plaintext;
}

public String getEncrypted()
{
return EncryptAesManaged();

}

public String getDecrypted()
{
return DecryptAesManaged();

}
}
}


Why is Decrypt() returning null rather than the originally encrypted string?







c# encryption aes






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 17 '18 at 18:15









dbc

53.6k869122




53.6k869122










asked Nov 17 '18 at 15:04









mareckiDevmareckiDev

134




134








  • 1





    (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read), this should using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write)

    – kelalaka
    Nov 17 '18 at 16:10








  • 1





    @kelalaka - CryptoStreamMode.Read is the correct mode to use in Decrypt(), since the decryption method requires read access to a cryptographic stream.

    – dbc
    Nov 17 '18 at 17:05














  • 1





    (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read), this should using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write)

    – kelalaka
    Nov 17 '18 at 16:10








  • 1





    @kelalaka - CryptoStreamMode.Read is the correct mode to use in Decrypt(), since the decryption method requires read access to a cryptographic stream.

    – dbc
    Nov 17 '18 at 17:05








1




1





(CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read), this should using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write)

– kelalaka
Nov 17 '18 at 16:10







(CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read), this should using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write)

– kelalaka
Nov 17 '18 at 16:10






1




1





@kelalaka - CryptoStreamMode.Read is the correct mode to use in Decrypt(), since the decryption method requires read access to a cryptographic stream.

– dbc
Nov 17 '18 at 17:05





@kelalaka - CryptoStreamMode.Read is the correct mode to use in Decrypt(), since the decryption method requires read access to a cryptographic stream.

– dbc
Nov 17 '18 at 17:05












1 Answer
1






active

oldest

votes


















3














You don't show how you use your Encryptor class, so your question doesn't quite include a Minimal, Complete, and Verifiable example. I was able to reproduce the problem with the following test harness:



public static void Test()
{
var key = "my key";
var plainText = "hello";

var encryptor = new Encryptor();

encryptor.setDecryptedText(plainText);
encryptor.setKey(key);

var encrypted = encryptor.getEncrypted();

Console.WriteLine(encrypted);

var deecryptor = new Encryptor();

deecryptor.setEncryptedText(encrypted);
deecryptor.setKey(key);

var decrypted = deecryptor.getDecrypted();

Console.WriteLine(decrypted);

Assert.IsTrue(plainText == decrypted);
}


Demo fiddle #1 here.



Given that, your code has 2 problems, both of which are actually in encryption rather than decryption.



Firstly, in Encrypt(string plainText, byte Key, byte IV), you are writing to the StreamWriter sw, then flushing the CryptoStream and returning the MemoryStream contents -- but you never flush or dispose sw, so its buffered contents are never forwarded to the underlying stream(s).



To fix this, your code should looks something like:



using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter sw = new StreamWriter(cs))
{
sw.Write(Encoding.UTF8.GetBytes(plainText));
}
}
encrypted = ms.ToArray();
}


Now getDecrypted() no longer returns a null result -- but instead returns a wrong result of "System.Byte", as shown in demo fiddle #2 here.



Secondly, again in Encrypt(...), you are effectively encoding your plainText twice at this line:



sw.Write(Encoding.UTF8.GetBytes(plainText));


Encoding.UTF8.GetBytes(plainText) converts the plain text to a byte array, but the StreamWriter is also intended to do this job, converting strings to bytes and passing them to the underlying stream. So, since you are not passing a string to Write(), the overload that gets called is StreamWriter.Write(Object):




Writes the text representation of an object to the text string or stream by calling the ToString() method on that object.




Thus what actually gets encrypted is the ToString() value of a byte array, which is "System.Byte".



To fix this, simply remove the call to Encoding.UTF8.GetBytes(plainText) and write the string directly. Thus your Encrypt() method should now look like:



static String Encrypt(string plainText, byte Key, byte IV)
{
string encrypted;
using (var aes = new RijndaelManaged())
{
aes.Mode = CipherMode.CBC;
aes.BlockSize = 128;
aes.KeySize = 256;
ICryptoTransform encryptor = aes.CreateEncryptor(Key, IV);
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write, true))
{
using (var sw = new StreamWriter(cs))
{
sw.Write(plainText);
}
}
// Calling GetBuffer() avoids the extra allocation of ToArray().
encrypted = Convert.ToBase64String(ms.GetBuffer(), 0, checked((int)ms.Length));
}
aes.Clear();
}

return encrypted;
}


Demo fiddle #3 here that now passes successfully.



Disclaimer: this answer does not attempt to to review your code for security best practices such as secure setup of salt and IV.






share|improve this answer

























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53352441%2fc-sharp-problem-with-aes-decryption-always-get-null%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    3














    You don't show how you use your Encryptor class, so your question doesn't quite include a Minimal, Complete, and Verifiable example. I was able to reproduce the problem with the following test harness:



    public static void Test()
    {
    var key = "my key";
    var plainText = "hello";

    var encryptor = new Encryptor();

    encryptor.setDecryptedText(plainText);
    encryptor.setKey(key);

    var encrypted = encryptor.getEncrypted();

    Console.WriteLine(encrypted);

    var deecryptor = new Encryptor();

    deecryptor.setEncryptedText(encrypted);
    deecryptor.setKey(key);

    var decrypted = deecryptor.getDecrypted();

    Console.WriteLine(decrypted);

    Assert.IsTrue(plainText == decrypted);
    }


    Demo fiddle #1 here.



    Given that, your code has 2 problems, both of which are actually in encryption rather than decryption.



    Firstly, in Encrypt(string plainText, byte Key, byte IV), you are writing to the StreamWriter sw, then flushing the CryptoStream and returning the MemoryStream contents -- but you never flush or dispose sw, so its buffered contents are never forwarded to the underlying stream(s).



    To fix this, your code should looks something like:



    using (MemoryStream ms = new MemoryStream())
    {
    using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
    {
    using (StreamWriter sw = new StreamWriter(cs))
    {
    sw.Write(Encoding.UTF8.GetBytes(plainText));
    }
    }
    encrypted = ms.ToArray();
    }


    Now getDecrypted() no longer returns a null result -- but instead returns a wrong result of "System.Byte", as shown in demo fiddle #2 here.



    Secondly, again in Encrypt(...), you are effectively encoding your plainText twice at this line:



    sw.Write(Encoding.UTF8.GetBytes(plainText));


    Encoding.UTF8.GetBytes(plainText) converts the plain text to a byte array, but the StreamWriter is also intended to do this job, converting strings to bytes and passing them to the underlying stream. So, since you are not passing a string to Write(), the overload that gets called is StreamWriter.Write(Object):




    Writes the text representation of an object to the text string or stream by calling the ToString() method on that object.




    Thus what actually gets encrypted is the ToString() value of a byte array, which is "System.Byte".



    To fix this, simply remove the call to Encoding.UTF8.GetBytes(plainText) and write the string directly. Thus your Encrypt() method should now look like:



    static String Encrypt(string plainText, byte Key, byte IV)
    {
    string encrypted;
    using (var aes = new RijndaelManaged())
    {
    aes.Mode = CipherMode.CBC;
    aes.BlockSize = 128;
    aes.KeySize = 256;
    ICryptoTransform encryptor = aes.CreateEncryptor(Key, IV);
    using (var ms = new MemoryStream())
    {
    using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write, true))
    {
    using (var sw = new StreamWriter(cs))
    {
    sw.Write(plainText);
    }
    }
    // Calling GetBuffer() avoids the extra allocation of ToArray().
    encrypted = Convert.ToBase64String(ms.GetBuffer(), 0, checked((int)ms.Length));
    }
    aes.Clear();
    }

    return encrypted;
    }


    Demo fiddle #3 here that now passes successfully.



    Disclaimer: this answer does not attempt to to review your code for security best practices such as secure setup of salt and IV.






    share|improve this answer






























      3














      You don't show how you use your Encryptor class, so your question doesn't quite include a Minimal, Complete, and Verifiable example. I was able to reproduce the problem with the following test harness:



      public static void Test()
      {
      var key = "my key";
      var plainText = "hello";

      var encryptor = new Encryptor();

      encryptor.setDecryptedText(plainText);
      encryptor.setKey(key);

      var encrypted = encryptor.getEncrypted();

      Console.WriteLine(encrypted);

      var deecryptor = new Encryptor();

      deecryptor.setEncryptedText(encrypted);
      deecryptor.setKey(key);

      var decrypted = deecryptor.getDecrypted();

      Console.WriteLine(decrypted);

      Assert.IsTrue(plainText == decrypted);
      }


      Demo fiddle #1 here.



      Given that, your code has 2 problems, both of which are actually in encryption rather than decryption.



      Firstly, in Encrypt(string plainText, byte Key, byte IV), you are writing to the StreamWriter sw, then flushing the CryptoStream and returning the MemoryStream contents -- but you never flush or dispose sw, so its buffered contents are never forwarded to the underlying stream(s).



      To fix this, your code should looks something like:



      using (MemoryStream ms = new MemoryStream())
      {
      using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
      {
      using (StreamWriter sw = new StreamWriter(cs))
      {
      sw.Write(Encoding.UTF8.GetBytes(plainText));
      }
      }
      encrypted = ms.ToArray();
      }


      Now getDecrypted() no longer returns a null result -- but instead returns a wrong result of "System.Byte", as shown in demo fiddle #2 here.



      Secondly, again in Encrypt(...), you are effectively encoding your plainText twice at this line:



      sw.Write(Encoding.UTF8.GetBytes(plainText));


      Encoding.UTF8.GetBytes(plainText) converts the plain text to a byte array, but the StreamWriter is also intended to do this job, converting strings to bytes and passing them to the underlying stream. So, since you are not passing a string to Write(), the overload that gets called is StreamWriter.Write(Object):




      Writes the text representation of an object to the text string or stream by calling the ToString() method on that object.




      Thus what actually gets encrypted is the ToString() value of a byte array, which is "System.Byte".



      To fix this, simply remove the call to Encoding.UTF8.GetBytes(plainText) and write the string directly. Thus your Encrypt() method should now look like:



      static String Encrypt(string plainText, byte Key, byte IV)
      {
      string encrypted;
      using (var aes = new RijndaelManaged())
      {
      aes.Mode = CipherMode.CBC;
      aes.BlockSize = 128;
      aes.KeySize = 256;
      ICryptoTransform encryptor = aes.CreateEncryptor(Key, IV);
      using (var ms = new MemoryStream())
      {
      using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write, true))
      {
      using (var sw = new StreamWriter(cs))
      {
      sw.Write(plainText);
      }
      }
      // Calling GetBuffer() avoids the extra allocation of ToArray().
      encrypted = Convert.ToBase64String(ms.GetBuffer(), 0, checked((int)ms.Length));
      }
      aes.Clear();
      }

      return encrypted;
      }


      Demo fiddle #3 here that now passes successfully.



      Disclaimer: this answer does not attempt to to review your code for security best practices such as secure setup of salt and IV.






      share|improve this answer




























        3












        3








        3







        You don't show how you use your Encryptor class, so your question doesn't quite include a Minimal, Complete, and Verifiable example. I was able to reproduce the problem with the following test harness:



        public static void Test()
        {
        var key = "my key";
        var plainText = "hello";

        var encryptor = new Encryptor();

        encryptor.setDecryptedText(plainText);
        encryptor.setKey(key);

        var encrypted = encryptor.getEncrypted();

        Console.WriteLine(encrypted);

        var deecryptor = new Encryptor();

        deecryptor.setEncryptedText(encrypted);
        deecryptor.setKey(key);

        var decrypted = deecryptor.getDecrypted();

        Console.WriteLine(decrypted);

        Assert.IsTrue(plainText == decrypted);
        }


        Demo fiddle #1 here.



        Given that, your code has 2 problems, both of which are actually in encryption rather than decryption.



        Firstly, in Encrypt(string plainText, byte Key, byte IV), you are writing to the StreamWriter sw, then flushing the CryptoStream and returning the MemoryStream contents -- but you never flush or dispose sw, so its buffered contents are never forwarded to the underlying stream(s).



        To fix this, your code should looks something like:



        using (MemoryStream ms = new MemoryStream())
        {
        using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
        {
        using (StreamWriter sw = new StreamWriter(cs))
        {
        sw.Write(Encoding.UTF8.GetBytes(plainText));
        }
        }
        encrypted = ms.ToArray();
        }


        Now getDecrypted() no longer returns a null result -- but instead returns a wrong result of "System.Byte", as shown in demo fiddle #2 here.



        Secondly, again in Encrypt(...), you are effectively encoding your plainText twice at this line:



        sw.Write(Encoding.UTF8.GetBytes(plainText));


        Encoding.UTF8.GetBytes(plainText) converts the plain text to a byte array, but the StreamWriter is also intended to do this job, converting strings to bytes and passing them to the underlying stream. So, since you are not passing a string to Write(), the overload that gets called is StreamWriter.Write(Object):




        Writes the text representation of an object to the text string or stream by calling the ToString() method on that object.




        Thus what actually gets encrypted is the ToString() value of a byte array, which is "System.Byte".



        To fix this, simply remove the call to Encoding.UTF8.GetBytes(plainText) and write the string directly. Thus your Encrypt() method should now look like:



        static String Encrypt(string plainText, byte Key, byte IV)
        {
        string encrypted;
        using (var aes = new RijndaelManaged())
        {
        aes.Mode = CipherMode.CBC;
        aes.BlockSize = 128;
        aes.KeySize = 256;
        ICryptoTransform encryptor = aes.CreateEncryptor(Key, IV);
        using (var ms = new MemoryStream())
        {
        using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write, true))
        {
        using (var sw = new StreamWriter(cs))
        {
        sw.Write(plainText);
        }
        }
        // Calling GetBuffer() avoids the extra allocation of ToArray().
        encrypted = Convert.ToBase64String(ms.GetBuffer(), 0, checked((int)ms.Length));
        }
        aes.Clear();
        }

        return encrypted;
        }


        Demo fiddle #3 here that now passes successfully.



        Disclaimer: this answer does not attempt to to review your code for security best practices such as secure setup of salt and IV.






        share|improve this answer















        You don't show how you use your Encryptor class, so your question doesn't quite include a Minimal, Complete, and Verifiable example. I was able to reproduce the problem with the following test harness:



        public static void Test()
        {
        var key = "my key";
        var plainText = "hello";

        var encryptor = new Encryptor();

        encryptor.setDecryptedText(plainText);
        encryptor.setKey(key);

        var encrypted = encryptor.getEncrypted();

        Console.WriteLine(encrypted);

        var deecryptor = new Encryptor();

        deecryptor.setEncryptedText(encrypted);
        deecryptor.setKey(key);

        var decrypted = deecryptor.getDecrypted();

        Console.WriteLine(decrypted);

        Assert.IsTrue(plainText == decrypted);
        }


        Demo fiddle #1 here.



        Given that, your code has 2 problems, both of which are actually in encryption rather than decryption.



        Firstly, in Encrypt(string plainText, byte Key, byte IV), you are writing to the StreamWriter sw, then flushing the CryptoStream and returning the MemoryStream contents -- but you never flush or dispose sw, so its buffered contents are never forwarded to the underlying stream(s).



        To fix this, your code should looks something like:



        using (MemoryStream ms = new MemoryStream())
        {
        using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
        {
        using (StreamWriter sw = new StreamWriter(cs))
        {
        sw.Write(Encoding.UTF8.GetBytes(plainText));
        }
        }
        encrypted = ms.ToArray();
        }


        Now getDecrypted() no longer returns a null result -- but instead returns a wrong result of "System.Byte", as shown in demo fiddle #2 here.



        Secondly, again in Encrypt(...), you are effectively encoding your plainText twice at this line:



        sw.Write(Encoding.UTF8.GetBytes(plainText));


        Encoding.UTF8.GetBytes(plainText) converts the plain text to a byte array, but the StreamWriter is also intended to do this job, converting strings to bytes and passing them to the underlying stream. So, since you are not passing a string to Write(), the overload that gets called is StreamWriter.Write(Object):




        Writes the text representation of an object to the text string or stream by calling the ToString() method on that object.




        Thus what actually gets encrypted is the ToString() value of a byte array, which is "System.Byte".



        To fix this, simply remove the call to Encoding.UTF8.GetBytes(plainText) and write the string directly. Thus your Encrypt() method should now look like:



        static String Encrypt(string plainText, byte Key, byte IV)
        {
        string encrypted;
        using (var aes = new RijndaelManaged())
        {
        aes.Mode = CipherMode.CBC;
        aes.BlockSize = 128;
        aes.KeySize = 256;
        ICryptoTransform encryptor = aes.CreateEncryptor(Key, IV);
        using (var ms = new MemoryStream())
        {
        using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write, true))
        {
        using (var sw = new StreamWriter(cs))
        {
        sw.Write(plainText);
        }
        }
        // Calling GetBuffer() avoids the extra allocation of ToArray().
        encrypted = Convert.ToBase64String(ms.GetBuffer(), 0, checked((int)ms.Length));
        }
        aes.Clear();
        }

        return encrypted;
        }


        Demo fiddle #3 here that now passes successfully.



        Disclaimer: this answer does not attempt to to review your code for security best practices such as secure setup of salt and IV.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 19 '18 at 21:57

























        answered Nov 17 '18 at 16:56









        dbcdbc

        53.6k869122




        53.6k869122






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53352441%2fc-sharp-problem-with-aes-decryption-always-get-null%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Can a sorcerer learn a 5th-level spell early by creating spell slots using the Font of Magic feature?

            Does disintegrating a polymorphed enemy still kill it after the 2018 errata?

            A Topological Invariant for $pi_3(U(n))$