Exemplo n.º 1
0
        /// <summary>
        /// Handle the decryption of the identified filepath to an output directory
        /// </summary>
        /// <returns>Returns true of the operation was successful</returns>
        public override bool StartOperation()
        {
            //Check that there is a single file to process
            if (identifiedFiles.Count != 1)
            {
                Console.WriteLine($"Can't start decryption operation, there is an invalid number ({identifiedFiles.Count}) of files set as the target. Expected only 1");
                return(false);
            }

            //Store the buffers that will be used for the operation
            FileStream fStream = null;
            GZipStream reader  = null;
            FileStream writer  = null;

            //Create the encryption key that will be used for this operation
            VigenèreCipherKey key = new VigenèreCipherKey(Key);

            //Flag if the operation was completed successfully
            bool successful = true;

            //Store a progress value that can be output
            float progress = 0f;

            //Store a collection of the files that are generated by this operation
            //<Temp Path, Final Path>
            List <Tuple <string, string> > generatedFiles = new List <Tuple <string, string> >();

            //Attempt to decrypt the entire file
            try {
                //Create the initial buffer objects
                fStream = new FileStream(TargetPath, FileMode.Open, FileAccess.Read, FileShare.Read, BUFFER_SIZE);
                reader  = new GZipStream(fStream, CompressionMode.Decompress);

                //Create the byte buffers that will be used for the operation
                byte[] dataBuffer = new byte[BUFFER_SIZE];
                byte[] intBuffer  = new byte[sizeof(int)];
                byte[] longBuffer = new byte[sizeof(long)];

                //Read the number of files that are included in this collection
                reader.Read(intBuffer, 0, sizeof(int));
                key.Decrypt(ref intBuffer, sizeof(int));

                //Decrypt the count
                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(intBuffer, 0, sizeof(int));
                }
                int fileCount = BitConverter.ToInt32(intBuffer, 0);

                //Calculate the percentage to use for each file processed
                float percentageUsage = .75f / fileCount;

                //Loop through each file to be processed
                for (int i = 0; i < fileCount; i++)
                {
                    //Read the bytes for the number of characters in the filepath
                    reader.Read(intBuffer, 0, sizeof(int));
                    key.Decrypt(ref intBuffer, sizeof(int));

                    //Get the number of characters that are in the
                    if (BitConverter.IsLittleEndian)
                    {
                        Array.Reverse(intBuffer, 0, sizeof(int));
                    }
                    int characterCount = BitConverter.ToInt32(intBuffer, 0);

                    //Construct the relative filepath back from the data
                    StringBuilder relativePath = new StringBuilder(characterCount);

                    //Loop through and read the filepath
                    long processedCount = 0;
                    do
                    {
                        //Retrieve the next chunk of characters from datafile
                        int readCount = reader.Read(dataBuffer, 0,
                                                    Math.Min(
                                                        (BUFFER_SIZE / sizeof(char)) * sizeof(char),
                                                        (characterCount - (int)processedCount) * sizeof(char)
                                                        )
                                                    );

                        //Decrypt the character bytes
                        key.Decrypt(ref dataBuffer, readCount);

                        //Half the count for final processing
                        readCount /= sizeof(char);

                        //Extract the characters from the buffer
                        byte[] charBuffer = new byte[sizeof(char)];
                        for (int c = 0; c < readCount; c++)
                        {
                            //Get the character bytes from the array
                            Array.Copy(dataBuffer, c * sizeof(char), charBuffer, 0, sizeof(char));

                            //Convert the byte data back to a character
                            if (BitConverter.IsLittleEndian)
                            {
                                Array.Reverse(charBuffer, 0, sizeof(char));
                            }
                            relativePath.Append(BitConverter.ToChar(charBuffer, 0));
                        }

                        //Increase the counter
                        processedCount += readCount;
                    } while (processedCount < characterCount);

                    //Get the amount of data to evaluated by this process
                    reader.Read(longBuffer, 0, sizeof(long));
                    key.Decrypt(ref longBuffer, sizeof(long));

                    //Get the amount of data to be processed
                    if (BitConverter.IsLittleEndian)
                    {
                        Array.Reverse(longBuffer, 0, sizeof(long));
                    }
                    long dataCount = BitConverter.ToInt64(longBuffer, 0);

                    //Get a temp file to store the data at
                    string tempPath = Path.GetTempFileName();

                    //Add the entry to the monitor list
                    generatedFiles.Add(new Tuple <string, string>(
                                           tempPath,
                                           Path.Combine(DestinationPath, relativePath.ToString())
                                           ));

                    //Try to create process the contained file
                    try {
                        //Open the temporary file for writing
                        writer = new FileStream(tempPath, FileMode.Append, FileAccess.Write, FileShare.Read, BUFFER_SIZE);

                        //Process all of the data within the file
                        processedCount = 0;
                        do
                        {
                            //Retrieve the next chunk of data to process
                            int readCount = reader.Read(dataBuffer, 0,
                                                        (int)Math.Min(
                                                            BUFFER_SIZE,
                                                            dataCount - processedCount
                                                            )
                                                        );

                            //If there is data to be read but nothing was read from the file, then something has gone wrong
                            if (readCount == 0 && dataCount - processedCount > 0)
                            {
                                throw new OperationCanceledException($"OperationCanceledException: {dataCount - processedCount} bytes are left to be read but 0 bytes were read. Reached EOF");
                            }

                            //Increase the counters
                            processedCount += readCount;

                            //Decrypt the buffer and write it to the file
                            key.Decrypt(ref dataBuffer, readCount);
                            writer.Write(dataBuffer, 0, readCount);
                        } while (processedCount < dataCount);
                    }
#if DEBUG
                    //Log the exception thrown for debugging purposes
                    catch (Exception exec) {
                        Console.WriteLine($"Decryption failed to process internal file. Writing of included file '{relativePath.ToString()}' failed. ERROR: {exec.Message}");
                        successful = false;
                        break;
                    }
#else
                    //Log general failure on exception. Assume key is wrong
                    catch {
                        Console.WriteLine("Decryption failed to process an internal file. Is the Cipher Key correct?");
                        successful = false;
                        break;
                    }
#endif
                    //Cleanup the file writing
                    finally { if (writer != null)
                              {
                                  writer.Dispose(); writer = null;
                              }
                    }

                    //Increment the operation percentage
                    progress += percentageUsage;
                    Console.WriteLine($"\tProgress: {(progress * 100f).ToString("F2") + '%'}");
                }
            }

