0

I am trying to encrypt and decrypt a string, and I can do it successfully. After that, I convert the encrypted byte[] to string to save in the database.

But when I try to convert the string back to byte[] again, my code throws an error.

To test the code I created a string variable to save the string encrypted.

the print error

How do I convert again the string back to byte[] successfully?

static void Main(string[] args)
{
    Console.WriteLine("Enter text that needs to be encrypted..");
    string data = Console.ReadLine();
    EncryptAesManaged(data);
    Console.ReadLine();
}

static void EncryptAesManaged(string raw)
{
    string EncryptionKey = "sruohfaymonerishfiahbihbgrG546";
    byte[] clearBytes = System.Text.Encoding.Unicode.GetBytes(raw);

    try
    {
        using (AesManaged aes = new AesManaged())
        {
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
            var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(EncryptionKey);

            aes.Key = pdb.GetBytes(32);
            aes.IV = pdb.GetBytes(16);
            // Encrypt string    
            byte[] encrypted = Encrypt(raw, aes.Key, aes.IV);

            // Print encrypted string    
            string passe = System.Text.Encoding.UTF8.GetString(encrypted);
            Console.WriteLine($"Encrypt:{passe}");
            Console.WriteLine(System.Text.Encoding.UTF8.GetBytes(passe));

            // Decrypt the bytes to a string.    
            string decrypted = Decrypt(System.Text.Encoding.UTF8.GetBytes(passe), aes.Key, aes.IV);
            // Print decrypted string. It should be same as raw data    
            Console.WriteLine($"Decrypted data: {decrypted}");
        }
    }
    catch (Exception exp)
    {
        Console.WriteLine(exp.Message);
    }

    Console.ReadKey();
}

static byte[] Encrypt(String plainText, byte[] Key, byte[] IV)
{
    byte[] encrypted;

    using (AesManaged aes = new AesManaged())
    {
        // Create encryptor    
        ICryptoTransform encryptor = aes.CreateEncryptor(Key, IV);

        // Create MemoryStream    
        using (MemoryStream ms = new MemoryStream())
        {
            // Create crypto stream using the CryptoStream class. This class is the key to encryption    
            // and encrypts and decrypts data from any given stream. In this case, we will pass a memory stream    
            // to encrypt    
            using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
            {
                // Create StreamWriter and write data to a stream    
                using (StreamWriter sw = new StreamWriter(cs))
                    sw.Write(plainText);

                encrypted = ms.ToArray();
            }
        }
    }

    return encrypted;
}

static string Decrypt(byte[] cipherText, byte[] Key, byte[] IV)
{
    string plaintext = null;
    // Create AesManaged    
    using (AesManaged aes = new AesManaged())
    {
        // Create a decryptor    
        ICryptoTransform decryptor = aes.CreateDecryptor(Key, IV);

        // Create the streams used for decryption.    
        using (MemoryStream ms = new MemoryStream(cipherText))
        {
            // Create crypto stream    
            using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
            {
                // Read crypto stream    
                using (StreamReader reader = new StreamReader(cs))
                    plaintext = reader.ReadToEnd();
            }
        }
    }

    return plaintext;
}
Hernani
  • 23
  • 1
  • 7
  • 2
    *throws an error* If you don't tell us what the error is, how can we possibly help? – DavidG Jul 02 '19 at 11:28
  • 4
    **Do not** use `Encoding....GetString` to convert a byte array to a string unless you know the bytes came from the paired `Encoding...GetBytes`, you can **not** convert an arbitrary array of bytes to a string this way. This is a sure way to corrupt the string. Instead, using `Convert.ToBase64String` and its sibling, `Convert.FromBase64String` to get a string representation of a byte array in Base64 format. – Lasse V. Karlsen Jul 02 '19 at 11:33
  • @DavidG ok, sorry I've already updated it. – Hernani Jul 02 '19 at 11:33
  • Don't post images of code and/or exceptions, put the text into the question. – DavidG Jul 02 '19 at 11:34
  • Possible duplicate of [AES encryption error: The input data is not a complete block?](https://stackoverflow.com/questions/19614178/aes-encryption-error-the-input-data-is-not-a-complete-block) – Kzryzstof Jul 02 '19 at 11:37
  • @LasseVågsætherKarlsen You are the man. you solved it! Thank you – Hernani Jul 02 '19 at 11:38
  • I'll leave my comment above but one part is inaccurate, you haven't "corrupted the string", instead what you have is a lossy translation from an arbitrary byte array to a string. If you then use the companion GetBytes on that string, you will not get back the original sequence of bytes, that is what I meant. The string, however, will probably be an OK string, as strings go, it will just not be an accurate representation of the byte array. – Lasse V. Karlsen Jul 02 '19 at 11:40

1 Answers1

3

The problem is right here:

string passe = System.Text.Encoding.UTF8.GetString(encrypted);
               ^---------------------------------^

and then here:

string decrypted = Decrypt(System.Text.Encoding.UTF8.GetBytes(passe), aes.Key, aes.IV);
                           ^--------------------------------^

I assume this is your simulation of storing it to the database and then getting it back, and storing it as a string.

However, what you've done is almost certainly corrupted the string this way.

Encoding.UTF8.GetString(bytes) does not convert a byte array containing arbitrary bytes to a string. Instead, it converts a byte array that is supposed to contain bytes making up an UTF8 encoded string back to that string.

If the byte array contains arbitrary bytes, such as the result of encrypting text, this step and its companion Encoding.UTF8.GetBytes is almost certain to corrupt the data and/or lose bytes.

Instead, you should use a different method of converting a byte array to a string and back.

One way would be to use Base64 encoding, and you can replace the two lines above with this:

string passe = Convert.ToBase64String(encrypted);
...
string decrypted = Decrypt(Convert.FromBase64String(passe), aes.Key, aes.IV);

This will result in your program encrypting and then decrypting the string just fine.


Additionally, you might want to look into storing the bytes into your database directly. Depending on your database engine there might be good support for storing byte arrays directly, without mucking about with string conversions of any kind.

Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825