Пример #1
0
        public override void Erase(Stream stream, long erasureLength, IPrng prng,
                                   ErasureMethodProgressFunction callback)
        {
            //Randomize the order of the passes
            ErasureMethodPass[] randomizedPasses = PassesSet;
            if (RandomizePasses)
            {
                randomizedPasses = ShufflePasses(randomizedPasses);
            }

            //Remember the starting position of the stream.
            long strmStart  = stream.Position;
            long strmLength = Math.Min(stream.Length - strmStart, erasureLength);
            long totalData  = CalculateEraseDataSize(null, strmLength);

            //Allocate memory for a buffer holding data for the pass.
            byte[] buffer = new byte[Math.Min(DiskOperationUnit, strmLength)];

            //Run every pass!
            for (int pass = 0; pass < Passes; ++pass)
            {
                //Do a progress callback first.
                if (callback != null)
                {
                    callback(0, totalData, pass + 1);
                }

                //Start from the beginning again
                stream.Seek(strmStart, SeekOrigin.Begin);

                //Write the buffer to disk.
                long toWrite     = strmLength;
                int  dataStopped = buffer.Length;
                while (toWrite > 0)
                {
                    //Calculate how much of the buffer to write to disk.
                    int amount = (int)Math.Min(toWrite, buffer.Length - dataStopped);

                    //If we have no data left, get more!
                    if (amount == 0)
                    {
                        randomizedPasses[pass].Execute(buffer, prng);
                        dataStopped = 0;
                        continue;
                    }

                    //Write the data.
                    stream.Write(buffer, dataStopped, amount);
                    stream.Flush();
                    dataStopped += amount;
                    toWrite     -= amount;

                    //Do a progress callback.
                    if (callback != null)
                    {
                        callback(amount, totalData, pass + 1);
                    }
                }
            }
        }
Пример #2
0
        /// <summary>
        /// Generates a random file name with the given length.
        /// </summary>
        /// <remarks>The generated file name is guaranteed not to exist.</remarks>
        /// <param name="info">The directory to generate the file name in. This
        /// parameter can be null to indicate merely a random file name</param>
        /// <param name="length">The length of the file name to generate.</param>
        /// <returns>A full path to a file containing random file name.</returns>
        public static string GenerateRandomFileName(DirectoryInfo info, int length)
        {
            //Get the PRNG we are going to use
            IPrng prng = Host.Instance.Prngs.ActivePrng;

            //Initialsie the base name, if any.
            string resultPrefix = info == null ? string.Empty : info.FullName +
                                  Path.DirectorySeparatorChar;

            //Variables to store the intermediates.
            byte[]        resultAry           = new byte[length];
            string        result              = string.Empty;
            List <string> prohibitedFileNames = new List <string>(new string[] {
                "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4",
                "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3",
                "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"
            });

            do
            {
                prng.NextBytes(resultAry);

                //Validate the name
                string validFileNameChars = "0123456789abcdefghijklmnopqrstuvwxyz" +
                                            "ABCDEFGHIJKLMNOPQRSTUVWXYZ _+=-()[]{}',`~!";
                for (int j = 0, k = resultAry.Length; j < k; ++j)
                {
                    resultAry[j] = (byte)validFileNameChars[
                        (int)resultAry[j] % validFileNameChars.Length];

                    if (j == 0 || j == k - 1)
                    {
                        //The first or last character cannot be whitespace
                        while (Char.IsWhiteSpace((char)resultAry[j]))
                        {
                            resultAry[j] = (byte)validFileNameChars[
                                (int)resultAry[j] % validFileNameChars.Length];
                        }
                    }
                }

                result = Encoding.UTF8.GetString(resultAry);
            }while (info != null &&
                    prohibitedFileNames.IndexOf(Path.GetFileNameWithoutExtension(result)) != -1 ||
                    (Directory.Exists(resultPrefix + result) || File.Exists(resultPrefix + result)));
            return(resultPrefix + result);
        }
