Instantly share code, notes, and snippets.

Embed
What would you like to do?
Helper class to securely create encryption keys without the need of user interaction on Android. There are way to much samples that use some hardcoded values which could be compromised. The keys of this class are only available for usage within the app that created them. Plus, if the app gets uninstalled, the keys get deleted.
using Android.Content;
using Android.OS;
using Android.Security;
using Android.Security.Keystore;
using Java.Math;
using Java.Security;
using Javax.Security.Auth.X500;
using Calendar = Android.Icu.Util.Calendar;
using CalendarField = Android.Icu.Util.CalendarField;
namespace [YOURNAMESPACEHERE]
{
public class PlatformEncryptionKeyHelper
{
//do not change this name, this is where the keys have to be stored on Android
static readonly string KEYSTORE_NAME = "AndroidKeyStore";
private readonly KeyStore _androidKeyStore;
private readonly Context _context;
private readonly string _keyName;
//Supported sizes: 512, 768, 1024, 2048, 3072, 4096
//default is 2048
//Higher value means longer processing time!
public int KeySize { get; set; } = 2048;
public PlatformEncryptionKeyHelper(Context context, string keyName)
{
_context = context;
_keyName = keyName.ToLowerInvariant();
_androidKeyStore = KeyStore.GetInstance(KEYSTORE_NAME);
_androidKeyStore.Load(null);
}
public bool DeleteKey()
{
if (!_androidKeyStore.ContainsAlias(_keyName))
return false;
_androidKeyStore.DeleteEntry(_keyName);
return true;
}
public bool KeysExist()
{
return _androidKeyStore.ContainsAlias(_keyName);
}
public IKey GetPrivateKey()
{
if (!_androidKeyStore.ContainsAlias(_keyName))
return null;
return _androidKeyStore.GetKey(_keyName, null);
}
public IKey GetPublicKey()
{
if (!_androidKeyStore.ContainsAlias(_keyName))
return null;
return _androidKeyStore.GetCertificate(_keyName)?.PublicKey;
}
public void CreateKeyPair()
{
DeleteKey();
KeyPairGenerator keyGenerator =
KeyPairGenerator.GetInstance(KeyProperties.KeyAlgorithmRsa, KEYSTORE_NAME);
if (Build.VERSION.SdkInt >= BuildVersionCodes.JellyBeanMr2 &&
Build.VERSION.SdkInt <= BuildVersionCodes.LollipopMr1)
{
var calendar = Calendar.GetInstance(_context.Resources.Configuration.Locale);
var endDate = Calendar.GetInstance(_context.Resources.Configuration.Locale);
endDate.Add(CalendarField.Year, 20);
//this API is obsolete after Android M, but I am supporting Android L, so I need this
#pragma warning disable 618
var builder = new KeyPairGeneratorSpec.Builder(_context)
#pragma warning restore 618
.SetAlias(_keyName).SetSerialNumber(BigInteger.One)
.SetSubject(new X500Principal($"CN={_keyName} CA Certificate"))
.SetStartDate(calendar.Time)
.SetEndDate(endDate.Time).SetKeySize(KeySize);
keyGenerator.Initialize(builder.Build());
}
else if (Build.VERSION.SdkInt >= BuildVersionCodes.M)
{
var builder =
new KeyGenParameterSpec.Builder(_keyName, KeyStorePurpose.Encrypt | KeyStorePurpose.Decrypt)
.SetBlockModes(KeyProperties.BlockModeEcb)
.SetEncryptionPaddings(KeyProperties.EncryptionPaddingRsaPkcs1)
.SetRandomizedEncryptionRequired(false).SetKeySize(KeySize);
keyGenerator.Initialize(builder.Build());
}
keyGenerator.GenerateKeyPair();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment