From 0fed85140bab43af404b3cd57ae099f4998dccb8 Mon Sep 17 00:00:00 2001 From: Federico Maccaroni Date: Thu, 1 Jun 2023 17:49:58 +0300 Subject: [PATCH] PM-115 Fix attachment encryption on new cipher item encryption model --- .../Pages/Vault/AttachmentsPageViewModel.cs | 2 +- src/Core/Abstractions/ICipherService.cs | 2 +- src/Core/Services/CipherService.cs | 11 ++++---- .../Cipher/CipherCustomizations.cs | 26 +++++++++++++++++-- test/Core.Test/Services/CipherServiceTests.cs | 12 ++++----- 5 files changed, 38 insertions(+), 15 deletions(-) diff --git a/src/App/Pages/Vault/AttachmentsPageViewModel.cs b/src/App/Pages/Vault/AttachmentsPageViewModel.cs index 253e2c2c6..d031bb627 100644 --- a/src/App/Pages/Vault/AttachmentsPageViewModel.cs +++ b/src/App/Pages/Vault/AttachmentsPageViewModel.cs @@ -123,7 +123,7 @@ namespace Bit.App.Pages { await _deviceActionService.ShowLoadingAsync(AppResources.Saving); _cipherDomain = await _cipherService.SaveAttachmentRawWithServerAsync( - _cipherDomain, FileName, FileData); + _cipherDomain, Cipher, FileName, FileData); Cipher = await _cipherDomain.DecryptAsync(); await _deviceActionService.HideLoadingAsync(); _platformUtilsService.ShowToast("success", null, AppResources.AttachementAdded); diff --git a/src/Core/Abstractions/ICipherService.cs b/src/Core/Abstractions/ICipherService.cs index e34aaa068..ff0a3e320 100644 --- a/src/Core/Abstractions/ICipherService.cs +++ b/src/Core/Abstractions/ICipherService.cs @@ -27,7 +27,7 @@ namespace Bit.Core.Abstractions Task GetAsync(string id); Task GetLastUsedForUrlAsync(string url); Task ReplaceAsync(Dictionary ciphers); - Task SaveAttachmentRawWithServerAsync(Cipher cipher, string filename, byte[] data); + Task SaveAttachmentRawWithServerAsync(Cipher cipher, CipherView cipherView, string filename, byte[] data); Task SaveCollectionsWithServerAsync(Cipher cipher); Task SaveNeverDomainAsync(string domain); Task SaveWithServerAsync(Cipher cipher); diff --git a/src/Core/Services/CipherService.cs b/src/Core/Services/CipherService.cs index 512f52c3b..acf167861 100644 --- a/src/Core/Services/CipherService.cs +++ b/src/Core/Services/CipherService.cs @@ -597,11 +597,12 @@ namespace Bit.Core.Services await UpsertAsync(data); } - public async Task SaveAttachmentRawWithServerAsync(Cipher cipher, string filename, byte[] data) + public async Task SaveAttachmentRawWithServerAsync(Cipher cipher, CipherView cipherView, string filename, byte[] data) { var orgKey = await _cryptoService.GetOrgKeyAsync(cipher.OrganizationId); - var encFileName = await _cryptoService.EncryptAsync(filename, orgKey); - var (attachmentKey, orgEncAttachmentKey) = await _cryptoService.MakeEncKeyAsync(orgKey); + var key = await UpdateCipherAndGetCipherKeyAsync(cipher, cipherView, orgKey); + var encFileName = await _cryptoService.EncryptAsync(filename, key); + var (attachmentKey, encAttachmentKey) = await _cryptoService.MakeEncKeyAsync(key); var encFileData = await _cryptoService.EncryptToBytesAsync(data, attachmentKey); CipherResponse response; @@ -609,7 +610,7 @@ namespace Bit.Core.Services { var request = new AttachmentRequest { - Key = orgEncAttachmentKey.EncryptedString, + Key = encAttachmentKey.EncryptedString, FileName = encFileName.EncryptedString, FileSize = encFileData.Buffer.Length, }; @@ -621,7 +622,7 @@ namespace Bit.Core.Services } catch (ApiException e) when (e.Error.StatusCode == System.Net.HttpStatusCode.NotFound || e.Error.StatusCode == System.Net.HttpStatusCode.MethodNotAllowed) { - response = await LegacyServerAttachmentFileUploadAsync(cipher.Id, encFileName, encFileData, orgEncAttachmentKey); + response = await LegacyServerAttachmentFileUploadAsync(cipher.Id, encFileName, encFileData, encAttachmentKey); } var userId = await _stateService.GetActiveUserIdAsync(); diff --git a/test/Core.Test/AutoFixture/Cipher/CipherCustomizations.cs b/test/Core.Test/AutoFixture/Cipher/CipherCustomizations.cs index 6d4f47aad..57cec73b2 100644 --- a/test/Core.Test/AutoFixture/Cipher/CipherCustomizations.cs +++ b/test/Core.Test/AutoFixture/Cipher/CipherCustomizations.cs @@ -1,6 +1,8 @@ using System; +using System.Text; using AutoFixture; using Bit.Core.Models.Domain; +using Bit.Core.Models.View; using Bit.Test.Common.AutoFixture; using Bit.Test.Common.AutoFixture.Attributes; @@ -26,16 +28,36 @@ namespace Bit.Core.Test.AutoFixture } } + internal class UserCipherView : ICustomization + { + public void Customize(IFixture fixture) + { + byte[] getRandomBytes(int size) + { + Random random = new Random(); + + byte[] bytes = new byte[size]; + random.NextBytes(bytes); + return bytes; + }; + + fixture.Customize(composer => composer + .Without(c => c.OrganizationId) + .Without(c => c.Attachments) + .With(c => c.Key, new SymmetricCryptoKey(getRandomBytes(32), Enums.EncryptionType.AesCbc128_HmacSha256_B64))); + } + } + internal class UserCipherAutoDataAttribute : CustomAutoDataAttribute { public UserCipherAutoDataAttribute() : base(new SutProviderCustomization(), - new UserCipher()) + new UserCipher(), new UserCipherView()) { } } internal class InlineUserCipherAutoDataAttribute : InlineCustomAutoDataAttribute { public InlineUserCipherAutoDataAttribute(params object[] values) : base(new[] { typeof(SutProviderCustomization), - typeof(UserCipher) }, values) + typeof(UserCipher), typeof(UserCipherView) }, values) { } } diff --git a/test/Core.Test/Services/CipherServiceTests.cs b/test/Core.Test/Services/CipherServiceTests.cs index 494fa192c..420e8b42e 100644 --- a/test/Core.Test/Services/CipherServiceTests.cs +++ b/test/Core.Test/Services/CipherServiceTests.cs @@ -22,7 +22,7 @@ namespace Bit.Core.Test.Services { [Theory, UserCipherAutoData] public async Task SaveWithServerAsync_PrefersFileUploadService(SutProvider sutProvider, - Cipher cipher, string fileName, EncByteArray data, AttachmentUploadDataResponse uploadDataResponse, EncString encKey) + Cipher cipher, CipherView cipherView, string fileName, EncByteArray data, AttachmentUploadDataResponse uploadDataResponse, EncString encKey) { var encFileName = new EncString(fileName); sutProvider.GetDependency().EncryptAsync(fileName, Arg.Any()) @@ -33,7 +33,7 @@ namespace Bit.Core.Test.Services sutProvider.GetDependency().PostCipherAttachmentAsync(cipher.Id, Arg.Any()) .Returns(uploadDataResponse); - await sutProvider.Sut.SaveAttachmentRawWithServerAsync(cipher, fileName, data.Buffer); + await sutProvider.Sut.SaveAttachmentRawWithServerAsync(cipher, cipherView, fileName, data.Buffer); await sutProvider.GetDependency().Received(1) .UploadCipherAttachmentFileAsync(uploadDataResponse, encFileName, data); @@ -43,7 +43,7 @@ namespace Bit.Core.Test.Services [InlineUserCipherAutoData(HttpStatusCode.NotFound)] [InlineUserCipherAutoData(HttpStatusCode.MethodNotAllowed)] public async Task SaveWithServerAsync_FallsBackToLegacyFormData(HttpStatusCode statusCode, - SutProvider sutProvider, Cipher cipher, string fileName, EncByteArray data, + SutProvider sutProvider, Cipher cipher, CipherView cipherView, string fileName, EncByteArray data, CipherResponse response, EncString encKey) { sutProvider.GetDependency().EncryptAsync(fileName, Arg.Any()) @@ -56,7 +56,7 @@ namespace Bit.Core.Test.Services sutProvider.GetDependency().PostCipherAttachmentLegacyAsync(cipher.Id, Arg.Any()) .Returns(response); - await sutProvider.Sut.SaveAttachmentRawWithServerAsync(cipher, fileName, data.Buffer); + await sutProvider.Sut.SaveAttachmentRawWithServerAsync(cipher, cipherView, fileName, data.Buffer); await sutProvider.GetDependency().Received(1) .PostCipherAttachmentLegacyAsync(cipher.Id, Arg.Any()); @@ -64,7 +64,7 @@ namespace Bit.Core.Test.Services [Theory, UserCipherAutoData] public async Task SaveWithServerAsync_ThrowsOnBadRequestApiException(SutProvider sutProvider, - Cipher cipher, string fileName, EncByteArray data, EncString encKey) + Cipher cipher, CipherView cipherView, string fileName, EncByteArray data, EncString encKey) { sutProvider.GetDependency().EncryptAsync(fileName, Arg.Any()) .Returns(new EncString(fileName)); @@ -77,7 +77,7 @@ namespace Bit.Core.Test.Services .Throws(expectedException); var actualException = await Assert.ThrowsAsync(async () => - await sutProvider.Sut.SaveAttachmentRawWithServerAsync(cipher, fileName, data.Buffer)); + await sutProvider.Sut.SaveAttachmentRawWithServerAsync(cipher, cipherView, fileName, data.Buffer)); Assert.Equal(expectedException.Error.StatusCode, actualException.Error.StatusCode); }