Пример #3
0
        public override void Erase(Stream strm, long erasureLength, IPrng prng,
                                   ErasureMethodProgressFunction callback)
        {
            //If we have no default or we are the default then throw an exception
            if (method == null || method.Guid == Guid)
            {
                throw new InvalidOperationException(S._("The First/last 16KB erasure method " +
                                                        "requires another erasure method to erase the file.\n\nThis must " +
                                                        "be set in the Plugin Settings dialog."));
            }

            //Make sure that the erasureLength passed in here is the maximum value
            //for the size of long, since we don't want to write extra or write
            //less.
            if (erasureLength != long.MaxValue)
            {
                throw new ArgumentException("The amount of data erased should not be " +
                                            "limited, since this is a self-limiting erasure method.");
            }

            //If the target stream is shorter than or equal to 32kb, just forward it to
            //the default function.
            if (strm.Length < DataSize * 2)
            {
                method.Erase(strm, erasureLength, prng, callback);
                return;
            }

            //We need to intercept the callback function as we run the erasure method
            //twice on two parts of the file.
            long dataSize = method.CalculateEraseDataSize(null, DataSize * 2);
            ErasureMethodProgressFunction customCallback =
                delegate(long lastWritten, long totalData, int currentPass)
            {
                callback(lastWritten, dataSize, currentPass);
            };

            //Seek to the beginning and write 16kb.
            strm.Seek(0, SeekOrigin.Begin);
            method.Erase(strm, dataSize, prng, callback == null ? null: customCallback);

            //Seek to the end - 16kb, and write.
            strm.Seek(-dataSize, SeekOrigin.End);
            method.Erase(strm, long.MaxValue, prng, callback == null ? null : customCallback);
        }
Пример #4
0
        /// <summary>
        /// Shuffles the passes in the input array, effectively randomizing the
        /// order or rewrites.
        /// </summary>
        /// <param name="passes">The input set of passes.</param>
        /// <returns>The shuffled set of passes.</returns>
        protected static ErasureMethodPass[] ShufflePasses(ErasureMethodPass[] passes)
        {
            //Make a copy.
            ErasureMethodPass[] result = new ErasureMethodPass[passes.Length];
            passes.CopyTo(result, 0);

            //Randomize.
            IPrng rand = Host.Instance.Prngs.ActivePrng;

            for (int i = 0; i < result.Length; ++i)
            {
                int val = rand.Next(result.Length - 1);
                ErasureMethodPass tmpPass = result[val];
                result[val] = result[i];
                result[i]   = tmpPass;
            }

            return(result);
        }
Пример #5
0
        /// <summary>
        /// Gets a random file from within the provided directory.
        /// </summary>
        /// <param name="info">The directory to get a random file name from.</param>
        /// <returns>A string containing the full path to the file.</returns>
        public static string GetRandomFile(DirectoryInfo info)
        {
            //First retrieve the list of files and folders in the provided directory.
            FileSystemInfo[] entries = null;
            try
            {
                entries = info.GetFileSystemInfos();
            }
            catch (DirectoryNotFoundException)
            {
                return(string.Empty);
            }
            if (entries.Length == 0)
            {
                return(string.Empty);
            }

            //Find a random entry.
            IPrng  prng   = Host.Instance.Prngs.ActivePrng;
            string result = string.Empty;

            while (result.Length == 0)
            {
                int index = prng.Next(entries.Length - 1);
                if (entries[index] is DirectoryInfo)
                {
                    result = GetRandomFile((DirectoryInfo)entries[index]);
                }
                else
                {
                    result = ((FileInfo)entries[index]).FullName;
                }
            }

            return(result);
        }
Пример #6
0
 public abstract void Erase(Stream stream, long erasureLength, IPrng prng,
                            ErasureMethodProgressFunction callback);
Пример #7
0
 /// <summary>
 /// Executes the pass.
 /// </summary>
 /// <param name="buffer">The buffer to populate with the data to write.</param>
 /// <param name="prng">The PRNG used for random passes.</param>
 public void Execute(byte[] buffer, IPrng prng)
 {
     Function(buffer, OpaqueValue == null ? prng : OpaqueValue);
 }
Пример #8
0
 public virtual void EraseDriveSpace(Stream stream, IPrng prng,
                                     ErasureMethodProgressFunction callback)
 {
     Erase(stream, long.MaxValue, prng, callback);
 }
