public FileMeta3 GetFileMeta() { byte metaTag = this._binaryReader.ReadByte(); if (metaTag != 0x42) { throw new InvalidDataException($"File {this._fileItem.Name} fails to extract meta"); } IFileStreamHandler <IDictionary <string, object> > metaHandler = this._handlerFactory.GetHandler <IDictionary <string, object> >(metaTag); IDictionary <string, object> metaDict = metaHandler.Handle(this._binaryReader); if (!(metaDict.ContainsKey("type") && "metadata".Equals(metaDict["type"]))) { throw new InvalidDataException($"File {this._fileItem.Name} fails to extract meta"); } return(FileMeta3.fromDictionary(metaDict)); }
public bool ProcessFile(string sourcePath, string destDir, bool respectFileNameInMeta = true) { string destPath = null; try { FileItem fi = new FileItem(sourcePath); using (CloudSyncFile cloudSyncFile = new CloudSyncFile(fi, _handlerFactory)) { cloudSyncFile.InitParsing(); FileMeta3 fileMeta = cloudSyncFile.GetFileMeta(); //Generate session key and make sure it matches the file byte[] sessionKeyComputed = CryptoUtils.RsaOaepDeciper(fileMeta.EncKey2, this._cloudSyncKey.KeyPair.Private); string sessionKeyHashStrComputed = CryptoUtils.SaltedMd5( fileMeta.SessionKeyHash.Substring(0, 10), sessionKeyComputed); if (!fileMeta.SessionKeyHash.Equals(sessionKeyHashStrComputed)) { throw new InvalidDataException($"File {fi.Name}, Computed session key is incorrect."); } //decrypt content byte[] sessionKeyBytes = BytesUtils.HexStringToByteArray( Encoding.ASCII.GetString(sessionKeyComputed)); ParametersWithIV keys = CryptoUtils.DeriveAESKeyParameters(sessionKeyBytes, null); AesCbcCryptor decryptor = new AesCbcCryptor(((KeyParameter)keys.Parameters).GetKey(), keys.GetIV()); destPath = Path.Join(destDir, respectFileNameInMeta ? fileMeta.FileName : Path.GetFileName(sourcePath)); using (var hasher = MD5.Create()) { using (AesCryptoServiceProvider aes = new AesCryptoServiceProvider()) { aes.Mode = CipherMode.CBC; aes.Key = ((KeyParameter)keys.Parameters).GetKey(); aes.IV = keys.GetIV(); //Stopwatch stopwatch = new Stopwatch(); //stopwatch.Start(); //byte[] buffer = new byte[1024 * 1024]; long bytesRead = 0; ICryptoTransform decoder = aes.CreateDecryptor(); using (CloudSyncPayloadStream cspls = new CloudSyncPayloadStream(cloudSyncFile.GetDataBlocks(decryptor))) using (CryptoStream aesStream = new CryptoStream(cspls, decoder, CryptoStreamMode.Read)) using (LZ4DecoderStream lz4ds = LZ4Stream.Decode(aesStream)) using (FileStream writeFs = new FileStream(destPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite, 1024 * 1024)) using (CryptoStream md5HashStream = new CryptoStream(writeFs, hasher, CryptoStreamMode.Write)) { lz4ds.CopyTo(md5HashStream, 1024 * 1024); // int read; // while ((read = md5HashStream.Read(buffer, 0, buffer.Length)) > 0) // { // //do nothing // bytesRead += read; // long elapsed = stopwatch.ElapsedMilliseconds; // if (elapsed > 1000) // { // double readInM = (double) bytesRead / 1024.0 / 1024.0/elapsed*1000.0; // bytesRead = 0; // Console.WriteLine($"Speed:{readInM} M/s"); // stopwatch.Reset(); // stopwatch.Start(); // } // } } //stopwatch.Stop(); if (!cloudSyncFile.VerifyContentHash(hasher.Hash)) { throw new InvalidDataException("File Md5 doesn't match."); } } } return(true); } } catch (Exception ex) { if (File.Exists(destPath)) { File.Delete(destPath); } this._exceptionHandler.Handle(ex); } return(false); }
public static FileMeta3 fromDictionary(IDictionary <string, object> dict) { FileMeta3 instance = new FileMeta3(); foreach (KeyValuePair <string, object> entry in dict) { switch (entry.Key) { case "compress": instance.Compress = (int)entry.Value > 0; break; case "digest": instance.Digest = (string)entry.Value; break; case "enc_key1": instance.EncKey1 = Convert.FromBase64String((string)entry.Value); break; case "enc_key2": instance.EncKey2 = Convert.FromBase64String((string)entry.Value); break; case "encrypt": instance.Encrypt = (int)entry.Value > 0; break; case "file_name": instance.FileName = (string)entry.Value; break; case "key1_hash": instance.Key1Hash = (string)entry.Value; break; case "key2_hash": instance.Key2Hash = (string)entry.Value; break; case "salt": instance.Salt = (string)entry.Value; break; case "session_key_hash": instance.SessionKeyHash = (string)entry.Value; break; case "version": IDictionary <string, object> versionDict = (IDictionary <string, object>)entry.Value; int major = (int)versionDict["major"]; int minor = (int)versionDict["minor"]; instance.Version = new FileVersion(major, minor); break; default: //TODO log not supported key break; } } return(instance); }