// Helper methods protected void LoadOuterManifest() { if (InnerProxy.Manifest.RootDirectory.Files.ContainsKey( DefaultOuterManifestFileName) == false) { throw new Exception("Encrypted manifest is not present."); } ManifestFileInfo outerManifestManifestFileInfo = InnerProxy.Manifest.RootDirectory.Files[ DefaultOuterManifestFileName]; FileInfo outerManifestFileInfo = InnerProxy.GetFile(outerManifestManifestFileInfo); Stream outerManifestFileStream = outerManifestFileInfo.OpenRead(); byte[] outerKeyBytes = CryptUtilities.MakeKeyBytesFromString( OuterKeyString, InnerProxy.Manifest.Guid.ToByteArray()); Stream outerManifestCryptoStream = CryptUtilities.MakeDecryptionReadStreamFrom( outerManifestFileStream, outerKeyBytes); OuterManifest = Manifest.ReadManifestStream(outerManifestCryptoStream); outerManifestCryptoStream.Close(); }
public FileInfo CloneFile( ManifestFileInfo copyFile, DirectoryInfo copyToDirectory) { ManifestFileInfo innerManifestFileInfo = HashToInnerFileMap[copyFile.FileHash]; FileInfo innerFileInfo = InnerProxy.GetFile(innerManifestFileInfo); byte[] keyData = CryptUtilities.MakeKeyBytesFromString( OuterKeyString, copyFile.FileHash.HashData); String destFilePath = Path.Combine( copyToDirectory.FullName, DefaultDecryptedTempFileName); ReadCryptFile( innerFileInfo, keyData, destFilePath); FileInfo fileInfo = new FileInfo(destFilePath); // Make sure that the last-modified date matches that of the // expected outer file. This is necessary because one inner file // may correspond to several outer files - each of which might // have separate dates. fileInfo.LastWriteTimeUtc = copyFile.LastModifiedUtc; return(fileInfo); }
protected void SaveOuterManifest() { // Serialize the manifest to memory MemoryStream serializedManifestStream = new MemoryStream(); OuterManifest.WriteManifestStream(serializedManifestStream); serializedManifestStream.Position = 0; String tempFilePath = Path.Combine( InnerProxy.TempDirectory.FullName, DefaultOuterManifestFileName); // We use the inner GUID as salt for the outer manifest, so update // it each time we write the outer manifest. The inner GUID is // really useless anyways. InnerProxy.Manifest.ChangeGUID(); byte[] outerKeyData = CryptUtilities.MakeKeyBytesFromString( OuterKeyString, InnerProxy.Manifest.Guid.ToByteArray()); byte[] cryptHash = WriteCryptFileAndHash( serializedManifestStream, outerKeyData, tempFilePath); // The new ManifestFileInfo is actually rooted in the inner // Manifest object, but that is ok - although it is kind of a // hack. The fact is that we don't maintain an actual Manifest // object to mirror the inner manifest - and we know that the // implementation of PutFile won't be affected by doing this. ManifestDirectoryInfo parentDirectory = InnerProxy.Manifest.RootDirectory; ManifestFileInfo destManifestFile = new ManifestFileInfo( DefaultOuterManifestFileName, parentDirectory); destManifestFile.RegisteredUtc = DateTime.Now; FileInfo outerManifestFileInfo = new FileInfo(tempFilePath); destManifestFile.LastModifiedUtc = outerManifestFileInfo.LastWriteTimeUtc; destManifestFile.FileLength = outerManifestFileInfo.Length; destManifestFile.FileHash = new FileHash(cryptHash, CryptUtilities.DefaultHashType); InnerProxy.PutFile(ProxyToInner, destManifestFile); }
protected void ValidateFile( ManifestFileInfo outerManFileInfo, Utilities.Console console) { ManifestFileInfo innerManifestFileInfo = null; try { innerManifestFileInfo = HashToInnerFileMap[outerManFileInfo.FileHash]; FileInfo innerFileInfo = InnerProxy.GetFile(innerManifestFileInfo); byte[] keyData = CryptUtilities.MakeKeyBytesFromString( OuterKeyString, outerManFileInfo.FileHash.HashData); Stream sourceFileStream = innerFileInfo.OpenRead(); Stream cryptoStream = CryptUtilities.MakeDecryptionReadStreamFrom( sourceFileStream, keyData); FileHash computedHash = FileHash.ComputeHash( cryptoStream, outerManFileInfo.FileHash.HashType); if (computedHash.Equals(outerManFileInfo.FileHash) == false) { throw new Exception("FAILED VALIDATION"); } } catch (Exception e) { console.WriteLine( Manifest.MakeStandardPathString(outerManFileInfo)); console.WriteLine( Manifest.MakeNativePathString(innerManifestFileInfo)); console.WriteLine(e.Message); console.WriteLine(); } }
/// <summary> /// Get rid of temp directory and cleanup orphaned files. /// </summary> public void CleanupBeforeExit() { if (myReadOnly == false && TempDirectory != null) { SaveOuterManifest(); // Removed orphaned data files ResolveInnerOuter(); foreach (ManifestFileInfo nextFile in OrphanedInnerFiles) { InnerProxy.RemoveFile(nextFile); } TempDirectory.Delete(true); TempDirectory = null; InnerProxy.CleanupBeforeExit(); } }
public void PutFile( IRepositoryProxy sourceRepository, ManifestFileInfo sourceManifestFile) { // Name the inner file with the hash of the hash. We protect // the hash in this way because it is used as the salt to // encrypt the data in the file, and it might provide some // benefit to a cryptographic attack. FileHash hashedHash = FileHash.ComputeHash( sourceManifestFile.FileHash.HashData); String hashedHashString = hashedHash.ToString(); // Only add the file data if we don't have it already. if (myHashedStringMap.ContainsKey(hashedHashString) == false) { FileInfo sourceFileInfo = sourceRepository.GetFile(sourceManifestFile); byte[] keyData = CryptUtilities.MakeKeyBytesFromString( OuterKeyString, sourceManifestFile.FileHash.HashData); // Use the inner proxy temp directory because that is likely // the ultimate destination of the file and we don't want to // copy the data if we can avoid it. This is a minor break in // encapsulation but has a significant impact on performance. String destFilePath = Path.Combine( InnerProxy.TempDirectory.FullName, hashedHashString); Stream sourceFileStream = sourceFileInfo.OpenRead(); byte[] cryptHash = WriteCryptFileAndHash( sourceFileStream, keyData, destFilePath); FileInfo cryptFileInfo = new FileInfo(destFilePath); // Make a dummy parent manifest directory to give to the inner // proxy. This is actually rooted in the inner manifest, but // that is ok - although it is kind of a hack. The fact is // that we don't maintain an actual manifest to mirror the // inner manifest - and we know that the implementation of // PutFile won't be affected by doing this. ManifestDirectoryInfo parentDirectory = MakeInnerParentDirectory( hashedHashString, InnerProxy.Manifest.RootDirectory); ManifestFileInfo destManifestFile = new ManifestFileInfo( hashedHashString, parentDirectory); destManifestFile.RegisteredUtc = DateTime.UtcNow; destManifestFile.LastModifiedUtc = cryptFileInfo.LastWriteTimeUtc; destManifestFile.FileLength = cryptFileInfo.Length; destManifestFile.FileHash = new FileHash(cryptHash, CryptUtilities.DefaultHashType); InnerProxy.PutFile(ProxyToInner, destManifestFile); myHashedStringMap.Add(hashedHashString, destManifestFile); myNeedToRegenerateFileMap = true; } ManifestFileInfo outerManifestFileInfo = Manifest.PutFileFromOtherManifest(sourceManifestFile); myManifestChanged = true; }