Пример #9
0
        private void saveSettings_Click(object sender, EventArgs e)
        {
            EraserSettings settings = EraserSettings.Get();

            //Save the settings that don't fail first.
            Host.Instance.Settings.ForceUnlockLockedFiles = lockedForceUnlock.Checked;
            ManagerLibrary.Instance.Settings.ExecuteMissedTasksImmediately =
                schedulerMissedImmediate.Checked;
            settings.ClearCompletedTasks = schedulerClearCompleted.Checked;

            bool pluginApprovalsChanged = false;
            IDictionary <Guid, bool> pluginApprovals =
                ManagerLibrary.Instance.Settings.PluginApprovals;

            foreach (ListViewItem item in pluginsManager.Items)
            {
                PluginInfo plugin = (PluginInfo)item.Tag;
                Guid       guid   = plugin.AssemblyInfo.Guid;
                if (!pluginApprovals.ContainsKey(guid))
                {
                    if (plugin.Loaded != item.Checked)
                    {
                        pluginApprovals.Add(guid, item.Checked);
                        pluginApprovalsChanged = true;
                    }
                }
                else if (pluginApprovals[guid] != item.Checked)
                {
                    pluginApprovals[guid]  = item.Checked;
                    pluginApprovalsChanged = true;
                }
            }

            if (pluginApprovalsChanged)
            {
                MessageBox.Show(this, S._("Plugins which have just been approved will only be loaded " +
                                          "the next time Eraser is started."), S._("Eraser"), MessageBoxButtons.OK,
                                MessageBoxIcon.Information, MessageBoxDefaultButton.Button1,
                                Localisation.IsRightToLeft(this) ?
                                MessageBoxOptions.RtlReading | MessageBoxOptions.RightAlign : 0);
            }

            //Error checks for the rest that do.
            errorProvider.Clear();
            if (uiLanguage.SelectedIndex == -1)
            {
                errorProvider.SetError(uiLanguage, S._("An invalid language was selected."));
                return;
            }
            else if (eraseFilesMethod.SelectedIndex == -1)
            {
                errorProvider.SetError(eraseFilesMethod, S._("An invalid file erasure method " +
                                                             "was selected."));
                return;
            }
            else if (eraseDriveMethod.SelectedIndex == -1)
            {
                errorProvider.SetError(eraseDriveMethod, S._("An invalid drive erasure method " +
                                                             "was selected."));
                return;
            }
            else if (erasePRNG.SelectedIndex == -1)
            {
                errorProvider.SetError(erasePRNG, S._("An invalid randomness data source was " +
                                                      "selected."));
                return;
            }
            else if (plausibleDeniability.Checked && plausibleDeniabilityFiles.Items.Count == 0)
            {
                errorProvider.SetError(plausibleDeniabilityFiles, S._("Erasures with plausible deniability " +
                                                                      "was selected, but no files were selected to be used as decoys."));
                errorProvider.SetIconPadding(plausibleDeniabilityFiles, -16);
                return;
            }

            if (CultureInfo.CurrentUICulture.Name != ((CultureInfo)uiLanguage.SelectedItem).Name)
            {
                settings.Language = ((CultureInfo)uiLanguage.SelectedItem).Name;
                MessageBox.Show(this, S._("The new UI language will take only effect when " +
                                          "Eraser is restarted."), S._("Eraser"), MessageBoxButtons.OK,
                                MessageBoxIcon.Information, MessageBoxDefaultButton.Button1,
                                Localisation.IsRightToLeft(this) ?
                                MessageBoxOptions.RtlReading | MessageBoxOptions.RightAlign : 0);
            }
            settings.IntegrateWithShell = uiContextMenu.Checked;

            Host.Instance.Settings.DefaultFileErasureMethod =
                ((IErasureMethod)eraseFilesMethod.SelectedItem).Guid;
            Host.Instance.Settings.DefaultDriveErasureMethod =
                ((IErasureMethod)eraseDriveMethod.SelectedItem).Guid;

            IPrng newPRNG = (IPrng)erasePRNG.SelectedItem;

            if (newPRNG.Guid != Host.Instance.Prngs.ActivePrng.Guid)
            {
                MessageBox.Show(this, S._("The new randomness data source will only be used when " +
                                          "the next task is run.\nCurrently running tasks will use the old source."),
                                S._("Eraser"), MessageBoxButtons.OK, MessageBoxIcon.Information,
                                MessageBoxDefaultButton.Button1,
                                Localisation.IsRightToLeft(this) ?
                                MessageBoxOptions.RtlReading | MessageBoxOptions.RightAlign : 0);
                Host.Instance.Settings.ActivePrng = newPRNG.Guid;
            }

            Host.Instance.Settings.PlausibleDeniability = plausibleDeniability.Checked;
            IList <string> plausibleDeniabilityFilesList = Host.Instance.Settings.PlausibleDeniabilityFiles;

            plausibleDeniabilityFilesList.Clear();
            foreach (string str in this.plausibleDeniabilityFiles.Items)
            {
                plausibleDeniabilityFilesList.Add(str);
            }
        }
