Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PM-115] Cipher key encryption update #2421

Merged
merged 31 commits into from
Sep 28, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
2bb7207
PM-115 Added new cipher key and encryption/decryption mechanisms on c…
fedemkr Mar 20, 2023
c8555ef
Merge branch 'master' into feature/PM-115-encryption-update-new-model
fedemkr Mar 20, 2023
a3b18dc
PM-115 fix format
fedemkr Mar 20, 2023
74190e0
Merge branch 'master' into feature/PM-115-encryption-update-new-model
fedemkr Apr 4, 2023
7cdc5a6
Merge branch 'master' into feature/PM-115-encryption-update-new-model
fedemkr May 22, 2023
1a0e9e9
PM-115 removed ForceKeyRotation from new cipher encryption model give…
fedemkr May 22, 2023
b150d88
[PM-1690] Added minimum server version restriction to cipher key encr…
fedemkr May 23, 2023
bcd47b3
Merge branch 'master' into feature/PM-115-encryption-update-new-model
fedemkr May 29, 2023
e19b86e
PM-115 Temporarily Changed cipher key new encryption config to help t…
fedemkr May 31, 2023
74196f6
Merge branch 'master' into feature/PM-115-encryption-update-new-model
fedemkr Jun 2, 2023
2a4ce73
PM-2456 Fix attachment encryption on new cipher item encryption model…
fedemkr Jun 5, 2023
e7c13a8
Merge branch 'master' into feature/PM-115-encryption-update-new-model
fedemkr Jun 6, 2023
7e18093
PM-2531 Fix new cipher encryption on adding attachments on ciphers wi…
fedemkr Jun 6, 2023
137e8f9
PM-115 Changed temporarily cipher key encryption min server version t…
fedemkr Jun 7, 2023
b2b12d6
Merge branch 'master' into feature/PM-115-encryption-update-new-model
fedemkr Jun 7, 2023
26c314c
PM-115 Reseted cipher key encryption minimum server version to 2023.5…
fedemkr Jun 7, 2023
38ae3d7
Merge branch 'master' into feature/PM-115-encryption-update-new-model
fedemkr Jun 28, 2023
9db4edb
Merge branch 'master' into feature/PM-115-encryption-update-new-model
fedemkr Jul 27, 2023
04e9d0a
Added Key value to the cipher export model (#2628)
aj-rosado Aug 15, 2023
f037214
Merge branch 'master' into feature/PM-115-encryption-update-new-model
fedemkr Aug 23, 2023
99b0c17
Merge branch 'master' into feature/PM-115-encryption-update-new-model
fedemkr Aug 31, 2023
b0c224e
Update Constants.cs
fedemkr Aug 31, 2023
3018e65
PM-115 Fix file format
fedemkr Sep 1, 2023
dd6f614
PM-115 Changed new encryption off and minimum new encryption server v…
fedemkr Sep 1, 2023
eab8adf
Merge branch 'master' into feature/PM-115-encryption-update-new-model
fedemkr Sep 5, 2023
69e306e
PM-115 Changed CIpher key encryption minimum server version to 2023.9.0
fedemkr Sep 5, 2023
6ae671b
Merge branch 'master' into feature/PM-115-encryption-update-new-model
fedemkr Sep 18, 2023
78bb8b2
PM-3737 Remove suffix on client version sent to server (#2779)
fedemkr Sep 18, 2023
9c7f966
PM-115 QA testing server min version and enable new cipher key encryp…
fedemkr Sep 27, 2023
0d8bb1c
PM-115 Disable new cipher encryption creation and change minimum serv…
fedemkr Sep 27, 2023
9a54708
Merge branch 'master' into feature/PM-115-encryption-update-new-model
fedemkr Sep 27, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Core/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public static class Constants
public const int Argon2MemoryInMB = 64;
public const int Argon2Parallelism = 4;
public const int MasterPasswordMinimumChars = 12;
public const int CipherKeyRandomBytesLength = 64;

public static readonly string[] AndroidAllClearCipherCacheKeys =
{
Expand Down
4 changes: 4 additions & 0 deletions src/Core/Models/Data/CipherData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ public CipherData(CipherResponse response, string userId = null, HashSet<string>
Notes = response.Notes;
CollectionIds = collectionIds?.ToList() ?? response.CollectionIds;
Reprompt = response.Reprompt;
Key = response.Key;
ForceKeyRotation = response.ForceKeyRotation;

try // Added to address Issue (https://github.com/bitwarden/mobile/issues/1006)
{
Expand Down Expand Up @@ -86,5 +88,7 @@ public CipherData(CipherResponse response, string userId = null, HashSet<string>
public List<string> CollectionIds { get; set; }
public DateTime? DeletedDate { get; set; }
public Enums.CipherRepromptType Reprompt { get; set; }
public string Key { get; set; }
public bool ForceKeyRotation { get; set; }
}
}
35 changes: 19 additions & 16 deletions src/Core/Models/Domain/Attachment.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.Core.Abstractions;
using Bit.Core.Models.Data;
using Bit.Core.Models.View;
using Bit.Core.Services;
using Bit.Core.Utilities;

namespace Bit.Core.Models.Domain
Expand All @@ -11,19 +13,19 @@ public class Attachment : Domain
{
private HashSet<string> _map = new HashSet<string>
{
"Id",
"Url",
"SizeName",
"FileName",
"Key"
nameof(Id),
nameof(Url),
nameof(SizeName),
nameof(FileName),
nameof(Key)
};

public Attachment() { }

public Attachment(AttachmentData obj, bool alreadyEncrypted = false)
{
Size = obj.Size;
BuildDomainModel(this, obj, _map, alreadyEncrypted, new HashSet<string> { "Id", "Url", "SizeName" });
BuildDomainModel(this, obj, _map, alreadyEncrypted, new HashSet<string> { nameof(Id), nameof(Url), nameof(SizeName) });
}

public string Id { get; set; }
Expand All @@ -33,25 +35,26 @@ public Attachment(AttachmentData obj, bool alreadyEncrypted = false)
public EncString Key { get; set; }
public EncString FileName { get; set; }

public async Task<AttachmentView> DecryptAsync(string orgId)
public async Task<AttachmentView> DecryptAsync(string orgId, SymmetricCryptoKey key = null)
{
var view = await DecryptObjAsync(new AttachmentView(this), this, new HashSet<string>
{
"FileName"
}, orgId);
nameof(FileName)
}, orgId, key);

if (Key != null)
{
var cryptoService = ServiceContainer.Resolve<ICryptoService>("cryptoService");
try
{
var orgKey = await cryptoService.GetOrgKeyAsync(orgId);
var decValue = await cryptoService.DecryptToBytesAsync(Key, orgKey);
var cryptoService = ServiceContainer.Resolve<ICryptoService>();

var decryptKey = key ?? await cryptoService.GetOrgKeyAsync(orgId);
var decValue = await cryptoService.DecryptToBytesAsync(Key, decryptKey);
view.Key = new SymmetricCryptoKey(decValue);
}
catch
catch (Exception ex)
{
// TODO: error?
LoggerHelper.LogEvenIfCantBeResolved(ex);
}
}
return view;
Expand All @@ -61,7 +64,7 @@ public AttachmentData ToAttachmentData()
{
var a = new AttachmentData();
a.Size = Size;
BuildDataModel(this, a, _map, new HashSet<string> { "Id", "Url", "SizeName" });
BuildDataModel(this, a, _map, new HashSet<string> { nameof(Id), nameof(Url), nameof(SizeName) });
return a;
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/Core/Models/Domain/Card.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ public Card(CardData obj, bool alreadyEncrypted = false)
public EncString ExpYear { get; set; }
public EncString Code { get; set; }

public Task<CardView> DecryptAsync(string orgId)
public Task<CardView> DecryptAsync(string orgId, SymmetricCryptoKey key = null)
{
return DecryptObjAsync(new CardView(this), this, _map, orgId);
return DecryptObjAsync(new CardView(this), this, _map, orgId, key);
}

public CardData ToCardData()
Expand Down
62 changes: 44 additions & 18 deletions src/Core/Models/Domain/Cipher.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Threading.Tasks;
using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Bit.Core.Models.Data;
using Bit.Core.Models.View;
using Bit.Core.Utilities;

namespace Bit.Core.Models.Domain
{
Expand All @@ -16,12 +19,12 @@ public Cipher(CipherData obj, bool alreadyEncrypted = false, Dictionary<string,
{
BuildDomainModel(this, obj, new HashSet<string>
{
"Id",
"OrganizationId",
"FolderId",
"Name",
"Notes"
}, alreadyEncrypted, new HashSet<string> { "Id", "OrganizationId", "FolderId" });
nameof(Id),
nameof(OrganizationId),
nameof(FolderId),
nameof(Name),
nameof(Notes)
}, alreadyEncrypted, new HashSet<string> { nameof(Id), nameof(OrganizationId), nameof(FolderId) });

Type = obj.Type;
Favorite = obj.Favorite;
Expand All @@ -32,6 +35,12 @@ public Cipher(CipherData obj, bool alreadyEncrypted = false, Dictionary<string,
CollectionIds = obj.CollectionIds != null ? new HashSet<string>(obj.CollectionIds) : null;
LocalData = localData;
Reprompt = obj.Reprompt;
ForceKeyRotation = obj.ForceKeyRotation;

if (obj.Key != null)
{
Key = new EncString(obj.Key);
}

switch (Type)
{
Expand Down Expand Up @@ -79,29 +88,44 @@ public Cipher(CipherData obj, bool alreadyEncrypted = false, Dictionary<string,
public HashSet<string> CollectionIds { get; set; }
public DateTime? DeletedDate { get; set; }
public CipherRepromptType Reprompt { get; set; }
public EncString Key { get; set; }
public bool ForceKeyRotation { get; set; }

public async Task<CipherView> DecryptAsync()
{
var model = new CipherView(this);

if (Key != null)
{
// HACK: I don't like resolving this here but I can't see a better way without
// refactoring a lot of things.
var cryptoService = ServiceContainer.Resolve<ICryptoService>();

var orgKey = await cryptoService.GetOrgKeyAsync(OrganizationId);

var key = await cryptoService.DecryptToBytesAsync(Key, orgKey);
model.Key = new SymmetricCryptoKey(key);
}

await DecryptObjAsync(model, this, new HashSet<string>
{
"Name",
"Notes"
}, OrganizationId);
nameof(Name),
nameof(Notes)
}, OrganizationId, model.Key);

switch (Type)
{
case Enums.CipherType.Login:
model.Login = await Login.DecryptAsync(OrganizationId);
model.Login = await Login.DecryptAsync(OrganizationId, model.Key);
break;
case Enums.CipherType.SecureNote:
model.SecureNote = await SecureNote.DecryptAsync(OrganizationId);
model.SecureNote = await SecureNote.DecryptAsync(OrganizationId, model.Key);
break;
case Enums.CipherType.Card:
model.Card = await Card.DecryptAsync(OrganizationId);
model.Card = await Card.DecryptAsync(OrganizationId, model.Key);
break;
case Enums.CipherType.Identity:
model.Identity = await Identity.DecryptAsync(OrganizationId);
model.Identity = await Identity.DecryptAsync(OrganizationId, model.Key);
break;
default:
break;
Expand All @@ -113,7 +137,7 @@ public async Task<CipherView> DecryptAsync()
var tasks = new List<Task>();
async Task decryptAndAddAttachmentAsync(Attachment attachment)
{
var decAttachment = await attachment.DecryptAsync(OrganizationId);
var decAttachment = await attachment.DecryptAsync(OrganizationId, model.Key);
model.Attachments.Add(decAttachment);
}
foreach (var attachment in Attachments)
Expand All @@ -128,7 +152,7 @@ async Task decryptAndAddAttachmentAsync(Attachment attachment)
var tasks = new List<Task>();
async Task decryptAndAddFieldAsync(Field field)
{
var decField = await field.DecryptAsync(OrganizationId);
var decField = await field.DecryptAsync(OrganizationId, model.Key);
model.Fields.Add(decField);
}
foreach (var field in Fields)
Expand All @@ -143,7 +167,7 @@ async Task decryptAndAddFieldAsync(Field field)
var tasks = new List<Task>();
async Task decryptAndAddHistoryAsync(PasswordHistory ph)
{
var decPh = await ph.DecryptAsync(OrganizationId);
var decPh = await ph.DecryptAsync(OrganizationId, model.Key);
model.PasswordHistory.Add(decPh);
}
foreach (var ph in PasswordHistory)
Expand Down Expand Up @@ -171,11 +195,13 @@ public CipherData ToCipherData(string userId)
CollectionIds = CollectionIds.ToList(),
DeletedDate = DeletedDate,
Reprompt = Reprompt,
Key = Key?.EncryptedString,
ForceKeyRotation = ForceKeyRotation
};
BuildDataModel(this, c, new HashSet<string>
{
"Name",
"Notes"
nameof(Name),
nameof(Notes)
});
switch (c.Type)
{
Expand Down
4 changes: 2 additions & 2 deletions src/Core/Models/Domain/Field.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ public Field(FieldData obj, bool alreadyEncrypted = false)
public FieldType Type { get; set; }
public LinkedIdType? LinkedId { get; set; }

public Task<FieldView> DecryptAsync(string orgId)
public Task<FieldView> DecryptAsync(string orgId, SymmetricCryptoKey key = null)
{
return DecryptObjAsync(new FieldView(this), this, _map, orgId);
return DecryptObjAsync(new FieldView(this), this, _map, orgId, key);
}

public FieldData ToFieldData()
Expand Down
4 changes: 2 additions & 2 deletions src/Core/Models/Domain/Identity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ public Identity(IdentityData obj, bool alreadyEncrypted = false)
public EncString PassportNumber { get; set; }
public EncString LicenseNumber { get; set; }

public Task<IdentityView> DecryptAsync(string orgId)
public Task<IdentityView> DecryptAsync(string orgId, SymmetricCryptoKey key = null)
{
return DecryptObjAsync(new IdentityView(this), this, _map, orgId);
return DecryptObjAsync(new IdentityView(this), this, _map, orgId, key);
}

public IdentityData ToIdentityData()
Expand Down
6 changes: 3 additions & 3 deletions src/Core/Models/Domain/Login.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,20 @@ public Login(LoginData obj, bool alreadyEncrypted = false)
public DateTime? PasswordRevisionDate { get; set; }
public EncString Totp { get; set; }

public async Task<LoginView> DecryptAsync(string orgId)
public async Task<LoginView> DecryptAsync(string orgId, SymmetricCryptoKey key = null)
{
var view = await DecryptObjAsync(new LoginView(this), this, new HashSet<string>
{
"Username",
"Password",
"Totp"
}, orgId);
}, orgId, key);
if (Uris != null)
{
view.Uris = new List<LoginUriView>();
foreach (var uri in Uris)
{
view.Uris.Add(await uri.DecryptAsync(orgId));
view.Uris.Add(await uri.DecryptAsync(orgId, key));
}
}
return view;
Expand Down
4 changes: 2 additions & 2 deletions src/Core/Models/Domain/LoginUri.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ public LoginUri(LoginUriData obj, bool alreadyEncrypted = false)
public EncString Uri { get; set; }
public UriMatchType? Match { get; set; }

public Task<LoginUriView> DecryptAsync(string orgId)
public Task<LoginUriView> DecryptAsync(string orgId, SymmetricCryptoKey key = null)
{
return DecryptObjAsync(new LoginUriView(this), this, _map, orgId);
return DecryptObjAsync(new LoginUriView(this), this, _map, orgId, key);
}

public LoginUriData ToLoginUriData()
Expand Down
4 changes: 2 additions & 2 deletions src/Core/Models/Domain/PasswordHistory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ public PasswordHistory(PasswordHistoryData obj, bool alreadyEncrypted = false)
public EncString Password { get; set; }
public DateTime LastUsedDate { get; set; }

public Task<PasswordHistoryView> DecryptAsync(string orgId)
public Task<PasswordHistoryView> DecryptAsync(string orgId, SymmetricCryptoKey key = null)
{
return DecryptObjAsync(new PasswordHistoryView(this), this, _map, orgId);
return DecryptObjAsync(new PasswordHistoryView(this), this, _map, orgId, key);
}

public PasswordHistoryData ToPasswordHistoryData()
Expand Down
2 changes: 1 addition & 1 deletion src/Core/Models/Domain/SecureNote.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public SecureNote(SecureNoteData obj, bool alreadyEncrypted = false)

public SecureNoteType Type { get; set; }

public Task<SecureNoteView> DecryptAsync(string orgId)
public Task<SecureNoteView> DecryptAsync(string orgId, SymmetricCryptoKey key = null)
{
return Task.FromResult(new SecureNoteView(this));
}
Expand Down
4 changes: 4 additions & 0 deletions src/Core/Models/Request/CipherRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ public CipherRequest(Cipher cipher)
Favorite = cipher.Favorite;
LastKnownRevisionDate = cipher.RevisionDate;
Reprompt = cipher.Reprompt;
Key = cipher.Key?.EncryptedString;
ForceKeyRotation = cipher.ForceKeyRotation;

switch (Type)
{
Expand Down Expand Up @@ -124,5 +126,7 @@ public CipherRequest(Cipher cipher)
public Dictionary<string, AttachmentRequest> Attachments2 { get; set; }
public DateTime LastKnownRevisionDate { get; set; }
public CipherRepromptType Reprompt { get; set; }
public string Key { get; set; }
public bool ForceKeyRotation { get; set; }
}
}
2 changes: 2 additions & 0 deletions src/Core/Models/Response/CipherResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,7 @@ public class CipherResponse
public List<string> CollectionIds { get; set; }
public DateTime? DeletedDate { get; set; }
public CipherRepromptType Reprompt { get; set; }
public string Key { get; set; }
public bool ForceKeyRotation { get; set; }
}
}
3 changes: 3 additions & 0 deletions src/Core/Models/View/CipherView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public CipherView(Cipher c)
RevisionDate = c.RevisionDate;
DeletedDate = c.DeletedDate;
Reprompt = c.Reprompt;
ForceKeyRotation = c.ForceKeyRotation;
}

public string Id { get; set; }
Expand All @@ -49,6 +50,8 @@ public CipherView(Cipher c)
public DateTime RevisionDate { get; set; }
public DateTime? DeletedDate { get; set; }
public CipherRepromptType Reprompt { get; set; }
public SymmetricCryptoKey Key { get; set; }
public bool ForceKeyRotation { get; set; }

public ItemView Item
{
Expand Down
Loading