mirror of
https://github.com/bitwarden/mobile
synced 2025-12-10 05:13:31 +00:00
[PM-2713] convert cipher service and others to crypto service api
This commit is contained in:
@@ -177,25 +177,28 @@ namespace Bit.App.Pages
|
|||||||
Name = string.IsNullOrWhiteSpace(Name) ? null : Name;
|
Name = string.IsNullOrWhiteSpace(Name) ? null : Name;
|
||||||
Email = Email.Trim().ToLower();
|
Email = Email.Trim().ToLower();
|
||||||
var kdfConfig = new KdfConfig(KdfType.PBKDF2_SHA256, Constants.Pbkdf2Iterations, null, null);
|
var kdfConfig = new KdfConfig(KdfType.PBKDF2_SHA256, Constants.Pbkdf2Iterations, null, null);
|
||||||
var masterKey = await _cryptoService.MakeMasterKeyAsync(MasterPassword, Email, kdfConfig);
|
var newMasterKey = await _cryptoService.MakeMasterKeyAsync(MasterPassword, Email, kdfConfig);
|
||||||
var encKey = await _cryptoService.MakeEncKeyAsync(masterKey);
|
var (newUserKey, newProtectedUserKey) = await _cryptoService.EncryptUserKeyWithMasterKeyAsync(
|
||||||
var hashedPassword = await _cryptoService.HashPasswordAsync(MasterPassword, masterKey);
|
newMasterKey,
|
||||||
var keys = await _cryptoService.MakeKeyPairAsync(encKey.Item1);
|
await _cryptoService.MakeUserKeyAsync()
|
||||||
|
);
|
||||||
|
var hashedPassword = await _cryptoService.HashPasswordAsync(MasterPassword, newMasterKey);
|
||||||
|
var (newPublicKey, newProtectedPrivateKey) = await _cryptoService.MakeKeyPairAsync(newUserKey);
|
||||||
var request = new RegisterRequest
|
var request = new RegisterRequest
|
||||||
{
|
{
|
||||||
Email = Email,
|
Email = Email,
|
||||||
Name = Name,
|
Name = Name,
|
||||||
MasterPasswordHash = hashedPassword,
|
MasterPasswordHash = hashedPassword,
|
||||||
MasterPasswordHint = Hint,
|
MasterPasswordHint = Hint,
|
||||||
Key = encKey.Item2.EncryptedString,
|
Key = newProtectedUserKey.EncryptedString,
|
||||||
Kdf = kdfConfig.Type,
|
Kdf = kdfConfig.Type,
|
||||||
KdfIterations = kdfConfig.Iterations,
|
KdfIterations = kdfConfig.Iterations,
|
||||||
KdfMemory = kdfConfig.Memory,
|
KdfMemory = kdfConfig.Memory,
|
||||||
KdfParallelism = kdfConfig.Parallelism,
|
KdfParallelism = kdfConfig.Parallelism,
|
||||||
Keys = new KeysRequest
|
Keys = new KeysRequest
|
||||||
{
|
{
|
||||||
PublicKey = keys.Item1,
|
PublicKey = newPublicKey,
|
||||||
EncryptedPrivateKey = keys.Item2.EncryptedString
|
EncryptedPrivateKey = newProtectedPrivateKey.EncryptedString
|
||||||
},
|
},
|
||||||
CaptchaResponse = _captchaToken,
|
CaptchaResponse = _captchaToken,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ namespace Bit.App.Pages
|
|||||||
_cipherDomain = await _cipherService.GetAsync(CipherId);
|
_cipherDomain = await _cipherService.GetAsync(CipherId);
|
||||||
Cipher = await _cipherDomain.DecryptAsync();
|
Cipher = await _cipherDomain.DecryptAsync();
|
||||||
LoadAttachments();
|
LoadAttachments();
|
||||||
_hasUpdatedKey = await _cryptoService.HasEncKeyAsync();
|
_hasUpdatedKey = await _cryptoService.HasUserKeyAsync();
|
||||||
var canAccessPremium = await _stateService.CanAccessPremiumAsync();
|
var canAccessPremium = await _stateService.CanAccessPremiumAsync();
|
||||||
_canAccessAttachments = canAccessPremium || Cipher.OrganizationId != null;
|
_canAccessAttachments = canAccessPremium || Cipher.OrganizationId != null;
|
||||||
if (!_canAccessAttachments)
|
if (!_canAccessAttachments)
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ namespace Bit.Core.Abstractions
|
|||||||
Task ToggleKeysAsync();
|
Task ToggleKeysAsync();
|
||||||
Task SetUserKeyAsync(UserKey userKey, string userId = null);
|
Task SetUserKeyAsync(UserKey userKey, string userId = null);
|
||||||
Task<UserKey> GetUserKeyAsync(string userId = null);
|
Task<UserKey> GetUserKeyAsync(string userId = null);
|
||||||
|
Task<UserKey> GetUserKeyWithLegacySupportAsync(string userId = null);
|
||||||
Task<bool> HasUserKeyAsync(string userId = null);
|
Task<bool> HasUserKeyAsync(string userId = null);
|
||||||
Task<bool> HasEncryptedUserKeyAsync(string userId = null);
|
Task<bool> HasEncryptedUserKeyAsync(string userId = null);
|
||||||
Task<UserKey> MakeUserKeyAsync();
|
Task<UserKey> MakeUserKeyAsync();
|
||||||
@@ -23,6 +24,8 @@ namespace Bit.Core.Abstractions
|
|||||||
Task ClearMasterKeyAsync(string userId = null);
|
Task ClearMasterKeyAsync(string userId = null);
|
||||||
Task<Tuple<UserKey, EncString>> EncryptUserKeyWithMasterKeyAsync(MasterKey masterKey, UserKey userKey = null);
|
Task<Tuple<UserKey, EncString>> EncryptUserKeyWithMasterKeyAsync(MasterKey masterKey, UserKey userKey = null);
|
||||||
Task<UserKey> DecryptUserKeyWithMasterKeyAsync(MasterKey masterKey, EncString encUserKey = null, string userId = null);
|
Task<UserKey> DecryptUserKeyWithMasterKeyAsync(MasterKey masterKey, EncString encUserKey = null, string userId = null);
|
||||||
|
Task<Tuple<SymmetricCryptoKey, EncString>> MakeDataEncKeyAsync(UserKey key);
|
||||||
|
Task<Tuple<SymmetricCryptoKey, EncString>> MakeDataEncKeyAsync(OrgKey key);
|
||||||
Task<string> HashPasswordAsync(string password, SymmetricCryptoKey key, HashPurpose hashPurpose = HashPurpose.ServerAuthorization);
|
Task<string> HashPasswordAsync(string password, SymmetricCryptoKey key, HashPurpose hashPurpose = HashPurpose.ServerAuthorization);
|
||||||
Task SetPasswordHashAsync(string keyHash);
|
Task SetPasswordHashAsync(string keyHash);
|
||||||
Task<string> GetPasswordHashAsync();
|
Task<string> GetPasswordHashAsync();
|
||||||
@@ -70,11 +73,9 @@ namespace Bit.Core.Abstractions
|
|||||||
void ClearCache();
|
void ClearCache();
|
||||||
Task<SymmetricCryptoKey> GetEncKeyAsync(SymmetricCryptoKey key = null);
|
Task<SymmetricCryptoKey> GetEncKeyAsync(SymmetricCryptoKey key = null);
|
||||||
Task<SymmetricCryptoKey> GetKeyAsync(string userId = null);
|
Task<SymmetricCryptoKey> GetKeyAsync(string userId = null);
|
||||||
Task<bool> HasEncKeyAsync();
|
|
||||||
Task<bool> HasKeyAsync(string userId = null);
|
Task<bool> HasKeyAsync(string userId = null);
|
||||||
Task<Tuple<SymmetricCryptoKey, EncString>> MakeEncKeyAsync(SymmetricCryptoKey key);
|
Task<Tuple<SymmetricCryptoKey, EncString>> MakeEncKeyAsync(SymmetricCryptoKey key);
|
||||||
// TODO(Jake): This isn't used, delete
|
// TODO(Jake): This isn't used, delete
|
||||||
Task<Tuple<EncString, SymmetricCryptoKey>> MakeShareKeyAsync();
|
|
||||||
Task SetEncKeyAsync(string encKey);
|
Task SetEncKeyAsync(string encKey);
|
||||||
Task SetKeyAsync(SymmetricCryptoKey key);
|
Task SetKeyAsync(SymmetricCryptoKey key);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -557,9 +557,20 @@ namespace Bit.Core.Services
|
|||||||
|
|
||||||
public async Task<Cipher> SaveAttachmentRawWithServerAsync(Cipher cipher, string filename, byte[] data)
|
public async Task<Cipher> SaveAttachmentRawWithServerAsync(Cipher cipher, string filename, byte[] data)
|
||||||
{
|
{
|
||||||
|
SymmetricCryptoKey attachmentKey;
|
||||||
|
EncString protectedAttachmentKey;
|
||||||
var orgKey = await _cryptoService.GetOrgKeyAsync(cipher.OrganizationId);
|
var orgKey = await _cryptoService.GetOrgKeyAsync(cipher.OrganizationId);
|
||||||
|
if (orgKey != null)
|
||||||
|
{
|
||||||
|
(attachmentKey, protectedAttachmentKey) = await _cryptoService.MakeDataEncKeyAsync(orgKey);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var userKey = await _cryptoService.GetUserKeyWithLegacySupportAsync();
|
||||||
|
(attachmentKey, protectedAttachmentKey) = await _cryptoService.MakeDataEncKeyAsync(userKey);
|
||||||
|
}
|
||||||
|
|
||||||
var encFileName = await _cryptoService.EncryptAsync(filename, orgKey);
|
var encFileName = await _cryptoService.EncryptAsync(filename, orgKey);
|
||||||
var (attachmentKey, orgEncAttachmentKey) = await _cryptoService.MakeEncKeyAsync(orgKey);
|
|
||||||
var encFileData = await _cryptoService.EncryptToBytesAsync(data, attachmentKey);
|
var encFileData = await _cryptoService.EncryptToBytesAsync(data, attachmentKey);
|
||||||
|
|
||||||
CipherResponse response;
|
CipherResponse response;
|
||||||
@@ -567,7 +578,7 @@ namespace Bit.Core.Services
|
|||||||
{
|
{
|
||||||
var request = new AttachmentRequest
|
var request = new AttachmentRequest
|
||||||
{
|
{
|
||||||
Key = orgEncAttachmentKey.EncryptedString,
|
Key = protectedAttachmentKey.EncryptedString,
|
||||||
FileName = encFileName.EncryptedString,
|
FileName = encFileName.EncryptedString,
|
||||||
FileSize = encFileData.Buffer.Length,
|
FileSize = encFileData.Buffer.Length,
|
||||||
};
|
};
|
||||||
@@ -578,7 +589,7 @@ namespace Bit.Core.Services
|
|||||||
}
|
}
|
||||||
catch (ApiException e) when (e.Error.StatusCode == System.Net.HttpStatusCode.NotFound || e.Error.StatusCode == System.Net.HttpStatusCode.MethodNotAllowed)
|
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, protectedAttachmentKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
var userId = await _stateService.GetActiveUserIdAsync();
|
var userId = await _stateService.GetActiveUserIdAsync();
|
||||||
@@ -807,14 +818,27 @@ namespace Bit.Core.Services
|
|||||||
|
|
||||||
var bytes = await attachmentResponse.Content.ReadAsByteArrayAsync();
|
var bytes = await attachmentResponse.Content.ReadAsByteArrayAsync();
|
||||||
var decBytes = await _cryptoService.DecryptFromBytesAsync(bytes, null);
|
var decBytes = await _cryptoService.DecryptFromBytesAsync(bytes, null);
|
||||||
var key = await _cryptoService.GetOrgKeyAsync(organizationId);
|
|
||||||
var encFileName = await _cryptoService.EncryptAsync(attachmentView.FileName, key);
|
SymmetricCryptoKey attachmentKey;
|
||||||
var dataEncKey = await _cryptoService.MakeEncKeyAsync(key);
|
EncString protectedAttachmentKey;
|
||||||
var encData = await _cryptoService.EncryptToBytesAsync(decBytes, dataEncKey.Item1);
|
var orgKey = await _cryptoService.GetOrgKeyAsync(organizationId);
|
||||||
|
if (orgKey != null)
|
||||||
|
{
|
||||||
|
(attachmentKey, protectedAttachmentKey) = await _cryptoService.MakeDataEncKeyAsync(orgKey);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var userKey = await _cryptoService.GetUserKeyWithLegacySupportAsync();
|
||||||
|
(attachmentKey, protectedAttachmentKey) = await _cryptoService.MakeDataEncKeyAsync(userKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
var encFileName = await _cryptoService.EncryptAsync(attachmentView.FileName, orgKey);
|
||||||
|
var encFileData = await _cryptoService.EncryptToBytesAsync(decBytes, attachmentKey);
|
||||||
|
|
||||||
var boundary = string.Concat("--BWMobileFormBoundary", DateTime.UtcNow.Ticks);
|
var boundary = string.Concat("--BWMobileFormBoundary", DateTime.UtcNow.Ticks);
|
||||||
var fd = new MultipartFormDataContent(boundary);
|
var fd = new MultipartFormDataContent(boundary);
|
||||||
fd.Add(new StringContent(dataEncKey.Item2.EncryptedString), "key");
|
fd.Add(new StringContent(protectedAttachmentKey.EncryptedString), "key");
|
||||||
fd.Add(new StreamContent(new MemoryStream(encData.Buffer)), "data", encFileName.EncryptedString);
|
fd.Add(new StreamContent(new MemoryStream(encFileData.Buffer)), "data", encFileName.EncryptedString);
|
||||||
await _apiService.PostShareCipherAttachmentAsync(cipherId, attachmentView.Id, fd, organizationId);
|
await _apiService.PostShareCipherAttachmentAsync(cipherId, attachmentView.Id, fd, organizationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,19 @@ namespace Bit.Core.Services
|
|||||||
return await _stateService.GetUserKeyAsync(userId);
|
return await _stateService.GetUserKeyAsync(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<UserKey> GetUserKeyWithLegacySupportAsync(string userId = null)
|
||||||
|
{
|
||||||
|
var userKey = await GetUserKeyAsync();
|
||||||
|
if (userKey != null)
|
||||||
|
{
|
||||||
|
return userKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Legacy support: encryption used to be done with the master key (derived from master password).
|
||||||
|
// Users who have not migrated will have a null user key and must use the master key instead.
|
||||||
|
return (SymmetricCryptoKey)await GetMasterKeyAsync() as UserKey;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<bool> HasUserKeyAsync(string userId = null)
|
public async Task<bool> HasUserKeyAsync(string userId = null)
|
||||||
{
|
{
|
||||||
return await GetUserKeyAsync(userId) != null;
|
return await GetUserKeyAsync(userId) != null;
|
||||||
@@ -176,22 +189,22 @@ namespace Bit.Core.Services
|
|||||||
return new UserKey(decUserKey);
|
return new UserKey(decUserKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Tuple<SymmetricCryptoKey, EncString>> MakeDataEncKey(UserKey key)
|
public async Task<Tuple<SymmetricCryptoKey, EncString>> MakeDataEncKeyAsync(UserKey key)
|
||||||
{
|
{
|
||||||
if (key == null)
|
if (key == null)
|
||||||
{
|
{
|
||||||
throw new Exception("No key provided");
|
throw new Exception("No user key provided");
|
||||||
}
|
}
|
||||||
|
|
||||||
var newSymKey = await _cryptoFunctionService.RandomBytesAsync(64);
|
var newSymKey = await _cryptoFunctionService.RandomBytesAsync(64);
|
||||||
return await BuildProtectedSymmetricKey<SymmetricCryptoKey>(key, newSymKey);
|
return await BuildProtectedSymmetricKey<SymmetricCryptoKey>(key, newSymKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Tuple<SymmetricCryptoKey, EncString>> MakeDataEncKey(OrgKey key)
|
public async Task<Tuple<SymmetricCryptoKey, EncString>> MakeDataEncKeyAsync(OrgKey key)
|
||||||
{
|
{
|
||||||
if (key == null)
|
if (key == null)
|
||||||
{
|
{
|
||||||
throw new Exception("No key provided");
|
throw new Exception("No org key provided");
|
||||||
}
|
}
|
||||||
|
|
||||||
var newSymKey = await _cryptoFunctionService.RandomBytesAsync(64);
|
var newSymKey = await _cryptoFunctionService.RandomBytesAsync(64);
|
||||||
@@ -1152,12 +1165,6 @@ namespace Bit.Core.Services
|
|||||||
return key != null;
|
return key != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> HasEncKeyAsync()
|
|
||||||
{
|
|
||||||
var encKey = await _stateService.GetEncKeyEncryptedAsync();
|
|
||||||
return encKey != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task ClearKeyAsync(string userId = null)
|
public async Task ClearKeyAsync(string userId = null)
|
||||||
{
|
{
|
||||||
await _stateService.SetKeyDecryptedAsync(null, userId);
|
await _stateService.SetKeyDecryptedAsync(null, userId);
|
||||||
@@ -1193,17 +1200,6 @@ namespace Bit.Core.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO(Jake): This isn't used, delete
|
|
||||||
public async Task<Tuple<EncString, SymmetricCryptoKey>> MakeShareKeyAsync()
|
|
||||||
{
|
|
||||||
var shareKey = await _cryptoFunctionService.RandomBytesAsync(64);
|
|
||||||
var publicKey = await GetPublicKeyAsync();
|
|
||||||
var encShareKey = await RsaEncryptAsync(shareKey, publicKey);
|
|
||||||
return new Tuple<EncString, SymmetricCryptoKey>(encShareKey, new SymmetricCryptoKey(shareKey));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public async Task<Tuple<SymmetricCryptoKey, EncString>> MakeEncKeyAsync(SymmetricCryptoKey key)
|
public async Task<Tuple<SymmetricCryptoKey, EncString>> MakeEncKeyAsync(SymmetricCryptoKey key)
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ namespace Bit.Core.Test.Services
|
|||||||
.Returns(encFileName);
|
.Returns(encFileName);
|
||||||
sutProvider.GetDependency<ICryptoService>().EncryptToBytesAsync(data.Buffer, Arg.Any<SymmetricCryptoKey>())
|
sutProvider.GetDependency<ICryptoService>().EncryptToBytesAsync(data.Buffer, Arg.Any<SymmetricCryptoKey>())
|
||||||
.Returns(data);
|
.Returns(data);
|
||||||
sutProvider.GetDependency<ICryptoService>().MakeEncKeyAsync(Arg.Any<SymmetricCryptoKey>()).Returns(new Tuple<SymmetricCryptoKey, EncString>(null, encKey));
|
sutProvider.GetDependency<ICryptoService>().MakeDataEncKeyAsync(Arg.Any<UserKey>()).Returns(new Tuple<SymmetricCryptoKey, EncString>(null, encKey));
|
||||||
sutProvider.GetDependency<IApiService>().PostCipherAttachmentAsync(cipher.Id, Arg.Any<AttachmentRequest>())
|
sutProvider.GetDependency<IApiService>().PostCipherAttachmentAsync(cipher.Id, Arg.Any<AttachmentRequest>())
|
||||||
.Returns(uploadDataResponse);
|
.Returns(uploadDataResponse);
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ namespace Bit.Core.Test.Services
|
|||||||
.Returns(new EncString(fileName));
|
.Returns(new EncString(fileName));
|
||||||
sutProvider.GetDependency<ICryptoService>().EncryptToBytesAsync(data.Buffer, Arg.Any<SymmetricCryptoKey>())
|
sutProvider.GetDependency<ICryptoService>().EncryptToBytesAsync(data.Buffer, Arg.Any<SymmetricCryptoKey>())
|
||||||
.Returns(data);
|
.Returns(data);
|
||||||
sutProvider.GetDependency<ICryptoService>().MakeEncKeyAsync(Arg.Any<SymmetricCryptoKey>()).Returns(new Tuple<SymmetricCryptoKey, EncString>(null, encKey));
|
sutProvider.GetDependency<ICryptoService>().MakeDataEncKeyAsync(Arg.Any<UserKey>()).Returns(new Tuple<SymmetricCryptoKey, EncString>(null, encKey));
|
||||||
sutProvider.GetDependency<IApiService>().PostCipherAttachmentAsync(cipher.Id, Arg.Any<AttachmentRequest>())
|
sutProvider.GetDependency<IApiService>().PostCipherAttachmentAsync(cipher.Id, Arg.Any<AttachmentRequest>())
|
||||||
.Throws(new ApiException(new ErrorResponse { StatusCode = statusCode }));
|
.Throws(new ApiException(new ErrorResponse { StatusCode = statusCode }));
|
||||||
sutProvider.GetDependency<IApiService>().PostCipherAttachmentLegacyAsync(cipher.Id, Arg.Any<MultipartFormDataContent>())
|
sutProvider.GetDependency<IApiService>().PostCipherAttachmentLegacyAsync(cipher.Id, Arg.Any<MultipartFormDataContent>())
|
||||||
@@ -70,7 +70,7 @@ namespace Bit.Core.Test.Services
|
|||||||
.Returns(new EncString(fileName));
|
.Returns(new EncString(fileName));
|
||||||
sutProvider.GetDependency<ICryptoService>().EncryptToBytesAsync(data.Buffer, Arg.Any<SymmetricCryptoKey>())
|
sutProvider.GetDependency<ICryptoService>().EncryptToBytesAsync(data.Buffer, Arg.Any<SymmetricCryptoKey>())
|
||||||
.Returns(data);
|
.Returns(data);
|
||||||
sutProvider.GetDependency<ICryptoService>().MakeEncKeyAsync(Arg.Any<SymmetricCryptoKey>())
|
sutProvider.GetDependency<ICryptoService>().MakeDataEncKeyAsync(Arg.Any<UserKey>())
|
||||||
.Returns(new Tuple<SymmetricCryptoKey, EncString>(null, encKey));
|
.Returns(new Tuple<SymmetricCryptoKey, EncString>(null, encKey));
|
||||||
var expectedException = new ApiException(new ErrorResponse { StatusCode = HttpStatusCode.BadRequest });
|
var expectedException = new ApiException(new ErrorResponse { StatusCode = HttpStatusCode.BadRequest });
|
||||||
sutProvider.GetDependency<IApiService>().PostCipherAttachmentAsync(cipher.Id, Arg.Any<AttachmentRequest>())
|
sutProvider.GetDependency<IApiService>().PostCipherAttachmentAsync(cipher.Id, Arg.Any<AttachmentRequest>())
|
||||||
|
|||||||
Reference in New Issue
Block a user