Is it possible to secure the Android KeyChain with an HSM? - android

For security reasons I want to store my private key in the HSM and then share the private key with another app via the KeyChain. The KeyStore mentions that it can be backed by the HSM but I haven't found any documentation that states it's possible with the KeyChain.
Based on the KeyChain documentation, the KeyChain is the proper way to share between apps:
Use the KeyChain API when you want system-wide credentials. When an
app requests the use of any credential through the KeyChain API, users
get to choose, through a system-provided UI, which of the installed
credentials an app can access. This allows several apps to use the
same set of credentials with user consent.
So, is it possible to secure the Android KeyChain with an HSM?

After a lot of searching, I finally found that the answer is yes, it is possible.
The Android 4.3 changelog seems to be the only place that documents it:
Android also now supports hardware-backed storage for your KeyChain
credentials, providing more security by making the keys unavailable
for extraction. That is, once keys are in a hardware-backed key store
(Secure Element, TPM, or TrustZone), they can be used for
cryptographic operations but the private key material cannot be
exported. Even the OS kernel cannot access this key material.
I tested this with code and it seems that once you import a KeyPair into the KeyChain it is automatically put into secure hardware. This is the Kotlin code that I ran to test:
GlobalScope.launch {
context?.let { it1 ->
val privKey = KeyChain.getPrivateKey(it1, "device_certificate")
Log.d("App", privKey.toString()) // Shows that this is an AndroidKeyStoreRSAPrivateKey
val keyFactory: KeyFactory = KeyFactory.getInstance(privKey?.algorithm, "AndroidKeyStore")
val keyInfo: KeyInfo = keyFactory.getKeySpec(privKey, KeyInfo::class.java)
if (keyInfo.isInsideSecureHardware()) {
Log.d("App", "The key is in secure hardware!")
}
else {
Log.d("App", "The key is not in secure hardware!")
}
}
}
which printed "The key is in secure hardware!".

Related

Using the Android hardware-backed KeyStore

I wish to use the Android hardware-backed KeyStore, but I'm concerned about security and usability.
From what I've read here, KeyStore gets wiped when the user changes the device lock, unless setEncryptionRequired() is omitted. For usability sake, it seems this needs to be done, otherwise all hardware-backed keys would get wiped once the device lock is modified.
However, I've also read here that hardware-backed keys are not actually stored in the TEE, but rather, stored as key files in /data/misc/keystore/user_0/, encrypted by a device specific key that is stored within the TEE. Since a change in device lock wipes the KeyStore, it seems that the device specific key is derived from the device lock.
For security reasons, it makes sense to encrypt the key file, otherwise any root user would be able to read the key files and extract the private key, since they'd presumably be in they clear.
So I'm kind of in a dilemma. For usability sake, I should omit setEncryptionRequired(), but for security sake, I should set setEncryptionRequired().
Lastly, is it possible import a private key into the hardware-backed KeyStore using setKeyEntry()? I'm able to do so with no errors but I'm not sure if it's hardware-backed.
Is my understanding correct?
setEncryptionRequired() was deprecated in Android 6.0 (Marshmallow), and never really accomplished very much. The security of Android KeyStore depends on the TEE, not the password.
The blog post you linked to is out of date, at least on devices running Android 6.0 or later. On those devices, you should not use setEncryptionRequired(), and your keys will not be deleted until your app is uninstalled (or a factory reset is done, or your app deletes them). Your keys will be securely wrapped by secret keys that never leave the TEE. In fact, your keys will never leave the TEE in plaintext. When you use your keys, the data is passed into the TEE along with the encrypted key. The TEE unwraps the key then processes and returns the encrypted/signed/whatever data.
Yes, you can import private keys using setKeyEntry(). If you want to be sure that your key is hardware-backed, use KeyInfo.isInsideSecureHardware(). For example (this is from the documentation):
PrivateKey key = ...; // Android KeyStore key
KeyFactory factory = KeyFactory.getInstance(key.getAlgorithm(), "AndroidKeyStore");
KeyInfo keyInfo;
boolean isHardwareBacked = false;
try {
keyInfo = factory.getKeySpec(key, KeyInfo.class);
isHardwareBacked = keyInfo.isInsideSecureHardware();
} catch (InvalidKeySpecException e) {
// Not an Android KeyStore key.
}

