mirror of
https://github.com/bitwarden/android.git
synced 2025-03-14 02:08:48 +03:00
crypto function service
This commit is contained in:
parent
fca1dbd6ec
commit
cb9dddc7a7
11 changed files with 296 additions and 10 deletions
|
@ -49,6 +49,9 @@
|
|||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Portable.BouncyCastle">
|
||||
<Version>1.8.5</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Essentials">
|
||||
<Version>1.1.0</Version>
|
||||
</PackageReference>
|
||||
|
@ -64,6 +67,7 @@
|
|||
<Compile Include="MainActivity.cs" />
|
||||
<Compile Include="Resources\Resource.designer.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Services\CryptoPrimitiveService.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidAsset Include="Assets\FontAwesome.ttf" />
|
||||
|
|
16
src/Android/Resources/Resource.designer.cs
generated
16
src/Android/Resources/Resource.designer.cs
generated
|
@ -26,6 +26,8 @@ namespace Bit.Droid
|
|||
|
||||
public static void UpdateIdValues()
|
||||
{
|
||||
global::PCLCrypto.Resource.String.ApplicationName = global::Bit.Droid.Resource.String.ApplicationName;
|
||||
global::PCLCrypto.Resource.String.Hello = global::Bit.Droid.Resource.String.Hello;
|
||||
global::Xamarin.Essentials.Resource.Attribute.alpha = global::Bit.Droid.Resource.Attribute.alpha;
|
||||
global::Xamarin.Essentials.Resource.Attribute.coordinatorLayoutStyle = global::Bit.Droid.Resource.Attribute.coordinatorLayoutStyle;
|
||||
global::Xamarin.Essentials.Resource.Attribute.font = global::Bit.Droid.Resource.Attribute.font;
|
||||
|
@ -7693,13 +7695,19 @@ namespace Bit.Droid
|
|||
{
|
||||
|
||||
// aapt resource value: 0x7f0b004f
|
||||
public const int AutoFillServiceDescription = 2131427407;
|
||||
public const int ApplicationName = 2131427407;
|
||||
|
||||
// aapt resource value: 0x7f0b004e
|
||||
public const int AutoFillServiceSummary = 2131427406;
|
||||
// aapt resource value: 0x7f0b0051
|
||||
public const int AutoFillServiceDescription = 2131427409;
|
||||
|
||||
// aapt resource value: 0x7f0b0050
|
||||
public const int MyVault = 2131427408;
|
||||
public const int AutoFillServiceSummary = 2131427408;
|
||||
|
||||
// aapt resource value: 0x7f0b004e
|
||||
public const int Hello = 2131427406;
|
||||
|
||||
// aapt resource value: 0x7f0b0052
|
||||
public const int MyVault = 2131427410;
|
||||
|
||||
// aapt resource value: 0x7f0b0018
|
||||
public const int abc_action_bar_home_description = 2131427352;
|
||||
|
|
37
src/Android/Services/CryptoPrimitiveService.cs
Normal file
37
src/Android/Services/CryptoPrimitiveService.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Enums;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Digests;
|
||||
using Org.BouncyCastle.Crypto.Generators;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using System;
|
||||
|
||||
namespace Bit.Droid.Services
|
||||
{
|
||||
public class CryptoPrimitiveService : ICryptoPrimitiveService
|
||||
{
|
||||
public byte[] Pbkdf2(byte[] password, byte[] salt, CryptoHashAlgorithm algorithm, int iterations)
|
||||
{
|
||||
int keySize = 256;
|
||||
IDigest digest = null;
|
||||
if(algorithm == CryptoHashAlgorithm.Sha256)
|
||||
{
|
||||
keySize = 256;
|
||||
digest = new Sha256Digest();
|
||||
}
|
||||
else if(algorithm == CryptoHashAlgorithm.Sha512)
|
||||
{
|
||||
keySize = 512;
|
||||
digest = new Sha512Digest();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("Unsupported PBKDF2 algorithm.");
|
||||
}
|
||||
|
||||
var generator = new Pkcs5S2ParametersGenerator(digest);
|
||||
generator.Init(password, salt, iterations);
|
||||
return ((KeyParameter)generator.GenerateDerivedMacParameters(keySize)).GetKey();
|
||||
}
|
||||
}
|
||||
}
|
10
src/Core/Abstractions/ICryptoFunctionService.cs
Normal file
10
src/Core/Abstractions/ICryptoFunctionService.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Bit.Core.Abstractions
|
||||
{
|
||||
public interface ICryptoFunctionService
|
||||
{
|
||||
}
|
||||
}
|
9
src/Core/Abstractions/ICryptoPrimitiveService.cs
Normal file
9
src/Core/Abstractions/ICryptoPrimitiveService.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
using Bit.Core.Enums;
|
||||
|
||||
namespace Bit.Core.Abstractions
|
||||
{
|
||||
public interface ICryptoPrimitiveService
|
||||
{
|
||||
byte[] Pbkdf2(byte[] password, byte[] salt, CryptoHashAlgorithm algorithm, int iterations);
|
||||
}
|
||||
}
|
|
@ -14,6 +14,7 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="LiteDB" Version="4.1.4" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
|
||||
<PackageReference Include="PCLCrypto" Version="2.0.147" />
|
||||
<PackageReference Include="Xamarin.Essentials" Version="1.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
10
src/Core/Enums/CryptoHashAlgorithm.cs
Normal file
10
src/Core/Enums/CryptoHashAlgorithm.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
namespace Bit.Core.Enums
|
||||
{
|
||||
public enum CryptoHashAlgorithm
|
||||
{
|
||||
Sha1 = 0,
|
||||
Sha256 = 1,
|
||||
Sha512 = 2,
|
||||
Md5 = 3
|
||||
}
|
||||
}
|
162
src/Core/Services/PclCryptoFunctionService.cs
Normal file
162
src/Core/Services/PclCryptoFunctionService.cs
Normal file
|
@ -0,0 +1,162 @@
|
|||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Enums;
|
||||
using PCLCrypto;
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static PCLCrypto.WinRTCrypto;
|
||||
|
||||
namespace Bit.Core.Services
|
||||
{
|
||||
public class PclCryptoFunctionService
|
||||
{
|
||||
private readonly ICryptoPrimitiveService _cryptoPrimitiveService;
|
||||
|
||||
public PclCryptoFunctionService(ICryptoPrimitiveService cryptoPrimitiveService)
|
||||
{
|
||||
_cryptoPrimitiveService = cryptoPrimitiveService;
|
||||
}
|
||||
|
||||
public Task<byte[]> Pbkdf2Async(string password, string salt, CryptoHashAlgorithm algorithm, int iterations)
|
||||
{
|
||||
return Pbkdf2Async(Encoding.UTF8.GetBytes(password), Encoding.UTF8.GetBytes(salt), algorithm, iterations);
|
||||
}
|
||||
|
||||
public Task<byte[]> Pbkdf2Async(byte[] password, string salt, CryptoHashAlgorithm algorithm, int iterations)
|
||||
{
|
||||
return Pbkdf2Async(password, Encoding.UTF8.GetBytes(salt), algorithm, iterations);
|
||||
}
|
||||
|
||||
public Task<byte[]> Pbkdf2Async(string password, byte[] salt, CryptoHashAlgorithm algorithm, int iterations)
|
||||
{
|
||||
return Pbkdf2Async(Encoding.UTF8.GetBytes(password), salt, algorithm, iterations);
|
||||
}
|
||||
|
||||
public Task<byte[]> Pbkdf2Async(byte[] password, byte[] salt, CryptoHashAlgorithm algorithm, int iterations)
|
||||
{
|
||||
if(algorithm != CryptoHashAlgorithm.Sha256 && algorithm != CryptoHashAlgorithm.Sha512)
|
||||
{
|
||||
throw new ArgumentException("Unsupported PBKDF2 algorithm.");
|
||||
}
|
||||
return Task.FromResult(_cryptoPrimitiveService.Pbkdf2(password, salt, algorithm, iterations));
|
||||
}
|
||||
|
||||
public Task<byte[]> HashAsync(string value, CryptoHashAlgorithm algorithm)
|
||||
{
|
||||
return HashAsync(Encoding.UTF8.GetBytes(value), algorithm);
|
||||
}
|
||||
|
||||
public Task<byte[]> HashAsync(byte[] value, CryptoHashAlgorithm algorithm)
|
||||
{
|
||||
var provider = HashAlgorithmProvider.OpenAlgorithm(ToHashAlgorithm(algorithm));
|
||||
return Task.FromResult(provider.HashData(value));
|
||||
}
|
||||
|
||||
public Task<byte[]> HmacAsync(byte[] value, byte[] key, CryptoHashAlgorithm algorithm)
|
||||
{
|
||||
var provider = MacAlgorithmProvider.OpenAlgorithm(ToMacAlgorithm(algorithm));
|
||||
var hasher = provider.CreateHash(key);
|
||||
hasher.Append(value);
|
||||
return Task.FromResult(hasher.GetValueAndReset());
|
||||
}
|
||||
|
||||
public Task<byte[]> AesEncryptAsync(byte[] data, byte[] iv, byte[] key)
|
||||
{
|
||||
var provider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7);
|
||||
var cryptoKey = provider.CreateSymmetricKey(key);
|
||||
return Task.FromResult(CryptographicEngine.Encrypt(cryptoKey, data, iv));
|
||||
}
|
||||
|
||||
public Task<byte[]> AesDecryptAsync(byte[] data, byte[] iv, byte[] key)
|
||||
{
|
||||
var provider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7);
|
||||
var cryptoKey = provider.CreateSymmetricKey(key);
|
||||
return Task.FromResult(CryptographicEngine.Decrypt(cryptoKey, data, iv));
|
||||
}
|
||||
|
||||
public Task<byte[]> RsaEncryptAsync(byte[] data, byte[] publicKey, CryptoHashAlgorithm algorithm)
|
||||
{
|
||||
var provider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(ToAsymmetricAlgorithm(algorithm));
|
||||
var cryptoKey = provider.ImportPublicKey(publicKey,
|
||||
CryptographicPublicKeyBlobType.X509SubjectPublicKeyInfo);
|
||||
return Task.FromResult(CryptographicEngine.Encrypt(cryptoKey, data));
|
||||
}
|
||||
|
||||
public Task<byte[]> RsaDecryptAsync(byte[] data, byte[] privateKey, CryptoHashAlgorithm algorithm)
|
||||
{
|
||||
var provider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(ToAsymmetricAlgorithm(algorithm));
|
||||
var cryptoKey = provider.ImportKeyPair(privateKey, CryptographicPrivateKeyBlobType.Pkcs8RawPrivateKeyInfo);
|
||||
return Task.FromResult(CryptographicEngine.Decrypt(cryptoKey, data));
|
||||
}
|
||||
|
||||
public Task<byte[]> RsaExtractPublicKeyAsync(byte[] privateKey)
|
||||
{
|
||||
// Have to specify some algorithm
|
||||
var provider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithm.RsaOaepSha1);
|
||||
var cryptoKey = provider.ImportKeyPair(privateKey, CryptographicPrivateKeyBlobType.Pkcs8RawPrivateKeyInfo);
|
||||
return Task.FromResult(cryptoKey.ExportPublicKey(CryptographicPublicKeyBlobType.X509SubjectPublicKeyInfo));
|
||||
}
|
||||
|
||||
public Task<Tuple<byte[], byte[]>> RsaGenerateKeyPairAsync(int length)
|
||||
{
|
||||
// Have to specify some algorithm
|
||||
var provider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithm.RsaOaepSha1);
|
||||
var cryptoKey = provider.CreateKeyPair(length);
|
||||
var publicKey = cryptoKey.ExportPublicKey(CryptographicPublicKeyBlobType.X509SubjectPublicKeyInfo);
|
||||
var privateKey = cryptoKey.Export(CryptographicPrivateKeyBlobType.Pkcs8RawPrivateKeyInfo);
|
||||
return Task.FromResult(new Tuple<byte[], byte[]>(publicKey, privateKey));
|
||||
}
|
||||
|
||||
public Task<byte[]> RandomBytesAsync(int length)
|
||||
{
|
||||
return Task.FromResult(CryptographicBuffer.GenerateRandom(length));
|
||||
}
|
||||
|
||||
private HashAlgorithm ToHashAlgorithm(CryptoHashAlgorithm algorithm)
|
||||
{
|
||||
switch(algorithm)
|
||||
{
|
||||
case CryptoHashAlgorithm.Sha1:
|
||||
return HashAlgorithm.Sha1;
|
||||
case CryptoHashAlgorithm.Sha256:
|
||||
return HashAlgorithm.Sha256;
|
||||
case CryptoHashAlgorithm.Sha512:
|
||||
return HashAlgorithm.Sha512;
|
||||
case CryptoHashAlgorithm.Md5:
|
||||
return HashAlgorithm.Md5;
|
||||
default:
|
||||
throw new ArgumentException("Unsupported hash algorithm.");
|
||||
}
|
||||
}
|
||||
|
||||
private MacAlgorithm ToMacAlgorithm(CryptoHashAlgorithm algorithm)
|
||||
{
|
||||
switch(algorithm)
|
||||
{
|
||||
case CryptoHashAlgorithm.Sha1:
|
||||
return MacAlgorithm.HmacSha1;
|
||||
case CryptoHashAlgorithm.Sha256:
|
||||
return MacAlgorithm.HmacSha256;
|
||||
case CryptoHashAlgorithm.Sha512:
|
||||
return MacAlgorithm.HmacSha512;
|
||||
default:
|
||||
throw new ArgumentException("Unsupported mac algorithm.");
|
||||
}
|
||||
}
|
||||
|
||||
private AsymmetricAlgorithm ToAsymmetricAlgorithm(CryptoHashAlgorithm algorithm)
|
||||
{
|
||||
switch(algorithm)
|
||||
{
|
||||
case CryptoHashAlgorithm.Sha1:
|
||||
return AsymmetricAlgorithm.RsaOaepSha1;
|
||||
// RsaOaepSha256 is not supported on iOS
|
||||
// ref: https://github.com/AArnott/PCLCrypto/issues/124
|
||||
// case CryptoHashAlgorithm.SHA256:
|
||||
// return AsymmetricAlgorithm.RsaOaepSha256;
|
||||
default:
|
||||
throw new ArgumentException("Unsupported asymmetric algorithm.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Foundation;
|
||||
using UIKit;
|
||||
using UIKit;
|
||||
|
||||
namespace Bit.iOS
|
||||
{
|
||||
|
@ -12,6 +7,8 @@ namespace Bit.iOS
|
|||
// This is the main entry point of the application.
|
||||
static void Main(string[] args)
|
||||
{
|
||||
ObjCRuntime.Dlfcn.dlopen(ObjCRuntime.Constants.libSystemLibrary, 0);
|
||||
|
||||
// if you want to use a different Application Delegate class from "AppDelegate"
|
||||
// you can specify it here.
|
||||
UIApplication.Main(args, null, "AppDelegate");
|
||||
|
|
47
src/iOS/Services/CryptoPrimitiveService.cs
Normal file
47
src/iOS/Services/CryptoPrimitiveService.cs
Normal file
|
@ -0,0 +1,47 @@
|
|||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Enums;
|
||||
using Foundation;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Bit.iOS.Services
|
||||
{
|
||||
public class CryptoPrimitiveService : ICryptoPrimitiveService
|
||||
{
|
||||
private const uint PBKDFAlgorithm = 2; // kCCPBKDF2
|
||||
|
||||
public byte[] Pbkdf2(byte[] password, byte[] salt, CryptoHashAlgorithm algorithm, int iterations)
|
||||
{
|
||||
uint keySize = 32;
|
||||
uint pseudoRandomAlgorithm = 3; // kCCPRFHmacAlgSHA256
|
||||
if(algorithm == CryptoHashAlgorithm.Sha512)
|
||||
{
|
||||
keySize = 64;
|
||||
pseudoRandomAlgorithm = 5; // kCCPRFHmacAlgSHA512
|
||||
}
|
||||
else if(algorithm != CryptoHashAlgorithm.Sha256)
|
||||
{
|
||||
throw new ArgumentException("Unsupported PBKDF2 algorithm.");
|
||||
}
|
||||
|
||||
var keyData = new NSMutableData();
|
||||
keyData.Length = keySize;
|
||||
|
||||
var passwordData = NSData.FromArray(password);
|
||||
var saltData = NSData.FromArray(salt);
|
||||
|
||||
var result = CCKeyCerivationPBKDF(PBKDFAlgorithm, passwordData.Bytes, passwordData.Length, saltData.Bytes,
|
||||
saltData.Length, pseudoRandomAlgorithm, Convert.ToUInt32(iterations), keyData.MutableBytes,
|
||||
keyData.Length);
|
||||
|
||||
byte[] keyBytes = new byte[keyData.Length];
|
||||
Marshal.Copy(keyData.Bytes, keyBytes, 0, Convert.ToInt32(keyData.Length));
|
||||
return keyBytes;
|
||||
}
|
||||
|
||||
// ref: http://opensource.apple.com/source/CommonCrypto/CommonCrypto-55010/CommonCrypto/CommonKeyDerivation.h
|
||||
[DllImport(ObjCRuntime.Constants.libSystemLibrary, EntryPoint = "CCKeyDerivationPBKDF")]
|
||||
private extern static int CCKeyCerivationPBKDF(uint algorithm, IntPtr password, nuint passwordLen,
|
||||
IntPtr salt, nuint saltLen, uint prf, nuint rounds, IntPtr derivedKey, nuint derivedKeyLength);
|
||||
}
|
||||
}
|
|
@ -92,6 +92,7 @@
|
|||
<ItemGroup>
|
||||
<Compile Include="Main.cs" />
|
||||
<Compile Include="AppDelegate.cs" />
|
||||
<Compile Include="Services\CryptoPrimitiveService.cs" />
|
||||
<None Include="Entitlements.plist" />
|
||||
<None Include="Info.plist" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
|
|
Loading…
Add table
Reference in a new issue