My application uses an RSA public key to encrypt the data before passed to the server. Everything works fine if I embed the public key to my solution and just use it.
However my client wants to change this public key sometimes, so I'm unable to add the PublicKey.key file to the solution as embedded resource.
My first tought was that I should install this public key to the Keystore like I install an X509Cetificate under the settings -> security -> Install user certificate method on the phone.
This method fails, because my file only contains the public key, which is not a certificate.
How can I store this public key in the Keystore? My goal is to install it, after that in would like to read it with my Xamarin Forms app in order to encrypt the data before I post to the server.
So my goal is not the set this public key to the keystore with code, it has to be there.
You could try to save public key as string into Secure Storage.
To save a value for a given key in secure storage:
try
{
await SecureStorage.SetAsync("oauth_token", "secret-oauth-token-value");
}
catch (Exception ex)
{
// Possible that device doesn't support secure storage on device.
}
To retrieve a value from secure storage:
try
{
var oauthToken = await SecureStorage.GetAsync("oauth_token");
}
catch (Exception ex)
{
// Possible that device doesn't support secure storage on device.
}
For more details, refer to Xamarin.Essentials: Secure Storage:
https://learn.microsoft.com/en-us/xamarin/essentials/secure-storage?context=xamarin%2Fandroid&tabs=ios
Related
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!".
I want to encrypt and decrypt with symmetrically with android Keystore KMS. I'm aware with Google cloud KMS, and AWS KMS, but I don't want to handle with that platform.
How to manage this generated Android Keystore private key for both (client, server) sides?
I have created a private key for encrypting and decrypting, but hard to manage for the store and share this key.
I had stored that private key in Private SharedPreferences for reuse but There is one problem is that, this private SharedPreferences is not secured because all can observe this private SharedPreferences file in the rooted device.
Refer this link to get information about generating a private key for Android Keystore.
I'm new with tink, so please help me to out this. if there is a wrong thing in my idea then feel free to give your opinion.
Android Keystore is a client side KMS, you cannot use it on server side.
If you want to use Tink with Android Keystore on Android, please take a look at AndroidKeysetManager. Here's an example:
String masterKeyUri = "android-keystore://my_master_key_id";
AndroidKeysetManager manager = AndroidKeysetManager.Builder()
.withSharedPref(getApplicationContext(), "my_keyset_name", "my_pref_file_name")
.withKeyTemplate(SignatureKeyTemplates.ECDSA_P256)
.withMasterKeyUri(masterKeyUri)
.build();
PublicKeySign signer = PublicKeySignFactory.getPrimitive(manager.getKeysetHandle());
This will read a keyset stored in the my_keyset_name preference of the my_pref_file_name preferences file. If the preference file name is null, it uses the default preferences file.
If the keyset is not found or invalid, and a valid KeyTemplate is set with AndroidKeysetManager.Builder.withKeyTemplate(com.google.crypto.tink.proto.KeyTemplate), a fresh keyset is generated and is written to the my_keyset_name preference of the my_pref_file_name shared preferences file.
On Android M or newer and if a master key URI is set with AndroidKeysetManager.Builder.withMasterKeyUri(java.lang.String), the keyset is encrypted with a master key generated and stored in Android Keystore. When Tink cannot decrypt the keyset it would assume that it is not encrypted.
The master key URI must start with android-keystore://. If the master key doesn't exist, a fresh one is generated. Usage of Android Keystore can be disabled with AndroidKeysetManager.Builder.doNotUseKeystore().
On Android L or older, or when the master key URI is not set, the keyset will be stored in cleartext in private preferences which, thanks to the security of the Android framework, no other apps can read or write.
I have an app that generates a key for encryption/decryption and it is working just fine. I store my key in KeyStore and IV as first 12B in encrypted file saved on external storage. When I want to decrypt the file, I get the file from external storage (hence I get IV) and key from KeyStore, and I am able to get original content. My second application App2 can access file in external storage (hence it can get IV), but it can't get key from App1 KeyStore. I was reading about KeyChain and it says in official documentation it is not app private (Use the KeyChain API when you want system-wide credentials). Can I somehow store my key in this KeyChain or somewhere else so my App2 can get it (with some user approval or something similar). Here is the code I used to create and store key in App1.
private static SecretKey createAndStoreKey() {
KeyGenerator keyGen;
try {
// Generate 256-bit key
keyGen = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, KEY_STORE_NAME);
final KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(KEY_ALIAS,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build();
keyGen.init(keyGenParameterSpec);
SecretKey secretKey = keyGen.generateKey();
if(secretKey != null)
return secretKey;
else
return null;
}
catch (NoSuchProviderException e){
e.printStackTrace();
return null;
}
catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
catch (InvalidAlgorithmParameterException e){
e.printStackTrace();
return null;
}
}
Thank you all for the help.
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.
Use the Android Keystore provider to let an individual app store its
own credentials that only the app itself can access. This provides a
way for apps to manage credentials that are usable only by itself
while providing the same security benefits that the KeyChain API
provides for system-wide credentials. This method requires no user
interaction to select the credentials.
refrence
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.
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();
}