2

I'm trying to make a console application that can encrypt and decrypt file. I gave encrypted file a custom file extension ".aes" (e.g. samplefile.aes) now the problem is when I decrypt the file there is no way to identify what is the original extension of the file when it was encrypted. Is there any chance I can get file type from AES 256 encrypted file ?

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

namespace FileEncryption
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length < 2)
            {
                Environment.ExitCode = 1;
                Console.Error.WriteLine(Strings.CommandlineUsage);
                return;
            }

            bool encrypt = args[0].StartsWith("-e", StringComparison.InvariantCultureIgnoreCase);
            bool decrypt = args[0].StartsWith("-d", StringComparison.InvariantCultureIgnoreCase);

            if (!(encrypt || decrypt))
            {
                Environment.ExitCode = 1;
                Console.Error.WriteLine(Strings.CommandlineUnknownMode);
                return;
            }

            string inputname = (args.Length >= 3) ? args[2] : null;

            if (inputname != null && !File.Exists(inputname))
            {
                Environment.ExitCode = 2;
                Console.Error.WriteLine(Strings.CommandlineInputFileNotFound);
                return;
            }

            byte[] passwordBytes = Encoding.UTF8.GetBytes(args[1]);
            // Hash the password with SHA256
            passwordBytes = SHA256Managed.Create().ComputeHash(passwordBytes);

            try
            {
                if (encrypt)
                {
                    //Encrypt file                   
                    byte[] bytesToBeEncrypted = File.ReadAllBytes(inputname);
                    byte[] bytesEncrypted = AES_Encrypt(bytesToBeEncrypted, passwordBytes);

                    //Save encrypted file
                    string fileEncrypted = inputname.Remove(inputname.IndexOf('.')) + ".aes";
                    File.WriteAllBytes(fileEncrypted, bytesEncrypted);
                }
                else
                {
                    byte[] bytesToBeDecrypted = File.ReadAllBytes(inputname);
                    byte[] bytesDecrypted = AES_Decrypt(bytesToBeDecrypted, passwordBytes);

                    string file = inputname;
                    File.WriteAllBytes(file, bytesDecrypted);
                }
                Environment.ExitCode = 0;
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine(string.Format(Strings.CommandlineError, ex.Message));
            }        
        }


        //***********************************************************************************************
        // --- HELPER FUNCTIONS ---
        //*

        //Encrypt File
        public static byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)
        {
            byte[] encryptedBytes = null;

            // Set your salt here, change it to meet your flavor:
            // The salt bytes must be at least 8 bytes.
            byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };

            using (MemoryStream ms = new MemoryStream())
            {
                using (RijndaelManaged AES = new RijndaelManaged())
                {
                    AES.KeySize = 256;
                    AES.BlockSize = 128;

                    var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
                    AES.Key = key.GetBytes(AES.KeySize / 8);
                    AES.IV = key.GetBytes(AES.BlockSize / 8);

                    AES.Mode = CipherMode.CBC;

                    using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
                        cs.Close();
                    }
                    encryptedBytes = ms.ToArray();
                }
            }

            return encryptedBytes;
        }

        //Decrypt File
        public static byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
        {
            byte[] decryptedBytes = null;

            // Set your salt here, change it to meet your flavor:
            // The salt bytes must be at least 8 bytes.
            byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };

            using (MemoryStream ms = new MemoryStream())
            {
                using (RijndaelManaged AES = new RijndaelManaged())
                {
                    AES.KeySize = 256;
                    AES.BlockSize = 128;

                    var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
                    AES.Key = key.GetBytes(AES.KeySize / 8);
                    AES.IV = key.GetBytes(AES.BlockSize / 8);

                    AES.Mode = CipherMode.CBC;

                    using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
                        cs.Close();
                    }
                    decryptedBytes = ms.ToArray();
                }
            }

            return decryptedBytes;
        }
    }
}

I know that the nature of encrypted file is not to identify original extension. What I was going to do is that when I encrypt the file I will give it .originalextension.aes (e.g. picture.png.aes) and then when I decrypt it I just need to remove .aes extension. Just wondering is this a good way or not?

Aidenmay
  • 41
  • 6
  • You would prepend a well defined header to the file data that contained whatever meta data you want, for example the original file name, then encrypt everything. If you don't care about disclosing the extension you can prepend the header to the encrypted data. – Alex K. Jul 19 '16 at 11:29
  • You should use a derived key rather than a hash of the password. – Alex K. Jul 19 '16 at 11:30

1 Answers1

0

If the file type is required to be hidden by the encryption or not is a user requirement. You may just want to protect the content and not the file type. Note that the file size can also give hints to an "attacker". It's also up to you if you need to hide that kind of meta-data.

Without the extension you may have a look at the file contents by using file fingerprinting. Many file formats give some kind of hint on what they are. For instance, it's certainly possible to guess the character encoding of .txt files. JPG files have JPG headers, same goes for zip archives etc. etc. Usually these tools output the MIME file type (as the extension is not always that well defined or standardized).

On GNU systems you may use the file command line for that. This kind of fingerprinting is also used for many content management systems (CMS). So you can have a look at the CMS in your language and try to filter out the file command functionality in there.

Or, now you know the right search keywords, you can simply find it here on StackOverflow: Using .NET, how can you find the mime type of a file based on the file signature not the extension was given as 3rd hit when typing in "fingerprint file type c# mime".

Note that, because extensions are not always that well defined, you may not get back the original extension this way. To allow this you need to store the extension in plaintext (in the filename) growing the file name size (!) or you can store it encrypted together with the data. You'd have to create an encryption protocol for that.

Community
  • 1
  • 1
Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263