Android Keystore's password protection

We used Anroid Keystore to store some confidential data and set up a password for Keystore. This passwords are used in conjunction with the KeyStore class in the load, getKey and setKeyEntry methods.
The Keystore itself is encrypted and app can only view and query its own data so we can say that data are somewhat secure inside Keystore but how we can secure the password that associated with keystore account? I found many example online and most of them having hardcoded password in code or use null parameter.
Please see in below example. I want to know what is the best approach to secure hardcoded password?
Want to find a safe way in android device itself to store this hardcoded password. Assume that moving it to external place like database, service call etc. options are NOT available.
Context context;
KeyStore ks;
KeyStore.PasswordProtection prot;
static readonly object fileLock = new object ();
const string FileName = "Xamarin.Social.Accounts";
static readonly char[] Password = "3295043EA18CA264B2C40E0B72051DEF2D07AD2B4593F43DDDE1515A7EC32617".ToCharArray ();
public AndroidAccountStore (Context context)
{
this.context = context;
ks = KeyStore.GetInstance (KeyStore.DefaultType);
**prot = new KeyStore.PasswordProtection (Password);**
try {
lock (fileLock) {
using (var s = context.OpenFileInput (FileName)) {
ks.Load (s, Password);
}
}
}
catch (FileNotFoundException) {
//ks.Load (null, Password);
LoadEmptyKeyStore (Password);
}
}
Assume that moving it to external place like database, service call etc. is NOT possible
You want to securely store sensitive information on the local user's machine.
The only way to do that is encrypting it. The most popular encryption algorithm is AES, and luckily Microsoft included an implementation of it in C#.
However, encryption uses a secret key to encrypt/decrypt the data, so we're basically moving the problem back - now we need to store that encryption key securely.
You could hard-code that key in the app, but a dedicated attacker could still get it and decrypt the password.
Instead, get that password from the user. Ask them to provide a password, hash it (using e.g. SHA256) and use the hash as the key for the encryption.

Can I have access to Trusted Certificate Entries in Android from my App

