private void ParseFile() { var directory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); var path = $"{directory}\\Resources\\crypto\\encrypted_jpg_01.jpg"; string magic = "__CLOUDSYNC_ENC__"; byte[] magicBytes = Encoding.ASCII.GetBytes(magic); using FileStream fs = new FileStream(path, FileMode.Open); using BinaryReader br = new BinaryReader(fs); byte[] value = br.ReadBytes(magicBytes.Length); Console.WriteLine(ByteArrayCompare(magicBytes, value)); //check "__CLOUDSYNC_ENC__" Md5 hash value = br.ReadBytes(32); byte[] expectedMagicHash = Encoding.ASCII.GetBytes(BytesUtils.ByteArrayToLowerHexString(Md5(magicBytes))); Assert.AreEqual(expectedMagicHash, value); // HandlerFactory handlerFactory = new HandlerFactory(); StringHandler stringHandler = new StringHandler(); IntHandler intHandler = new IntHandler(); ByteSteamHandler byteSteamHandler = new ByteSteamHandler(); OrderedDictHandler dictHandler = new OrderedDictHandler(handlerFactory); handlerFactory.AddHandler(stringHandler); handlerFactory.AddHandler(dictHandler); handlerFactory.AddHandler(intHandler); handlerFactory.AddHandler(byteSteamHandler); byte metaTag = br.ReadByte(); if (metaTag != 0x42) { throw new InvalidDataException(); } IFileStreamHandler <IDictionary <string, object> > metaHandler = handlerFactory.GetHandler <IDictionary <string, object> >(metaTag); IDictionary <string, object> metaDict = metaHandler.Handle(br); if (!(metaDict.ContainsKey("type") && "metadata".Equals(metaDict["type"]))) { throw new InvalidDataException(); } FileMeta3 fileMeta = FileMeta3.fromDictionary(metaDict); Console.WriteLine(fileMeta); AsymmetricKeyParameter akp = CryptoUtils.readPemPk(this.privateKey); byte[] sessionKeyCharArray = CryptoUtils.RsaOaepDeciper(fileMeta.EncKey2, akp); string computedSessionKeyHash = CryptoUtils.SaltedMd5( fileMeta.SessionKeyHash.Substring(0, 10), sessionKeyCharArray); if (!fileMeta.SessionKeyHash.Equals(computedSessionKeyHash)) { throw new InvalidDataException("key is incorrect"); } //decrypt content byte[] sessionKey = BytesUtils.HexStringToByteArray( Encoding.ASCII.GetString(sessionKeyCharArray)); Console.Write(sessionKey); ParametersWithIV keys = CryptoUtils.DeriveAESKeyParameters(sessionKey, null); AesCbcCryptor decryptor = new AesCbcCryptor(((KeyParameter)keys.Parameters).GetKey(), keys.GetIV()); List <byte[]> decryptedData = new List <byte[]>(); byte[] buf = null; byte[] decBuf = null; IDictionary <string, object> dataResult = null; while (true) { byte dataTag = br.ReadByte(); if (dataTag == 0x40) { Console.WriteLine("come here"); } if (dataTag != 0x42) { decBuf = decryptor.DecryptBlock(buf, true); decryptedData.Add(decBuf); break; } if (buf != null) { decBuf = decryptor.DecryptBlock(buf, false); decryptedData.Add(decBuf); } IFileStreamHandler <IDictionary <string, object> > dataHandler = handlerFactory.GetHandler <IDictionary <string, object> >(metaTag); dataResult = dataHandler.Handle(br); object typeValue = null; dataResult.TryGetValue("type", out typeValue); string typeValueString = typeValue as string; if (!"data".Equals(typeValueString)) { break; } buf = (byte[])dataResult["data"]; } byte[] decData = CryptoUtils.Concat(decryptedData.ToArray()); File.WriteAllBytes("z:\\123.jpg.lz4", decData); //last directory //TODO validate dataResult["type"] == "metadata" string fileMd5 = (string)dataResult["file_md5"]; Console.Write(fileMd5); }
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); }