/// <summary> /// Create an AES helper based on a previously saved keyfile and a password to decrypt it /// </summary> /// <param name="file"></param> /// <param name="password"></param> /// <returns></returns> public static AesHelper CreateFromKeyFile(byte[] file, string password) { Dictionary <string, byte[]> savedobjects = BinaryEncoding.dict_decode(file); var phasher = new Rfc2898DeriveBytes(password, savedobjects["passwordsalt-v1"]); var datakeykey = phasher.GetBytes(16); var phashhasher = new Rfc2898DeriveBytes(datakeykey, savedobjects["datakeykeyhashsalt-v1"], 8192); var phashhash = phashhasher.GetBytes(IVSize); if (phashhash.SequenceEqual(savedobjects["datakeykeyhash-v1"])) { return(new AesHelper(datakeykey, savedobjects["passwordsalt-v1"], savedobjects["datakeykeyhash-v1"], savedobjects["datakeykeyhashsalt-v1"], DecryptAesDataKey(savedobjects["encrypteddatakey-v1"], datakeykey, savedobjects["datakeyiv-v1"]), savedobjects["datakeyiv-v1"])); } else { throw new PasswordIncorrectException("The password used to decrypt the keyfile " + "does not match the file used to creat it."); } }
/// <summary> /// Store this node and its descendents in a blobstore /// Breaks with circular references, but these should only occur /// with hard- (and soft-?) -links TODO: handle links /// </summary> /// <param name="blobs"></param> /// <param name="storeGetHash">Function called to store node data, returns hash</param> /// <returns>The hash of the stored tree and a tree of its child hashes.</returns> public (byte[] nodehash, HashTreeNode node) Store(Func <byte[], byte[]> storeGetHash) { List <(byte[] nodehash, HashTreeNode node)> children = new List <(byte[] nodehash, HashTreeNode node)>(); List <byte[]> dirhashes = new List <byte[]>(); foreach (MetadataNode dir in Directories.Values) { var(newhash, newnode) = dir.Store(storeGetHash); dirhashes.Add(newhash); children.Add((newhash, newnode)); } foreach (var fm in Files.Values.AsEnumerable()) { children.Add((fm.FileHash, null)); } Dictionary <string, byte[]> mtdata = new Dictionary <string, byte[]>(); // -"-v1" // DirMetadata = FileMetadata DirMetadata.serialize() // Directories = enum_encode([Directories.Values MetadataNode.serialize(),... ]) // Files = enum_encode([Files.Values FileMetadata.serialize(),... ]) // -"-v2" // Directories = enum_encode([dirrefs,...]) // "-v3" // DirectoriesMultiblock = enum_encode([BitConverter.GetBytes(multiblock),...]) // -v4 // removed DirectoriesMultiblock mtdata.Add("DirMetadata-v1", DirMetadata.serialize()); mtdata.Add("Files-v1", BinaryEncoding.enum_encode(Files.Values.AsEnumerable() .Select(fm => fm.serialize()))); mtdata.Add("Directories-v2", BinaryEncoding.enum_encode(dirhashes)); byte[] nodehash = storeGetHash(BinaryEncoding.dict_encode(mtdata)); HashTreeNode node = new HashTreeNode(children); return(nodehash, node); }
public static BlobLocation deserialize(byte[] data) { Dictionary <string, byte[]> savedobjects = BinaryEncoding.dict_decode(data); byte[]? encryptedHash = savedobjects["EncryptedHash-v9"].Length == 0 ? null : savedobjects["EncryptedHash-v9"]; string relfilepath = Encoding.UTF8.GetString(savedobjects["RelativeFilePath-v1"]); int bytelength = BitConverter.ToInt32(savedobjects["ByteLength-v1"], 0); var encodedBackupSets = BinaryEncoding.enum_decode(savedobjects["BSetReferenceCounts.BackupSets-v5"]); if (encodedBackupSets == null) { throw new Exception("Backup sets are required"); } List <BackupSetKey> backupsets = new List <BackupSetKey>(); foreach (var bin in encodedBackupSets) { if (bin == null) { throw new Exception("Backup sets cannot be null"); } backupsets.Add(BackupSetKey.decode(bin)); } List <byte[]?>?encodedRefCounts = BinaryEncoding.enum_decode(savedobjects["BSetReferenceCounts.ReferenceCounts-v5"]); if (encodedRefCounts == null) { throw new Exception("Reference counts are required"); } List <int> referencecounts = new List <int>(); foreach (var bin in encodedRefCounts) { if (bin == null) { throw new Exception("Reference counts cannot be null"); } referencecounts.Add(BitConverter.ToInt32(bin, 0)); } Dictionary <BackupSetKey, int> bsrc = new Dictionary <BackupSetKey, int>(); for (int i = 0; i < backupsets.Count; i++) { bsrc[backupsets[i]] = referencecounts[i]; } var multiblock = BitConverter.ToBoolean(savedobjects["IsMultiBlockReference-v7"], 0); List <byte[]>?childhashes = null; if (multiblock) { childhashes = new List <byte[]>(); var binchildhashes = BinaryEncoding.enum_decode(savedobjects["BlockHashes-v8"]); if (binchildhashes == null) { throw new Exception("Multiblock blobs must have child hashes"); } foreach (var bin in binchildhashes) { if (bin == null) { throw new Exception("Child hashes cannot be null"); } childhashes.Add(bin); } } return(new BlobLocation(encryptedHash, relfilepath, bytelength, childhashes, bsrc)); }