2

I want to encrypt picturebox image and save it to file and be able to decrypt it and load back to picturebox. There are various code examples out there but none of them seem to work for me. I always get bigger decrypted file than the original one is.

I tried different methods to do this and here is most current one I wrote:

// Save signature file
    public void SaveFile(System.Drawing.Image image, string filename, string password)
    {


        byte[] img = imgToByteArray(image);
        byte[] encrypted = Signatures.Encryption.Encrypt(img, password);
        File.WriteAllBytes(filename, encrypted);

        // DEBUG
        byte[] decrypted = Signatures.Encryption.Decrypt(encrypted, password);
        image.Save(filename + "O");
        File.WriteAllBytes(filename + "E", encrypted);
        File.WriteAllBytes(filename + "D", decrypted);
        // End of DEBUG

    }

    // Open signature file
    public System.Drawing.Image ReadFile(string filename, string password)
    {
        byte[] encrypted = File.ReadAllBytes(filename);
        byte[] decrypted = Signatures.Encryption.Decrypt(encrypted, password);
        Image image = bytearrayToImage(decrypted);
        return image;
    }


    // Convert image to bytearray
    private byte[] imgToByteArray(Image img)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            img.Save(ms, ImageFormat.Png);
            return ms.ToArray();
        }
    }

    // Convert bytearray to image
    private Image bytearrayToImage(byte[] bytearray)
    {
        using (MemoryStream ms = new MemoryStream(bytearray))
        {
            return Image.FromStream(ms);    
        }
    }

Signatures.Encryption:

public static byte[] Encrypt(byte[] input, string password)
    {
        byte[] output;

        PasswordDeriveBytes pdb = new PasswordDeriveBytes(password, new byte[] { 0x43, 0x87, 0x23, 0x72 });

        Aes aes = new AesManaged();

        aes.Padding = PaddingMode.PKCS7;
        aes.KeySize = 256;
        aes.Key = pdb.GetBytes(aes.KeySize / 8);
        aes.IV = pdb.GetBytes(aes.BlockSize / 8);

        using (MemoryStream ms = new MemoryStream())
        {
            using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
            {
                cs.Write(input, 0, input.Length);
            }

            output = ms.ToArray();
        }

        return output;
    }

    public static byte[] Decrypt(byte[] input, string password)
    {
        byte[] output;

        PasswordDeriveBytes pdb = new PasswordDeriveBytes(password, new byte[] { 0x43, 0x87, 0x23, 0x72 });

        Aes aes = new AesManaged();

        aes.Padding = PaddingMode.PKCS7;
        aes.KeySize = 256;
        aes.Key = pdb.GetBytes(aes.KeySize / 8);
        aes.IV = pdb.GetBytes(aes.BlockSize / 8);

        using (MemoryStream ms = new MemoryStream())
        {
            using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
            {
                cs.Write(input, 0, input.Length);
            }

            output = ms.ToArray();
        }

        return output;
    }

Using PaddingMode.PKCS7 generates exception:

 +      Thrown: "Padding is invalid and cannot be removed." (System.Security.Cryptography.CryptographicException)   Exception Message = "Padding is invalid and cannot be removed.", Exception Type = "System.Security.Cryptography.CryptographicException", Exception WinRT Data = null    

and PaddingMode.Zeros generates exception:

+       Thrown: "Parameter is not valid." (System.ArgumentException)    Exception Message = "Parameter is not valid.", Exception Type = "System.ArgumentException", Exception WinRT Data = null 

I think that the Parameter is not valid. exception is generated because the image isn't valid (because of higher decryption byte lenght), the CompareBytes(byte[] first, byte[] second) gives false on all these cases.

EDIT: I just found out that one NULL byte is being added to the end of encrypted/decrypted file. EDIT2: The NULL byte gets added when encrypting. Removing it doesn't do much, the Image.FromStream(); still throws "Parameter is not valid.".

Alexander
  • 169
  • 2
  • 11
  • 1
    `CompareBytes` doesn't do what its name implies (it compares the references to the two arrays), and even if it did, why are you comparing the encrypted and decrypted versions and expecting them to be equal? – Damien_The_Unbeliever Jun 02 '15 at 08:02
  • Ah, simple mistake. Well, you can ignore the whole compare section. I'll remove it from the code above since it isn't actually relevant, just my tries for pinpointing the error. – Alexander Jun 02 '15 at 08:15
  • So, what is the problem? [Loading the bitmap from the decrypted byte array](http://stackoverflow.com/questions/21555394/how-to-create-bitmap-from-byte-array) ? – Patrik Jun 02 '15 at 08:22
  • @PatrikEckebrecht Problem occurs somewhere in encrypting/decrypting. The decrypted file is 1 byte bigger than it should and **I think** because of that the `Image.FromStream()` gives `"Parameter is not valid." (System.ArgumentException)`. File saving and loading without encryption/decryption works fine. – Alexander Jun 02 '15 at 09:27

1 Answers1

0

The problem here is (re)compression, not encryption. I tried your code on a JPG file and the decrypted output is PNG.

To retain the size, you have to use the same codec on the same input and account for metadata and data alignment, i.e. stuff you may have little control over.

Yegor
  • 2,235
  • 2
  • 16
  • 21
  • That's more a comment and less an answer. – Patrik Jun 02 '15 at 08:24
  • Simply because it's short? The problem was misidentified by the original poster. There's not much to answer to. – Yegor Jun 02 '15 at 08:27
  • If there is no answer, why do you post one? The initial post just didn't contain any advise for the poster. – Patrik Jun 02 '15 at 08:31
  • I though I already replied but seems like I did not. I changed the `ImageFormat.Png` to `ImageFormat.Jpeg` but that didn't change anything. I guess `Image.FromStream()` autodetects the format since there is no arguments to set it. – Alexander Jun 02 '15 at 09:36
  • There are different compression levels, different paddings in the file, etc. Even the same payload may have any number of additional metadata bytes attached to it. So you really shouldn't compare reencoded images as plain binary data, even uncompressed BMP files. If you really want the same array, you should encrypt the original file content, not the image you get from it. – Yegor Jun 02 '15 at 09:54
  • I just [compared](http://i.imgur.com/gBA3vLv.png) original jpeg and decrypted one. It seems that one NULL byte gets added to the end of the file. – Alexander Jun 02 '15 at 10:16