Home > Back-end >  C# Missing character on encrypt decrypt
C# Missing character on encrypt decrypt

Time:07-14

I tried to create encrypt decrypt function on my C# project

But somehow it got issue when the text need to be encrypted is more than 16 characters

The decrypted text is missing characters at the end

If I use shorter plainText like "abcde" it can decrypt the text with no problem

But if the plainText is long like on the example, some of the last character is gone

Need your help to check this code

Thanks

program.cs

string plainText = "abcdefghijklmnopqrstuvwhyz1234567890";
string password = Convert.ToBase64String(Cryptography.GenerateRandomEntropy());
string encryptedText = Cryptography.Encrypt(plainText, password);
string decryptedText = Cryptography.Decrypt(encryptedText, password);

Console.WriteLine("Text: "   plainText); //abcdefghijklmnopqrstuvwhyz1234567890
Console.WriteLine("Pass: "   password);
Console.WriteLine("Enc:  "   encryptedText);
Console.WriteLine("Dec:  "   decryptedText); //abcdefghijklmnopqrstuvwhyz123456

crypt.cs

using System.Text;
using System.Security.Cryptography;

public static class Cryptography
{
    private const int Keysize = 128;

    private const int DerivationIterations = 1000;

    public static string Encrypt(string plainText, string passPhrase)
    {
        var saltStringBytes = GenerateRandomEntropy();
        var ivStringBytes = GenerateRandomEntropy();
        var plainTextBytes = Encoding.UTF8.GetBytes(plainText);

        using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
        {
            var keyBytes = password.GetBytes(Keysize / 8);
            using (var symmetricKey = Aes.Create())
            {
                symmetricKey.BlockSize = Keysize;
                symmetricKey.Mode = CipherMode.CBC;
                symmetricKey.Padding = PaddingMode.PKCS7;
                using (var key = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes))
                {
                    using (var memoryStream = new MemoryStream())
                    {
                        using (var cryptoStream = new CryptoStream(memoryStream, key, CryptoStreamMode.Write))
                        {
                            cryptoStream.Write(plainTextBytes);
                            cryptoStream.FlushFinalBlock();
                            var cryptTextBytes = saltStringBytes;
                            cryptTextBytes = cryptTextBytes.Concat(ivStringBytes).ToArray();
                            cryptTextBytes = cryptTextBytes.Concat(memoryStream.ToArray()).ToArray();
                            memoryStream.Close();
                            cryptoStream.Close();
                            return Convert.ToBase64String(cryptTextBytes);
                        }
                    }
                }
            }
        }
    }

    public static string Decrypt(string cryptText, string passPhrase)
    {
        var cryptTextBytesWithSaltAndIv = Convert.FromBase64String(cryptText);
        var saltStringBytes = cryptTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();
        var ivStringBytes = cryptTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray();
        var cryptTextBytes = cryptTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cryptTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray();

        using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
        {
            var keyBytes = password.GetBytes(Keysize / 8);
            using (var symmetricKey = Aes.Create())
            {
                symmetricKey.BlockSize = Keysize;
                symmetricKey.Mode = CipherMode.CBC;
                symmetricKey.Padding = PaddingMode.PKCS7;
                using (var key = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes))
                {
                    using (var memoryStream = new MemoryStream(cryptTextBytes))
                    {
                        using (var cryptoStream = new CryptoStream(memoryStream, key, CryptoStreamMode.Read))
                        {
                            var plainTextBytes = new byte[cryptTextBytes.Length];
                            cryptoStream.Read(plainTextBytes);
                            memoryStream.Close();
                            cryptoStream.Close();
                            return Encoding.UTF8.GetString(plainTextBytes);
                        }
                    }
                }
            }
        }
    }

    public static byte[] GenerateRandomEntropy()
    {
        var randomBytes = new byte[Keysize / 8];
        using (var rngCsp = RandomNumberGenerator.Create())
        {
            rngCsp.GetBytes(randomBytes);
        }
        return randomBytes;
    }
}

CodePudding user response:

Somehow I got the workaround for this issue after post the question

I realize that the decryption text are missing when the plainText length is not a multiply of 16 (Keysize / 8)

