user1052042
user1052042

Reputation: 31

unable to open xml after decryption 1 byte to many?

I'm trying to encrypt XML, and after decryption I end up with 1 byte too many - probably because of padding. This is my code. How can I change this to make it work?

public byte[] encryptData(byte[] source,string key)
{
    byte[] btKeyInBytes = UTF8Encoding.UTF8.GetBytes(key);
    Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(key, btKeyInBytes);

    AesManaged encryptor = new AesManaged();
    encryptor.Padding = PaddingMode.Zeros;

    using (MemoryStream encryptStream = new MemoryStream())
    {
        using (CryptoStream encStream = new CryptoStream(encryptStream, encryptor.CreateEncryptor(rfc.GetBytes(16), rfc.GetBytes(16)), CryptoStreamMode.Read))
        {
            //Read from the input stream, then encrypt and write to the output stream.
            encStream.Write(source, 0, source.Length);
            encStream.FlushFinalBlock();
            encryptor.Clear();
        }
        encryptStream.Flush();
        encryptedSource = encryptStream.ToArray();
    }
    return encryptedSource;
}

public byte[] decryptData(byte[] source, string key)
{
    byte[] encryptedSource = null;

    byte[] btKeyInBytes = UTF8Encoding.UTF8.GetBytes(key);
    Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(key, btKeyInBytes);

    AesManaged encryptor = new AesManaged();
    encryptor.Padding = PaddingMode.Zeros;

    using (MemoryStream encryptStream = new MemoryStream())
    {
        using (CryptoStream encStream = new CryptoStream(encryptStream, encryptor.CreateDecryptor(rfc.GetBytes(16), rfc.GetBytes(16)), CryptoStreamMode.Write))
        {
            //Read from the input stream, then encrypt and write to the output stream.
            encStream.Write(source, 0, source.Length);
            encStream.FlushFinalBlock();
            encryptor.Clear();
        }
        encryptStream.Flush();
        encryptedSource = encryptStream.ToArray();
    }

    return encryptedSource;
}

It seems that the padding gives me 1 extra byte during decryption

Upvotes: 2

Views: 351

Answers (2)

user1052042
user1052042

Reputation: 31

I got it!

Now let's try to explain.

Let's say I have a file of 927 bytes.

What I do is to read this file and split it in pieces of 656 bytes. This byte array of 656 bytes is being encrypted. The second array will be 271 bytes.

In every block for encryption I used padding. When decrypting, you will not be able to know in which block padding was used because every block now can be divided by 16 (because of the padding in the encryption). Basically I only want padding used for the last block(271).

so this is my new code:

public byte[] encryptData(byte[] source, string key, bool padding)
{
    byte[] encryptedSource = null;


    byte[] btKeyInBytes = UTF8Encoding.UTF8.GetBytes(key);
    Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(key, btKeyInBytes);

    AesManaged encryptor = new AesManaged();
    //encryptor.Mode = CipherMode.CFB; 
    encryptor.KeySize = 128;          // in bits     
    encryptor.Key = new byte[128 / 8];  // 16 bytes for 128 bit encryption     
    encryptor.IV = new byte[128 / 8];
    if (padding) { encryptor.Padding = PaddingMode.PKCS7; }
    else { encryptor.Padding = PaddingMode.None; }


    using (MemoryStream encryptStream = new MemoryStream())
    {
        using (CryptoStream encStream =
                   new CryptoStream(encryptStream,
                                    encryptor.CreateEncryptor(rfc.GetBytes(16),
                                                              rfc.GetBytes(16)),
                                    CryptoStreamMode.Write))
        {
            //Read from the input stream, then encrypt and write to the output stream.
            encStream.Write(source, 0, source.Length);
        }
        encryptStream.Flush();
        encryptedSource = encryptStream.ToArray();
    }
    return encryptedSource;
}

public byte[] decryptData(byte[] source, string key,bool padding)
{
    byte[] encryptedSource = null;

    byte[] btKeyInBytes = UTF8Encoding.UTF8.GetBytes(key);
    Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(key, btKeyInBytes);

    AesManaged encryptor = new AesManaged();
    encryptor.Key = new byte[128 / 8];  // 16 bytes for 128 bit encryption     
    encryptor.IV = new byte[128 / 8];
    if (padding) { encryptor.Padding = PaddingMode.PKCS7; }
    else { encryptor.Padding = PaddingMode.None; }


    using (MemoryStream encryptStream = new MemoryStream())
    {
        using (CryptoStream encStream =
                 new CryptoStream(encryptStream,
                                  encryptor.CreateDecryptor(rfc.GetBytes(16),
                                                            rfc.GetBytes(16)),
                                  CryptoStreamMode.Write))
        {
            //Read from the input stream, then encrypt and write to the output stream.
            encStream.Write(source, 0, source.Length);
        }
        encryptStream.Flush();
        encryptedSource = encryptStream.ToArray();

    }

    return encryptedSource;
}

I hope this helps!

Upvotes: 1

rossum
rossum

Reputation: 15685

If your problem is padding, then PaddingMode.Zeros is about the worst choice, since zeros cannot always be reliably removed. Better to use PKCS7 padding.

It is also possible that the encoding of end-of-line has changed between systems. Some systems use a single byte while other systems use two bytes. You really need to look at exactly what is in the decrypted file, byte by byte, as @Rup suggests.

Upvotes: 1

Related Questions