I have this scenario where my App needs to make requests towards a secure server (NON http(s), actually it is about SIP protocol but the question should apply to any non http(s) protocol), and I need be able to tell if the server is considered trusted, based on the System Default Trusted certificates installed in my Android device's keystore.
The problem is that after checking all the APIs Android provides for certificates (like KeyStore, KeyChain, etc) I haven't been able to find a solution.
Seems that each app, even though it can gain access to the System Default keystore of the device, it can only access it's own resources, not global, even when we are talking about TrustedCertificateEntry-type entries.
Is there anything I'm missing here?
Seems like a pretty valid use case for non-https authentication
Best regards,
Antonis
Finally, managed to find a way to do this, so let me share in case this can be useful to others. Turns out Android gives access to system wide trusted certificates. The detail here (and the reason it didn't work for me previously) was the keystore 'type' identifier that I used:
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
Which I believe was trying to find actual keys, which off course shouldn't be shared. So after some digging I found that there's a separate type, AndroidCAStore, which did the trick for me. So here's a working code excerpt, that just prints out certificates:
try {
KeyStore ks = KeyStore.getInstance("AndroidCAStore");
ks.load(null);
try {
Enumeration<String> aliases = ks.aliases();
while (aliases.hasMoreElements()) {
Certificate cert = ks.getCertificate(aliases.nextElement());
Log.e(TAG, "Certificate: " + cert.toString());
}
}
catch(Exception e) {
e.printStackTrace();
}
}
catch (IOException|NoSuchAlgorithmException|KeyStoreException|CertificateException e) {
e.printStackTrace();
}

Where to keep the OAuth client credentials on Android

I have an Android application that interacts with a WebAPI through OAuth security. For getting the access token, I need to send the OAuth credentials (i.e. client id and client secret) in the header of the request. My question is, where should I keep these 2 values (client id and client secret) for the application to use it when required. Currently, I have just hardcoded it in the call. Is it safe to keep these in the strings.xml file?
Hidden in BuildConfigs
First, create a file apikey.properties in your root directory with the values for different secret keys:
CONSUMER_KEY=XXXXXXXXXXX
CONSUMER_SECRET=XXXXXXX
To avoid these keys showing up in your repository, make sure to exclude the file from being checked in by adding to your .gitignore file:
apikey.properties
Next, add this section to read from this file in your app/build.gradle file. You'll also create compile-time options that will be generated from this file by using the buildConfigField definition:
def apikeyPropertiesFile = rootProject.file("apikey.properties")
def apikeyProperties = new Properties()
apikeyProperties.load(new FileInputStream(apikeyPropertiesFile))
android {
defaultConfig {
// should correspond to key/value pairs inside the file
buildConfigField("String", "CONSUMER_KEY", apikeyProperties['CONSUMER_KEY'])
buildConfigField("String", "CONSUMER_SECRET", apikeyProperties['CONSUMER_SECRET'])
}
}
You can now access these two fields anywhere within your source code with the BuildConfig object provided by Gradle:
// inside of any of your application's code
String consumerKey = BuildConfig.CONSUMER_KEY;
String consumerSecret = BuildConfig.CONSUMER_SECRET;
It seems you should be using a different OAuth Flow. As you experinced, Native Apps can't keep secrets. You can read about recommendations for OAuth and native apps here. https://www.rfc-editor.org/rfc/rfc8252
Your probably want to look at Authorization Code Flow with PKCE. Here you accept the fact that a native apps can't keep a secret. You can find a relatively simple explanation of the flow here: https://auth0.com/docs/flows/concepts/auth-code-pkce
As an alternative you can look at dyanmic client registration (https://www.rfc-editor.org/rfc/rfc7591) but it might be overkill for your application. Using dynamic client registration you won't have to hard code the client secret
If you are concerned about security then you can save the data in SharedPreference by encrypting and saving encryption keys in Android Keystore.
The Keystore is not used directly for storing application secrets such as password, however, it provides a secure container, which can be used by apps to store their private keys, in a way that’s pretty difficult for malicious (unauthorised) users and apps to retrieve.
Here is nice tutorial for creating keystores.
http://www.androidauthority.com/use-android-keystore-store-passwords-sensitive-information-623779/
No, it's not safe to keep it in strings.xml. Use SharedPreferences instead. For example:
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
and then store your client ID and client secret like this:
sharedPreferences.edit()
.putString("client_id", "your_client_id")
.putString("client_secret", "your_client_secret")
.apply();
To get the client ID and client secret back from SharedPreferences:
String clientId = preferences.getString("client_id", "No ID");
String clientSecret = preferences.getString("client_secret", "No Secret");
Please use SharedPreferences to store secure data, because if any one reverse engineer your application, they will get hard coded strings. SharedPreferences is a secure place where you can store data.

How i can store my password in Titanium?

How i can store my password (string) in titanium application?
Is titanium have analog for android secret key, for example?
(i need it only for android)
Thanks!
iOS (and Mac) has a mechanism for storing passwords and things like that securely called the Keychain. With Titanium, there is a module that supports this API called securely.
Once you have securely installed, it is a simple matter to save the password at this point:
var securely = require('bencoding.securely');
//You can provide optional identifier, if none provided securely uses your bundle id
// This wraps the Keychain functions
var SecureProperties = securely.createProperties({
identifier:"Foo",
accessGroup:"Bar"
});
// Now add it to the properties
SecureProperties.setString('Password', the_password_var);
// Get it back
var MyPassword = SecureProperties.getString("password");
Have you checked the FileSystem of Titanium. You can use Properties to store data
Have you tried using this
Titanium.App.Properties.setString("password","P#ssw0rD");
var MyPassword = Titanium.App.Properties.getString("password");
Please check this also

Categories

Resources