Пример #10
0
 public void Erase(Stream strm, long erasureLength, IPrng prng,
                   ErasureMethodProgressFunction callback)
 {
     throw new InvalidOperationException("The DefaultMethod class should never " +
                                         "be used and should instead be replaced before execution!");
 }
Пример #11
0
        /// <summary>
        /// Writes a file for plausible deniability over the current stream.
        /// </summary>
        /// <param name="stream">The stream to write the data to.</param>
        private void DeleteFileWithPlausibleDeniability(FileInfo info)
        {
            ObfuscateFileSystemInfoName(info);

            //Get the template file to copy
            FileInfo shadowFileInfo;

            {
                string        shadowFile = null;
                List <string> entries    = new List <string>(
                    Host.Instance.Settings.PlausibleDeniabilityFiles);
                IPrng prng = Host.Instance.Prngs.ActivePrng;
                do
                {
                    if (entries.Count == 0)
                    {
                        throw new FatalException(S._("Plausible deniability was selected, " +
                                                     "but no decoy files were found. The current file has been only " +
                                                     "replaced with random data."));
                    }

                    //Get an item from the list of files, and then check that the item exists.
                    int index = prng.Next(entries.Count - 1);
                    shadowFile = entries[index];
                    if (File.Exists(shadowFile) || Directory.Exists(shadowFile))
                    {
                        if ((File.GetAttributes(shadowFile) & FileAttributes.Directory) != 0)
                        {
                            DirectoryInfo dir   = new DirectoryInfo(shadowFile);
                            FileInfo[]    files = dir.GetFiles("*", SearchOption.AllDirectories);
                            entries.Capacity += files.Length;
                            foreach (FileInfo f in files)
                            {
                                entries.Add(f.FullName);
                            }
                            shadowFile = null;
                        }
                        else
                        {
                            shadowFile = entries[index];
                        }
                    }
                    else
                    {
                        shadowFile = null;
                    }

                    entries.RemoveAt(index);
                }while (string.IsNullOrEmpty(shadowFile));
                shadowFileInfo = new FileInfo(shadowFile);
            }

            //Copy the contents of the shadow.
            using (Stream stream = info.OpenWrite())
            {
                //Dump the copy (the first 4MB, or less, depending on the file size and size of
                //the original file)
                long amountToCopy = Math.Min(4 * 1024 * 1024, shadowFileInfo.Length);
                using (FileStream shadowFileStream = shadowFileInfo.Open(
                           FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                {
                    while (stream.Position < amountToCopy)
                    {
                        byte[] buf       = new byte[524288];
                        int    bytesRead = shadowFileStream.Read(buf, 0, buf.Length);

                        //Stop bothering if the input stream is at the end
                        if (bytesRead == 0)
                        {
                            break;
                        }

                        //Dump the read contents onto the file to be deleted
                        stream.Write(buf, 0,
                                     (int)Math.Min(bytesRead, amountToCopy - stream.Position));
                    }
                }

                //Make the file to be deleted have the same length as the file
                //which is being used as a decoy. The end of the file might contain
                //noise, which should make the decoy more convincing.
                stream.SetLength(shadowFileInfo.Length);
            }

            //Make the file to be deleted look like the shadow.
            info.MoveTo(Path.Combine(info.DirectoryName, shadowFileInfo.Name));
            if (shadowFileInfo.IsCompressed())
            {
                info.Compress();
            }
            info.SetAccessControl(shadowFileInfo.GetAccessControl());
            info.Attributes = shadowFileInfo.Attributes;
            info.CopyTimes(shadowFileInfo);

            //Just delete the file.
            info.Delete();
        }
Пример #12
0
 /// <summary>
 /// Create a new RandomizedList of type T
 /// </summary>
 /// <param name="prng">A class that implements IPrng and can create strong pseduo-random numbers</param>
 public RandomizedList(IPrng prng)
 {
     Prng = prng;
 }