mirror of
https://github.com/bitwarden/android.git
synced 2024-12-18 23:31:52 +03:00
privatekey, rsa decryption, org key management
This commit is contained in:
parent
e7f3b115a4
commit
498379bb7e
2 changed files with 140 additions and 48 deletions
|
@ -97,7 +97,8 @@ namespace Bit.App.Models
|
||||||
public string InitializationVector { get; private set; }
|
public string InitializationVector { get; private set; }
|
||||||
public string CipherText { get; private set; }
|
public string CipherText { get; private set; }
|
||||||
public string Mac { get; private set; }
|
public string Mac { get; private set; }
|
||||||
public byte[] InitializationVectorBytes => Convert.FromBase64String(InitializationVector);
|
public byte[] InitializationVectorBytes => InitializationVector == null ?
|
||||||
|
null : Convert.FromBase64String(InitializationVector);
|
||||||
public byte[] CipherTextBytes => Convert.FromBase64String(CipherText);
|
public byte[] CipherTextBytes => Convert.FromBase64String(CipherText);
|
||||||
public byte[] MacBytes => Mac == null ? null : Convert.FromBase64String(Mac);
|
public byte[] MacBytes => Mac == null ? null : Convert.FromBase64String(Mac);
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,8 @@ using Bit.App.Abstractions;
|
||||||
using Bit.App.Models;
|
using Bit.App.Models;
|
||||||
using PCLCrypto;
|
using PCLCrypto;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Bit.App.Enums;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Bit.App.Services
|
namespace Bit.App.Services
|
||||||
{
|
{
|
||||||
|
@ -12,6 +14,8 @@ namespace Bit.App.Services
|
||||||
{
|
{
|
||||||
private const string KeyKey = "key";
|
private const string KeyKey = "key";
|
||||||
private const string PreviousKeyKey = "previousKey";
|
private const string PreviousKeyKey = "previousKey";
|
||||||
|
private const string PrivateKeyKey = "privateKey";
|
||||||
|
private const string OrgKeyKeyPrefix = "orgKey:";
|
||||||
private const int InitializationVectorSize = 16;
|
private const int InitializationVectorSize = 16;
|
||||||
|
|
||||||
private readonly ISecureStorageService _secureStorage;
|
private readonly ISecureStorageService _secureStorage;
|
||||||
|
@ -19,6 +23,8 @@ namespace Bit.App.Services
|
||||||
private CryptoKey _key;
|
private CryptoKey _key;
|
||||||
private CryptoKey _legacyEtmKey;
|
private CryptoKey _legacyEtmKey;
|
||||||
private CryptoKey _previousKey;
|
private CryptoKey _previousKey;
|
||||||
|
private IDictionary<Guid, CryptoKey> _orgKeys = new Dictionary<Guid, CryptoKey>();
|
||||||
|
private byte[] _privateKey;
|
||||||
|
|
||||||
public CryptoService(
|
public CryptoService(
|
||||||
ISecureStorageService secureStorage,
|
ISecureStorageService secureStorage,
|
||||||
|
@ -94,6 +100,62 @@ namespace Bit.App.Services
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[] PrivateKey
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if(_privateKey == null)
|
||||||
|
{
|
||||||
|
_privateKey = _secureStorage.Retrieve(PrivateKeyKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _privateKey;
|
||||||
|
}
|
||||||
|
private set
|
||||||
|
{
|
||||||
|
if(value != null)
|
||||||
|
{
|
||||||
|
_secureStorage.Store(PrivateKeyKey, value);
|
||||||
|
_privateKey = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetPrivateKey(CipherString privateKeyEnc, CryptoKey key)
|
||||||
|
{
|
||||||
|
var bytes = DecryptToBytes(privateKeyEnc, key);
|
||||||
|
PrivateKey = bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CryptoKey GetOrgKey(Guid orgId)
|
||||||
|
{
|
||||||
|
if(!_orgKeys.ContainsKey(orgId))
|
||||||
|
{
|
||||||
|
var key = string.Concat(OrgKeyKeyPrefix, orgId);
|
||||||
|
if(!_secureStorage.Contains(key))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_orgKeys[orgId] = new CryptoKey(_secureStorage.Retrieve(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
return _orgKeys[orgId];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddOrgKey(Guid orgId, CipherString encOrgKey, byte[] privateKey)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var decBytes = RsaDecryptToBytes(encOrgKey, privateKey);
|
||||||
|
_orgKeys[orgId] = new CryptoKey(decBytes);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Debug.WriteLine("Cannot set org key. Decryption failed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public CipherString Encrypt(string plaintextValue, CryptoKey key = null)
|
public CipherString Encrypt(string plaintextValue, CryptoKey key = null)
|
||||||
{
|
{
|
||||||
if(key == null)
|
if(key == null)
|
||||||
|
@ -126,53 +188,8 @@ namespace Bit.App.Services
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if(key == null)
|
var bytes = DecryptToBytes(encyptedValue, key);
|
||||||
{
|
return Encoding.UTF8.GetString(bytes, 0, bytes.Length).TrimEnd('\0');
|
||||||
key = Key;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(key == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(key));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(encyptedValue == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(encyptedValue));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(encyptedValue.EncryptionType == Enums.EncryptionType.AesCbc128_HmacSha256_B64 &&
|
|
||||||
key.EncryptionType == Enums.EncryptionType.AesCbc256_B64)
|
|
||||||
{
|
|
||||||
// Old encrypt-then-mac scheme, swap out the key
|
|
||||||
if(_legacyEtmKey == null)
|
|
||||||
{
|
|
||||||
_legacyEtmKey = new CryptoKey(key.Key, Enums.EncryptionType.AesCbc128_HmacSha256_B64);
|
|
||||||
}
|
|
||||||
|
|
||||||
key = _legacyEtmKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(encyptedValue.EncryptionType != key.EncryptionType)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("encType unavailable.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(key.MacKey != null && !string.IsNullOrWhiteSpace(encyptedValue.Mac))
|
|
||||||
{
|
|
||||||
var computedMac = ComputeMac(encyptedValue.CipherTextBytes,
|
|
||||||
encyptedValue.InitializationVectorBytes, key.MacKey);
|
|
||||||
if(computedMac != encyptedValue.Mac)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("MAC failed.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var provider = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7);
|
|
||||||
var cryptoKey = provider.CreateSymmetricKey(key.EncKey);
|
|
||||||
var decryptedBytes = WinRTCrypto.CryptographicEngine.Decrypt(cryptoKey, encyptedValue.CipherTextBytes,
|
|
||||||
encyptedValue.InitializationVectorBytes);
|
|
||||||
return Encoding.UTF8.GetString(decryptedBytes, 0, decryptedBytes.Length).TrimEnd('\0');
|
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
|
@ -181,6 +198,80 @@ namespace Bit.App.Services
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[] DecryptToBytes(CipherString encyptedValue, CryptoKey key = null)
|
||||||
|
{
|
||||||
|
if(key == null)
|
||||||
|
{
|
||||||
|
key = Key;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(key == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(encyptedValue == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(encyptedValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(encyptedValue.EncryptionType == Enums.EncryptionType.AesCbc128_HmacSha256_B64 &&
|
||||||
|
key.EncryptionType == Enums.EncryptionType.AesCbc256_B64)
|
||||||
|
{
|
||||||
|
// Old encrypt-then-mac scheme, swap out the key
|
||||||
|
if(_legacyEtmKey == null)
|
||||||
|
{
|
||||||
|
_legacyEtmKey = new CryptoKey(key.Key, Enums.EncryptionType.AesCbc128_HmacSha256_B64);
|
||||||
|
}
|
||||||
|
|
||||||
|
key = _legacyEtmKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(encyptedValue.EncryptionType != key.EncryptionType)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("encType unavailable.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(key.MacKey != null && !string.IsNullOrWhiteSpace(encyptedValue.Mac))
|
||||||
|
{
|
||||||
|
var computedMac = ComputeMac(encyptedValue.CipherTextBytes,
|
||||||
|
encyptedValue.InitializationVectorBytes, key.MacKey);
|
||||||
|
if(computedMac != encyptedValue.Mac)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("MAC failed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var provider = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7);
|
||||||
|
var cryptoKey = provider.CreateSymmetricKey(key.EncKey);
|
||||||
|
var decryptedBytes = WinRTCrypto.CryptographicEngine.Decrypt(cryptoKey, encyptedValue.CipherTextBytes,
|
||||||
|
encyptedValue.InitializationVectorBytes);
|
||||||
|
return decryptedBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] RsaDecryptToBytes(CipherString encyptedValue, byte[] privateKey)
|
||||||
|
{
|
||||||
|
if(privateKey == null)
|
||||||
|
{
|
||||||
|
privateKey = PrivateKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(privateKey == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(privateKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(encyptedValue.EncryptionType != EncryptionType.RsaOaep_Sha256_B64)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("encType unavailable.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var provider = WinRTCrypto.AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithm.RsaOaepSha256);
|
||||||
|
var cryptoKey = provider.ImportKeyPair(privateKey, CryptographicPrivateKeyBlobType.Pkcs8RawPrivateKeyInfo);
|
||||||
|
var decryptedBytes = WinRTCrypto.CryptographicEngine.Decrypt(cryptoKey, encyptedValue.CipherTextBytes);
|
||||||
|
return decryptedBytes;
|
||||||
|
}
|
||||||
|
|
||||||
private string ComputeMac(byte[] ctBytes, byte[] ivBytes, byte[] macKey)
|
private string ComputeMac(byte[] ctBytes, byte[] ivBytes, byte[] macKey)
|
||||||
{
|
{
|
||||||
if(macKey == null)
|
if(macKey == null)
|
||||||
|
|
Loading…
Reference in a new issue