public static DirectoryHeader Load(string filePath, DerivedBytesProvider derivedBytesProvider) { DirectoryHeader directoryHeader = new DirectoryHeader(); using Stream streamIn = File.OpenRead(filePath); using HelixFileDecryptor decryptor = new HelixFileDecryptor(streamIn); decryptor.Initialize(derivedBytesProvider); directoryHeader.FileVersion = decryptor.FileVersion; directoryHeader.Header = decryptor.ReadHeader(); directoryHeader.FileVersion = decryptor.FileVersion; var contentSerialized = decryptor.GetContentString(); //var contentDeserialized = JsonConvert.DeserializeAnonymousType(contentSerialized, new { EncryptedFileNameSalt = new byte[] { } }); JsonConvert.PopulateObject(contentSerialized, directoryHeader); if (!Regex.IsMatch(directoryHeader.DirectoryId, "^[0-9A-F]{32}$")) { throw new HelixException("Data curruption directory header, DirectoryId malformed"); } if (directoryHeader.FileNameKey == null || directoryHeader.FileNameKey.Length != 32) { throw new HelixException("Data curruption directory header, FileNameKey missing or insufficient length"); } return(directoryHeader); }
/// <summary> /// Returns the header for an encrypted file /// </summary> public static FileEntry DecryptHeader(string encrFile, DerivedBytesProvider derivedBytesProvider) { using var inputStream = File.OpenRead(encrFile); using var decryptor = new HelixFileDecryptor(inputStream); try { decryptor.Initialize(derivedBytesProvider); FileEntry header = decryptor.ReadHeader(); if (!header.IsValid(out HeaderCorruptionException ex)) { throw ex; } return(header); } catch (FileCorruptionException ex) { throw new FileCorruptionException($"Failed to decrypt {encrFile}, {ex.Message}", ex); } catch (AuthenticatedEncryptionException ex) { throw new FileCorruptionException($"Failed to decrypt {encrFile}, {ex.Message}", ex); } }
public static int Inspect(InspectOptions options, ConsoleEx consoleEx = null) { if (options == null) { throw new ArgumentNullException(nameof(options)); } consoleEx ??= new ConsoleEx(); using (Stream fileIn = File.OpenRead(options.File)) using (HelixFileDecryptor decryptor = new HelixFileDecryptor(fileIn)) { consoleEx.WriteLine("== Outer Header =="); Dictionary <string, byte[]> header = null; decryptor.Initialize(DerivedBytesProvider.FromPassword(options.Password, options.KeyFile), (h) => header = h); consoleEx.WriteLine("Designator: " + BitConverter.ToString(header[nameof(FileHeader.fileDesignator)]).Replace("-", "") + " (" + new string(Encoding.ASCII.GetString(header[nameof(FileHeader.fileDesignator)]) .Select(c => Char.IsControl(c) ? '?' : c) .ToArray()) + ")"); consoleEx.WriteLine("Password Salt: " + BitConverter.ToString(header[nameof(FileHeader.passwordSalt)]).Replace("-", "")); consoleEx.WriteLine("HMAC Salt: " + BitConverter.ToString(header[nameof(FileHeader.hmacSalt)]).Replace("-", "")); consoleEx.WriteLine("IV: " + BitConverter.ToString(header[nameof(FileHeader.iv)]).Replace("-", "")); consoleEx.WriteLine("Authn (HMAC): " + BitConverter.ToString(header[nameof(FileHeader.headerAuthnDisk)]).Replace("-", "")); consoleEx.WriteLine(); consoleEx.WriteLine("== Inner Header =="); decryptor.ReadHeader( afterRawMetadata: (r) => consoleEx.WriteLine(JsonFormat(r))); consoleEx.WriteLine(); using Stream content = decryptor.GetContentStream(); ContentPreview(content, consoleEx, options.ContentFormat); consoleEx.WriteLine(); } //Reopen to calculate the checksum using (Stream fileIn = File.OpenRead(options.File)) using (HelixFileDecryptor decryptor = new HelixFileDecryptor(fileIn)) { decryptor.Initialize(DerivedBytesProvider.FromPassword(options.Password, options.KeyFile)); decryptor.ReadHeader(); using Stream content = decryptor.GetContentStream(); Checksum(content, consoleEx); return(0); } }
public static string Decrypt(string encrPath, string decrPath, DerivedBytesProvider derivedBytesProvider, FileDecryptOptions options = null) { if (string.IsNullOrWhiteSpace(encrPath)) { throw new ArgumentNullException(nameof(encrPath)); } if (string.IsNullOrWhiteSpace(decrPath)) { throw new ArgumentNullException(nameof(decrPath)); } if (derivedBytesProvider == null) { throw new ArgumentNullException(nameof(derivedBytesProvider)); } options ??= new FileDecryptOptions(); using (FileStream inputStream = File.OpenRead(encrPath)) using (HelixFileDecryptor decryptor = new HelixFileDecryptor(inputStream)) { decryptor.Initialize(derivedBytesProvider); FileEntry header = decryptor.ReadHeader(); options?.AfterMetadataRead?.Invoke(header, options); if (!header.IsValid(out HeaderCorruptionException ex)) { throw ex; } string decrFullFileName = decrPath; string decrStagedFileName = decrPath + HelixConsts.StagedHxExtention; string decrBackupFileName = decrPath + HelixConsts.BackupExtention; if (header.EntryType == FileEntryType.File) { if (!string.IsNullOrEmpty(Path.GetDirectoryName(decrStagedFileName))) { Directory.CreateDirectory(Path.GetDirectoryName(decrStagedFileName)); } using (var contentStream = decryptor.GetContentStream()) using (var stagedFile = File.OpenWrite(decrStagedFileName)) { contentStream.CopyTo(stagedFile); } File.SetLastWriteTimeUtc(decrStagedFileName, header.LastWriteTimeUtc); if (File.Exists(decrFullFileName)) { File.Move(decrFullFileName, decrBackupFileName); } else if (Directory.Exists(decrFullFileName)) { if (Directory.GetFiles(decrFullFileName).Length > 0) { throw new IOException($"Unable to process entry, directory is not empty ({decrFullFileName})"); } Directory.Move(decrFullFileName, decrBackupFileName); } File.Move(decrStagedFileName, decrFullFileName); if (File.Exists(decrBackupFileName)) { File.SetAttributes(decrBackupFileName, FileAttributes.Normal); //incase it was read only File.Delete(decrBackupFileName); } else if (Directory.Exists(decrBackupFileName)) { Directory.Delete(decrBackupFileName); } } else if (header.EntryType == FileEntryType.Directory) { if (File.Exists(decrFullFileName)) { File.Move(decrFullFileName, decrBackupFileName); } if (Directory.Exists(decrFullFileName)) { //If there is a case difference need to delete the directory if (Path.GetFileName(decrFullFileName) != Path.GetFileName(new DirectoryInfo(decrFullFileName).Name)) { if (Directory.GetFiles(decrFullFileName).Length > 0) { throw new IOException($"Unable to process entry, directory is not empty ({decrFullFileName})"); } Directory.Move(decrFullFileName, decrBackupFileName); } } Directory.CreateDirectory(decrFullFileName); } else //purge or delete { if (File.Exists(decrFullFileName)) { File.Move(decrFullFileName, decrBackupFileName); } else if (Directory.Exists(decrFullFileName)) { if (Directory.GetFiles(decrFullFileName).Length > 0) { throw new IOException($"Unable to process entry, directory is not empty ({decrFullFileName})"); } Directory.Move(decrFullFileName, decrBackupFileName); } } if (File.Exists(decrBackupFileName)) { File.Delete(decrBackupFileName); } else if (Directory.Exists(decrBackupFileName)) { Directory.Delete(decrBackupFileName); } } return(decrPath); }