#if DEBUG
            //Log the exception thrown for debugging purposes
            catch (Exception exec) {
                Console.WriteLine($"Decryption failed to process internal file. Is the Cipher Key correct? ERROR: {exec.Message}");
                successful = false;
            }
#else
            //Log general failure on exception. Assume key is wrong
            catch {
                Console.WriteLine("Decryption failed to process an internal file. Is the Cipher Key correct?");
                successful = false;
            }
#endif

            finally {
                //Clear out the file streams
                if (writer != null)
                {
                    writer.Dispose(); writer = null;
                }
                if (reader != null)
                {
                    reader.Dispose(); reader = null;
                }
                if (fStream != null)
                {
                    fStream.Dispose(); fStream = null;
                }

                //Loop for the duration of the cleanup
                while (true)
                {
                    //If the operation failed, delete all of the temp files
                    if (!successful)
                    {
                        //Delete all of the (remaining) temp files
                        for (int i = 0; i < generatedFiles.Count; i++)
                        {
                            try { File.Delete(generatedFiles[i].Item1); } catch { }
                        }

                        //Break from the infinite loop
                        break;
                    }

                    //Otherwise, shift the files to the valid destination
                    else
                    {
                        //Calculate a percentage requirement for each file to shift
                        float percentageUsage = .25f / generatedFiles.Count;

                        //Process all of the files
                        string destinationPath = string.Empty;
                        for (int i = 0; i < generatedFiles.Count; i++)
                        {
                            //Get the next filepath that is to be processed by the data
                            destinationPath = generatedFiles[i].Item2;

                            //Attempt to ensure the directory exists, catching filepaths that are to long
                            bool attempted = false, failed = false;
                            while (true)
                            {
                                try {
                                    //Ensure the directory exists
                                    Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));

                                    //If gotten this far, path is valid. Exit from the loop
                                    break;
                                }

                                //Otherwise, shorten the path
                                catch (PathTooLongException) {
                                    //If the fix has already been attempted then nothing we can do
                                    if (attempted)
                                    {
                                        Console.WriteLine($"Failed to setup decrypted file '{Path.GetFileName(destinationPath)}' as the resulting filepath '{destinationPath}' was to long");
                                        successful = false;
                                        failed     = true;
                                        break;
                                    }

                                    //Otherwise, try to temp fix the positioning of the file
                                    else
                                    {
                                        //Construct a debug string that can be used to explain the resulting operation
                                        StringBuilder sb = new StringBuilder($"Failed to setup directory for filepath '{destinationPath}' as the filepath is to long. ");

                                        //Shorten the filename to the destination directory with additional information (To prevent copy overwrite)
                                        destinationPath = Path.Combine(DestinationPath, $"{Path.GetFileNameWithoutExtension(destinationPath)}_({Path.GetFileNameWithoutExtension(generatedFiles[i].Item1)}){Path.GetExtension(destinationPath)}");

                                        //Add the new path to the message
                                        sb.Append($"The new path of '{destinationPath}' has been assigned to try and shorten the final path");

                                        //Log the message
                                        Console.WriteLine(sb.ToString());

                                        //Flag as the fix being attempted
                                        attempted = true;
                                    }
                                }
                            }

                            //If the operation has failed, quit out
                            if (failed)
                            {
                                break;
                            }

                            //Delete the file if it already exists
                            try { File.Delete(destinationPath); } catch { }

                            //Try to move the decrypted file to the final location
                            try { File.Move(generatedFiles[i].Item1, destinationPath); } catch (Exception exec) {
                                Console.WriteLine($"Decryption operation failed to relocate decrypted file to '{destinationPath}'. ERROR: {exec.Message}");
                                successful = false;
                                break;
                            }

                            //Increment the operation percentage
                            progress += percentageUsage;
                            Console.WriteLine($"\tProgress: {(progress * 100f).ToString("F2") + '%'}");
                        }

                        //Exit from the loop if the operation was a success
                        if (successful)
                        {
                            break;
                        }
                    }
                }
            }

            //Mark the end of the operation
            return(successful);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Handle the encryption of the identified filepaths to an output file
        /// </summary>
        /// <returns>Returns true of the operation was successful</returns>
        public override bool StartOperation()
        {
            //Check that there are files to process
            if (identifiedFiles.Count == 0)
            {
                Console.WriteLine("Can't start encryption operation. No files were identified for encryption");
                return(false);
            }

            //Store the buffers that will be used for the operation
            FileStream fStream = null;
            GZipStream writer  = null;
            FileStream reader  = null;

            //Create the encryption key that will be used for this operation
            VigenèreCipherKey key = new VigenèreCipherKey(Key);

            //Flag if the operation was completed successfully
            bool successful = true;

            //Store a progress value that can be output
            float progress = 0f;

            //Attempt to parse all of the supplied data
            try {
                //Create the initial buffer objects
                fStream = new FileStream(DestinationPath, FileMode.Create, FileAccess.Write, FileShare.None, BUFFER_SIZE);
                writer  = new GZipStream(fStream, CompressionMode.Compress);

                //Create the byte buffers that will be used for the operation
                byte[] dataBuffer = new byte[BUFFER_SIZE];
                byte[] intBuffer  = null;
                byte[] longBuffer = null;

                //Get the root directory of the target path
                string rootDir = (Path.HasExtension(TargetPath) ?
                                  Path.GetDirectoryName(TargetPath) :
                                  TargetPath
                                  );

                //Ensure that there is a trailing slash on the directory
                if (!rootDir.EndsWith(Path.DirectorySeparatorChar.ToString()) ||
                    !rootDir.EndsWith(Path.AltDirectorySeparatorChar.ToString()))
                {
                    rootDir += Path.DirectorySeparatorChar;
                }

                //Determine the percentage to use per file that is encrypted
                float percentageUsage = 1f / identifiedFiles.Count;

                //Convert the number of files to process into bytes
                intBuffer = BitConverter.GetBytes(identifiedFiles.Count);
                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(intBuffer, 0, sizeof(int));
                }
                key.Encrypt(ref intBuffer, sizeof(int));

                //Write the count to the file
                writer.Write(intBuffer, 0, sizeof(int));

                //Process each of the files that are to be included
                foreach (FileInfo file in identifiedFiles)
                {
                    //Remove the root directory from the filepath
                    string relativePath = file.FullName.Substring(rootDir.Length);

                    //Get the number of characters to be processed in the relative path
                    intBuffer = BitConverter.GetBytes(relativePath.Length);
                    if (BitConverter.IsLittleEndian)
                    {
                        Array.Reverse(intBuffer, 0, sizeof(int));
                    }
                    key.Encrypt(ref intBuffer, sizeof(int));

                    //Write the character count to the file
                    writer.Write(intBuffer, 0, sizeof(int));

                    //Write the filepath to the buffer
                    long processedCount = 0;
                    do
                    {
                        //Track the number of characters that have been added to the buffer
                        int dataBufferUsage = 0;

                        //Copy the available characters to the buffer
                        for (; processedCount < relativePath.Length && dataBufferUsage + sizeof(char) < BUFFER_SIZE; processedCount++, dataBufferUsage += sizeof(char))
                        {
                            //Get the bytes for the characters
                            byte[] charBuffer = BitConverter.GetBytes(relativePath[(int)processedCount]);

                            //Copy the characters to the buffer
                            if (BitConverter.IsLittleEndian)
                            {
                                Array.Reverse(charBuffer, 0, sizeof(char));
                            }
                            Array.Copy(charBuffer, 0, dataBuffer, dataBufferUsage, sizeof(char));
                        }

                        //Encrypt the buffer and write it to the file
                        key.Encrypt(ref dataBuffer, dataBufferUsage);
                        writer.Write(dataBuffer, 0, dataBufferUsage);
                    } while (processedCount < relativePath.Length);

                    //Get the amount of data in the file
                    longBuffer = BitConverter.GetBytes(file.Length);
                    if (BitConverter.IsLittleEndian)
                    {
                        Array.Reverse(longBuffer, 0, sizeof(long));
                    }
                    key.Encrypt(ref longBuffer, sizeof(long));

                    //Write the data count to the buffer
                    writer.Write(longBuffer, 0, sizeof(long));

                    //Try to open and process the file that is being processed
                    try {
                        //Open the file for reading
                        reader = new FileStream(file.FullName, FileMode.Open, FileAccess.Read, FileShare.Read, BUFFER_SIZE);

                        //Process all of the data in the file
                        processedCount = 0;
                        do
                        {
                            //Retrieve the chunk of data from the file
                            int readCount = reader.Read(dataBuffer, 0, BUFFER_SIZE);

                            //Add to the counter
                            processedCount += readCount;

                            //Encrypt and write the data
                            key.Encrypt(ref dataBuffer, readCount);
                            writer.Write(dataBuffer, 0, readCount);
                        } while (processedCount < file.Length);
                    }

                    //Log any errors that occur
                    catch (Exception exec) {
                        Console.WriteLine($"Encryption failed to process the file '{file.FullName}'. ERROR: {exec.Message}");
                        successful = false;
                        break;
                    }

                    //Cleanup the file elements
                    finally { if (reader != null)
                              {
                                  reader.Dispose(); reader = null;
                              }
                    }

                    //Increment the operation percentage
                    progress += percentageUsage;
                    Console.WriteLine($"\tProgress: {(progress * 100f).ToString("F2") + '%'}");
                }
            }

            //Catch anything unexpected that happens
            catch (Exception exec) {
                Console.WriteLine($"Unexpected error occurred, unable to complete encryption operation. ERROR: {exec.Message}");
                successful = false;
            }

            finally {
                //Clear out the file streams
                if (reader != null)
                {
                    reader.Dispose(); reader = null;
                }
                if (writer != null)
                {
                    writer.Dispose(); writer = null;
                }
                if (fStream != null)
                {
                    fStream.Dispose(); fStream = null;
                }

                //If the operation wasn't successful, delete the file if it exists
                if (!successful)
                {
                    File.Delete(DestinationPath);
                }
            }

            //Mark the end of the operation
            return(successful);
        }