So I add this code to append space character on plainText when the plainText is not multiple of 16

But this code make new issue (space character on the end of the decrypted text, and somehow the Trim() command cannot remove the trailing space)

 public static string Encrypt(string plainText, string passPhrase)
    {
        var saltStringBytes = GenerateRandomEntropy();
        var ivStringBytes = GenerateRandomEntropy();
        var mod = plainText.Length % (Keysize / 2);
        if (mod > 0) {
            for (var x = mod; x < Keysize / 2; x  ) {
                plainText = plainText   " ";
            }
        }
        var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
...

CodePudding user response:

Your issue is you are applying a padding on both the encrypt and decrypt, so on decrypt it will also apply that padding to remove the last 8 bytes and in your case some actual data. You can see this more visual with zero padding. You can try something like this to better suite you.

crypt.cs

private const int Keysize = 128;

private const int DerivationIterations = 1000;

public static string Encrypt(string plainText, string passPhrase)
{
    var saltStringBytes = GenerateRandomEntropy();
    var ivStringBytes = GenerateRandomEntropy();
    var plainTextBytes = Encoding.UTF8.GetBytes(plainText);

    using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
    {
        var keyBytes = password.GetBytes(Keysize / 8);
        using (var symmetricKey = Aes.Create())
        {
            symmetricKey.BlockSize = Keysize;
            symmetricKey.Mode = CipherMode.CBC;
            symmetricKey.Padding = PaddingMode.Zeros;
            using (var key = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes))
            {
                using (var memoryStream = new MemoryStream())
                {
                    using (var cryptoStream = new CryptoStream(memoryStream, key, CryptoStreamMode.Write))
                    {
                        cryptoStream.Write(plainTextBytes);
                        cryptoStream.FlushFinalBlock();
                        var cryptTextBytes = saltStringBytes;
                        cryptTextBytes = cryptTextBytes.Concat(ivStringBytes).ToArray();
                        cryptTextBytes = cryptTextBytes.Concat(memoryStream.ToArray()).ToArray();
                        memoryStream.Close();
                        cryptoStream.Close();
                        return Convert.ToBase64String(cryptTextBytes);
                    }
                }
            }
        }
    }
}

public static string Decrypt(string cryptText, string passPhrase)
{
    var cryptTextBytesWithSaltAndIv = Convert.FromBase64String(cryptText);
    var saltStringBytes = cryptTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();
    var ivStringBytes = cryptTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray();
    var cryptTextBytes = cryptTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cryptTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray();

    using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
    {
        var keyBytes = password.GetBytes(Keysize / 8);
        using (var symmetricKey = Aes.Create())
        {
            symmetricKey.BlockSize = Keysize;
            symmetricKey.Mode = CipherMode.CBC;
            symmetricKey.Padding = PaddingMode.Zeros;
            using (var key = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes))
            {
                using (var memoryStream = new MemoryStream(cryptTextBytes))
                {
                    using (var cryptoStream = new CryptoStream(memoryStream, key, CryptoStreamMode.Read))
                    {
                        var plainTextBytes = new byte[cryptTextBytes.Length];
                        
                        cryptoStream.Read(plainTextBytes);

                        memoryStream.Close();
                        cryptoStream.Close();
                        return Encoding.UTF8.GetString(plainTextBytes).TrimEnd('\0');
                    }
                }
            }
        }
    }
}

public static byte[] GenerateRandomEntropy()
{
    var randomBytes = new byte[Keysize / 8];
    using (var rngCsp = RandomNumberGenerator.Create())
    {
        rngCsp.GetBytes(randomBytes);
    }
    return randomBytes;
}

output

Text: abcdefghijklmnopqrstuvwhyz1234567890
Pass: 4UnD6QCMCe0vgYA0ZHJKaw==
Enc:  SdKNaXWweKyaJsh93bvPeMzmtewNHlKdN3LTeWZEWD2ubQOY88d bbetB 4ymGguYYBZG54NEGCu 9Epg4 1dW 8kdNKJ2Sf71HIVoaFxnc=
Dec:  abcdefghijklmnopqrstuvwhyz1234567890
  • Related