Skip to content
This repository was archived by the owner on May 4, 2022. It is now read-only.

Commit

Permalink
changes v1.3 to v1.4 (#6) (#7)
Browse files Browse the repository at this point in the history
release 1.4

Co-authored-by: cbeets <87814389+cbeets@users.noreply.github.com>
  • Loading branch information
sweidenbach and cbeets authored Sep 13, 2021
1 parent 65329d4 commit 895026c
Show file tree
Hide file tree
Showing 41 changed files with 1,225 additions and 324 deletions.
5 changes: 5 additions & 0 deletions src/IDWallet.Android/AusweisSDK/AusweisSDK_Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ public bool IsConnected()
try
{
AusweisSdkServiceConnection ausweisSdkServiceConnection = MainActivity.AusweisSdkServiceConnection;

if (ausweisSdkServiceConnection == null)
{
return false;
}

return ausweisSdkServiceConnection.IsConnected;
}
Expand Down
3 changes: 2 additions & 1 deletion src/IDWallet.Android/IDWallet.Android.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@
<Compile Include="Resources\Resource.designer.cs" />
<AndroidResource Include="Resources\xml\provider_paths.xml" />
<TransformFile Include="Resources\values\values.xml" />
<Compile Include="SecurityChecks\HardwareKeyServiceAndroid.cs" />
<Compile Include="SecurityChecks\SecurityChecksAndroid.cs" />
<Compile Include="SplashScreenActivity.cs" />
</ItemGroup>
Expand Down Expand Up @@ -342,7 +343,7 @@
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<ProjectExtensions>
<VisualStudio>
<UserProperties XamarinHotReloadUnhandledDeviceExceptionIDWalletAndroidHideInfoBar="True" TriggeredFromHotReload="False" />
<UserProperties TriggeredFromHotReload="False" XamarinHotReloadUnhandledDeviceExceptionIDWalletAndroidHideInfoBar="True" />
</VisualStudio>
</ProjectExtensions>
</Project>
3 changes: 1 addition & 2 deletions src/IDWallet.Android/Properties/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="10305" android:versionName="1.3" package="com.digitalenabling.idw" android:installLocation="preferExternal">
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="10403" android:versionName="1.4" package="com.digitalenabling.idw" android:installLocation="preferExternal">
<uses-sdk android:minSdkVersion="24" android:targetSdkVersion="29" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!--<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />-->
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
128 changes: 128 additions & 0 deletions src/IDWallet.Android/SecurityChecks/HardwareKeyServiceAndroid.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
using Android.Content.PM;
using Android.Security.Keystore;
using IDWallet.Droid.SecurityChecks;
using IDWallet.Interfaces;
using Java.Security;
using Java.Security.Cert;
using Java.Security.Spec;
using Java.Util;
using Newtonsoft.Json;
using Xamarin.Essentials;

[assembly: Xamarin.Forms.Dependency(typeof(HardwareKeyServiceAndroid))]
namespace IDWallet.Droid.SecurityChecks
{
public class HardwareKeyServiceAndroid : IHardwareKeyService
{
private const string ALIAS = "BaseIdHWKey";
private const string TRANSFORMATION = "SHA256withECDSA";
private const string KEYALGORITHM = KeyProperties.KeyAlgorithmEc;
private const string KEYSTORE_TYPE = "AndroidKeyStore";
private const int AUTHENTICATION_LEVEL = 32768;

public string GetPublicKeyAsBase64(byte[] nonce)
{
// Check if PPK pair is allready generated
bool strongBoxBacked = StrongBoxFeatureAvailable();
bool isPhysicalDevice = IsPhysicalDevice();

GenerateNewKeyPair(nonce, strongBoxBacked);

KeyStore keyStore = KeyStore.GetInstance(KEYSTORE_TYPE);
keyStore.Load(null);
Certificate[] certificates = keyStore.GetCertificateChain(ALIAS);
string[] certArr = CreateCertificateChainArray(certificates);

return JsonConvert.SerializeObject(certArr);
}

public string Sign(byte[] nonce)
{
KeyStore.PrivateKeyEntry entry = null;
bool exists = TryGetPrivateKey(out entry);
if (exists)
{
IPrivateKey privateKey = entry.PrivateKey;

Java.Security.Signature signature = Java.Security.Signature.GetInstance(TRANSFORMATION);
signature.InitSign(privateKey);

signature.Update(nonce);

try
{
byte[] signed = signature.Sign();

Base64.Encoder encoder = Base64.GetEncoder();
return encoder.EncodeToString(signed);
}
catch (SignatureException)
{
return null;
}
}
return null;
}

private bool TryGetPrivateKey(out KeyStore.PrivateKeyEntry entry)
{
KeyStore keyStore = KeyStore.GetInstance(KEYSTORE_TYPE);
keyStore.Load(null);
entry = (KeyStore.PrivateKeyEntry)keyStore.GetEntry(ALIAS, null);

// Check if PPK pair is allready generated
if (entry == null)
{
return false;
}
else
{
return true;
}
}

private static string[] CreateCertificateChainArray(Certificate[] certificates)
{
string[] certArr = new string[certificates.Length];

for (int i = 0; i < certificates.Length; i++)
{
certArr[i] = $"-----BEGIN CERTIFICATE-----{EncodeToString(certificates[i].GetEncoded())}-----END CERTIFICATE-----";
}

return certArr;
}

private static string EncodeToString(byte[] bytesToEncde)
{
Base64.Encoder encoder = Base64.GetEncoder();
return encoder.EncodeToString(bytesToEncde);
}

private static void GenerateNewKeyPair(byte[] nonce, bool strongBoxBacked)
{
KeyPairGenerator kpGenerator = KeyPairGenerator.GetInstance(KEYALGORITHM, KEYSTORE_TYPE);
// This failes, when the user does not have a biometric enrollment
KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(ALIAS, KeyStorePurpose.Sign)
.SetDigests(KeyProperties.DigestSha256)
.SetAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
.SetRandomizedEncryptionRequired(false)
.SetAttestationChallenge(nonce)
.SetIsStrongBoxBacked(strongBoxBacked)
.Build();

kpGenerator.Initialize(spec);
kpGenerator.GenerateKeyPair();
}

private bool StrongBoxFeatureAvailable()
{
return Android.App.Application.Context.PackageManager.HasSystemFeature(PackageManager.FeatureStrongboxKeystore);
}

private bool IsPhysicalDevice()
{
return DeviceInfo.DeviceType == DeviceType.Physical;
}
}
}
1 change: 1 addition & 0 deletions src/IDWallet.iOS/IDWallet.iOS.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
<Compile Include="Renderer\CircleViewRenderer.cs" />
<Compile Include="Renderer\PinItemViewRenderer.cs" />
<Compile Include="Renderer\ZFRippleButton.cs" />
<Compile Include="SecurityChecks\HardwareKeyServiceIOS.cs" />
<Compile Include="SecurityChecks\SecurityChecksIos.cs" />
<None Include="Entitlements.plist" />
<None Include="Info.plist" />
Expand Down
4 changes: 2 additions & 2 deletions src/IDWallet.iOS/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<key>CFBundleDisplayName</key>
<string>ID Wallet</string>
<key>CFBundleVersion</key>
<string>10305</string>
<string>10403</string>
<key>CFBundleName</key>
<string>ID Wallet</string>
<key>UIAppFonts</key>
Expand Down Expand Up @@ -77,7 +77,7 @@
<key>CFBundleIdentifier</key>
<string>com.digitalenabling.idw</string>
<key>CFBundleShortVersionString</key>
<string>1.3</string>
<string>1.4</string>
<key>XSAppIconAssets</key>
<string>Assets.xcassets/AppIcons.appiconset</string>
<key>UILaunchStoryboardName</key>
Expand Down
107 changes: 107 additions & 0 deletions src/IDWallet.iOS/SecurityChecks/HardwareKeyServiceIOS.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
using IDWallet.Interfaces;
using IDWallet.iOS.SecurityChecks;
using IDWallet.Utils;
using Foundation;
using Security;
using System.Diagnostics;

[assembly: Xamarin.Forms.Dependency(typeof(HardwareKeyServiceIOS))]
namespace IDWallet.iOS.SecurityChecks
{
public class HardwareKeyServiceIOS : IHardwareKeyService
{
private const string ALIAS = "BaseIdHWKey";

public string GetPublicKeyAsBase64(byte[] nonce)
{
SecKey privKey = GetPrivateKey();
while (privKey != null)
{
Debug.WriteLine("Key found");
var deleted = SecKeyChain.Remove(new SecRecord(SecKind.Key)
{
ApplicationTag = NSData.FromString(ALIAS),
KeyType = SecKeyType.ECSecPrimeRandom,
});

Debug.WriteLine($"Key deleted: {deleted}");

privKey = GetPrivateKey();
}

CreateKey(nonce);

privKey = GetPrivateKey();

SecKey publKey = privKey.GetPublicKey();
return publKey.GetExternalRepresentation().GetBase64EncodedString(NSDataBase64EncodingOptions.None);
}

public string Sign(byte[] nonce)
{
SecKey key = GetPrivateKey();
if (key != null)
{
NSError nSError;
NSData encrypt = key.CreateSignature(SecKeyAlgorithm.EcdsaSignatureMessageX962Sha256, NSData.FromArray(nonce), out nSError);

return encrypt.GetBase64EncodedString(NSDataBase64EncodingOptions.None);
}

return null;
}

public void CreateKey(byte[] nonce)
{
using (SecAccessControl access = new SecAccessControl(SecAccessible.WhenUnlockedThisDeviceOnly, SecAccessControlCreateFlags.PrivateKeyUsage))
{
SecKeyGenerationParameters keyParameters = new SecKeyGenerationParameters
{
KeyType = SecKeyType.ECSecPrimeRandom,
KeySizeInBits = 256,
Label = ALIAS,
ApplicationTag = NSData.FromString(ALIAS),
// CanSign = true,
PrivateKeyAttrs = new SecKeyParameters
{
//IsPermanent = true,
ApplicationTag = NSData.FromString(ALIAS),
AccessControl = access
},
PublicKeyAttrs = new SecKeyParameters
{
ApplicationTag = NSData.FromArray(Sha256.sha256(nonce))
}
};

NSError error;
SecKey genKey = SecKey.CreateRandomKey(keyParameters, out error);
if (genKey == null)
{
throw new NSErrorException(error);
}

SecRecord sr = new SecRecord(SecKind.Key)
{
ApplicationTag = NSData.FromString(ALIAS),
KeyType = SecKeyType.ECSecPrimeRandom,
};
sr.SetKey(genKey);

SecStatusCode ssc = SecKeyChain.Add(sr);
}
}

private SecKey GetPrivateKey()
{
object privateKey = SecKeyChain.QueryAsConcreteType(
new SecRecord(SecKind.Key)
{
ApplicationTag = NSData.FromString(ALIAS),
KeyType = SecKeyType.ECSecPrimeRandom,
},
out SecStatusCode code);
return code == SecStatusCode.Success ? privateKey as SecKey : null;
}
}
}
2 changes: 1 addition & 1 deletion src/IDWallet.iOS/SecurityChecks/SecurityChecksIos.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public async void SafetyCheck(byte[] nonce)
{
string key = await attestService.GenerateKeyAsync();

NSData attest = await attestService.AttestKeyAsync(key, NSData.FromArray(nonce));
NSData attest = await attestService.AttestKeyAsync(key, NSData.FromArray(Sha256.sha256(nonce)));

App.SafetyKey = key;
App.SafetyResult = attest.GetBase64EncodedString(new NSDataBase64EncodingOptions());
Expand Down
Loading

0 comments on commit 895026c

Please sign in to comment.