public void TestAesStream() { var baseStream = new MemoryStream(); var key = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; var encryptStream = new AesStream(baseStream, key); var plaintext = Encoding.UTF8.GetBytes("Hello, world!"); encryptStream.Write(plaintext, 0, plaintext.Length); baseStream.Seek(0, SeekOrigin.Begin); var decryptStream = new AesStream(baseStream, key); byte[] buffer = new byte[plaintext.Length]; decryptStream.Read(buffer, 0, buffer.Length); Assert.AreEqual("Hello, world!", Encoding.UTF8.GetString(buffer)); }
public void AesStreamWrite() { var data = Encoding.ASCII.GetBytes("Hello"); Assert.IsTrue(data.ToArray().SequenceEqual(new byte[] { 72, 101, 108, 108, 111 })); var password = SecurityHelper.ToSecureString("MyPassword"); using (var baseStream = new MemoryStream()) using (var aesStream = new AesStream(baseStream, password, SecurityHelper.GetSaltKeys(password).GetBytes(16))) { aesStream.Write(data, 0, data.Length); aesStream.Position = 0; var cryptedData = new byte[baseStream.Length]; baseStream.Read(cryptedData, 0, cryptedData.Length); Assert.IsTrue(cryptedData.ToArray().SequenceEqual(new byte[] { 238, 75, 117, 248, 55 })); } }
/// <summary> /// Read a specified clipboard data, encrypt and save it into a file. /// </summary> /// <param name="clipboardReader">The <see cref="ClipboardReader"/> used to read the data.</param> /// <param name="identifier">The data identifier.</param> /// <param name="clipboardDataPath">The full path to the clipboard data folder.</param> private void WriteClipboardDataToFile(ClipboardReader clipboardReader, DataIdentifier identifier, string clipboardDataPath) { Requires.NotNull(clipboardReader, nameof(clipboardReader)); Requires.NotNull(identifier, nameof(identifier)); Requires.NotNullOrWhiteSpace(clipboardDataPath, nameof(clipboardDataPath)); var dataFilePath = Path.Combine(clipboardDataPath, $"{identifier.Identifier}.dat"); if (File.Exists(dataFilePath)) { Logger.Instance.Fatal(new FileLoadException($"The file {dataFilePath} already exists.")); } var dataPassword = SecurityHelper.ToSecureString(SecurityHelper.EncryptString(SecurityHelper.ToSecureString( identifier.Identifier.ToString( )))); Requires.NotNull(dataPassword, nameof(dataPassword)); clipboardReader.BeginRead(identifier.FormatName); Requires.IsTrue(clipboardReader.IsReadable); Requires.IsTrue(clipboardReader.CanReadNextBlock()); using (var fileStream = File.OpenWrite(dataFilePath)) using (var aesStream = new AesStream(fileStream, dataPassword, SecurityHelper.GetSaltKeys(dataPassword).GetBytes(16))) { aesStream.AutoDisposeBaseStream = false; while (clipboardReader.CanReadNextBlock()) { var buffer = clipboardReader.ReadNextBlock(); aesStream.Write(buffer, 0, buffer.Length); } aesStream.Position = 0; } clipboardReader.EndRead(); }
/// <summary> /// Force to synchronize that data with the cloud. /// </summary> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> internal async Task SynchronizeAsync() { if (IsSynchronizing) { return; } Logger.Instance.Information("Synchronization with the cloud started."); IsSynchronizing = true; if (CurrentCloudStorageProvider == null) { Logger.Instance.Warning("The user is not logged to any cloud storage provider. The synchronization stopped."); IsSynchronizing = false; return; } if (!CoreHelper.IsUnitTesting() && !SystemInfoHelper.CheckForInternetConnection()) { Logger.Instance.Warning("There is no internet connection. The synchronization stopped."); IsSynchronizing = false; return; } SynchronizationStarted?.Invoke(this, new EventArgs()); try { if (!await CurrentCloudStorageProvider.TryAuthenticateAsync()) { Logger.Instance.Warning("The user is not authenticated correctly. Consider unlink the app and connect again. The synchronization stopped."); IsSynchronizing = false; SynchronizationEnded?.Invoke(this, new EventArgs()); return; } var userId = SecurityHelper.ToSecureString(await CurrentCloudStorageProvider.GetUserIdAsync()); if (string.IsNullOrWhiteSpace(SecurityHelper.ToUnsecureString(userId))) { Logger.Instance.Warning("The user's id from the cloud storage provider has not been found. The synchronization stopped."); IsSynchronizing = false; SynchronizationEnded?.Invoke(this, new EventArgs()); SynchronizationFailed?.Invoke(this, new EventArgs()); return; } Logger.Instance.Information("Freezing the data before synchronize."); var dataService = ServiceLocator.GetService <DataService>(); var cloudDataEntryFromServer = new List <CloudDataEntry>(); var cloudAppFolder = await CurrentCloudStorageProvider.GetAppFolderAsync(); var cloudDataEntryFilePath = Path.Combine(cloudAppFolder.FullPath, Consts.DataEntryFileName); var cloudDataPassword = SecurityHelper.ToSecureString(SecurityHelper.EncryptString(userId, SecurityHelper.ToSecureString(await CurrentCloudStorageProvider.GetUserNameAsync()))); var localFrozenDataEntries = DataHelper.FromByteArray <AsyncObservableCollection <DataEntry> >(DataHelper.ToByteArray(dataService.DataEntries)); var localFrozenCache = DataHelper.FromByteArray <List <DataEntryCache> >(DataHelper.ToByteArray(dataService.Cache)); // Download data from server. if (cloudAppFolder.Files.Any(file => file.FullPath == cloudDataEntryFilePath)) { Logger.Instance.Information("Downloading the data entry file from the server."); try { using (var memoryStream = new MemoryStream()) { await CurrentCloudStorageProvider.DownloadFileAsync(cloudDataEntryFilePath, memoryStream); memoryStream.Position = 0; using (var aesStream = new AesStream(memoryStream, cloudDataPassword, SecurityHelper.GetSaltKeys(cloudDataPassword).GetBytes(16))) { var data = new byte[aesStream.Length]; aesStream.Read(data, 0, data.Length); cloudDataEntryFromServer = JsonConvert.DeserializeObject <List <CloudDataEntry> >(Encoding.UTF8.GetString(data)); } } } catch (Exception exception) { Logger.Instance.Warning($"Unable to download or read the data file entry from the cloud for the following reason : {exception.Message}"); IsSynchronizing = false; SynchronizationEnded?.Invoke(this, new EventArgs()); SynchronizationFailed?.Invoke(this, new EventArgs()); return; } } else { Logger.Instance.Information("There is no data entry file on the server yet."); } // Synchronize locally the data. The result must corresponds to what we will have locally and on the server at the end of the synchronization process. var cloudDataEntryToServer = dataService.DifferenceLocalAndCloudDataEntries(cloudDataEntryFromServer); // Download the needed data from the server to the local machine. Logger.Instance.Information("Downloading the needed data from the server to the local machine."); var dataToDownload = cloudDataEntryFromServer.Cast <DataEntryBase>().Except(localFrozenDataEntries, (item1, item2) => item1.Identifier == item2.Identifier).ToList(); var taskList = new List <Task>(); foreach (var cloudDataEntry in dataToDownload) { if (dataToDownload.Any(data => localFrozenCache.Any(item => data.Identifier == item.Identifier && item.Status == DataEntryStatus.Deleted))) { continue; } foreach (var dataEntryDataIdentifier in cloudDataEntry.DataIdentifiers) { var task = DownloadDataFileAsync(dataService.ClipboardDataPath, cloudAppFolder, cloudDataPassword, dataEntryDataIdentifier); taskList.Add(task); } } await Task.WhenAll(taskList); // Delete the needed data from the server Logger.Instance.Information("Deleting the needed data from the server."); taskList = new List <Task>(); foreach (var dataServiceDataEntry in localFrozenDataEntries.Where(item => !item.CanSynchronize)) { foreach (var dataEntryDataIdentifier in dataServiceDataEntry.DataIdentifiers) { var task = DeleteFileAsync(cloudAppFolder, dataEntryDataIdentifier); taskList.Add(task); } } await Task.WhenAll(taskList); taskList = new List <Task>(); foreach (var cacheEntry in localFrozenCache.Where(item => item.Status == DataEntryStatus.Deleted)) { var dataEntry = cloudDataEntryFromServer.SingleOrDefault(item => item.Identifier == cacheEntry.Identifier); if (dataEntry != null) { foreach (var dataEntryDataIdentifier in dataEntry.DataIdentifiers) { var task = DeleteFileAsync(cloudAppFolder, dataEntryDataIdentifier); taskList.Add(task); } } } await Task.WhenAll(taskList); await dataService.MakeCacheSynchronized(cloudDataEntryToServer, true, localFrozenCache); localFrozenDataEntries = DataHelper.FromByteArray <AsyncObservableCollection <DataEntry> >(DataHelper.ToByteArray(dataService.DataEntries)); localFrozenCache = DataHelper.FromByteArray <List <DataEntryCache> >(DataHelper.ToByteArray(dataService.Cache)); // Upload the needed data from the server to the local machine Logger.Instance.Information("Uploading the needed data from the server to the local machine."); var dataToUpload = localFrozenDataEntries.Cast <DataEntryBase>().Except(cloudDataEntryFromServer, (item1, item2) => item1.Identifier == item2.Identifier); taskList = new List <Task>(); foreach (var dataEntry in dataToUpload) { var localDataEntry = localFrozenDataEntries.Single(item => item.Identifier == dataEntry.Identifier); if (!localDataEntry.CanSynchronize || localDataEntry.Thumbnail.Type == ThumbnailDataType.Files) { continue; } foreach (var dataEntryDataIdentifier in dataEntry.DataIdentifiers) { var task = UploadDataFileAsync(dataService.ClipboardDataPath, cloudAppFolder, cloudDataPassword, dataEntryDataIdentifier); taskList.Add(task); } } await Task.WhenAll(taskList); // Upload the new data to the server. Logger.Instance.Information("Uploading the data entry file to the server."); using (var memoryStream = new MemoryStream()) using (var aesStream = new AesStream(memoryStream, cloudDataPassword, SecurityHelper.GetSaltKeys(cloudDataPassword).GetBytes(16))) { var data = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(cloudDataEntryToServer)); aesStream.Write(data, 0, data.Length); aesStream.Position = 0; await CurrentCloudStorageProvider.UploadFileAsync(memoryStream, cloudDataEntryFilePath); } await dataService.MakeCacheSynchronized(cloudDataEntryToServer, false, localFrozenCache); } catch (Exception exception) { Logger.Instance.Warning($"Unable to synchronize for the following reason : {exception.Message}. {exception.InnerException?.Message}"); SynchronizationFailed?.Invoke(this, new EventArgs()); } _synchronizeTimer.Stop(); _synchronizeTimer.Start(); IsSynchronizing = false; SynchronizationEnded?.Invoke(this, new EventArgs()); }