I have Android application which using WebRTC. All works perfect. But now, main problem, with encryption.
For making call and transfer data, WebRTC creates and uses a single KeyPair for every call. But I want to use custom KeyPair from AndroidKeyStore. For this problem I need to send own KeyPair to OpenSSL shared object to work.
The fix will be in NATIVE OpenSSL code, where WebRTC is getting OpenSSL context for encryption data using this function (opensslidnetity.cc):
bool OpenSSLIdentity::ConfigureIdentity
{
...
}
How transfer PK from AndroidKeyStore to WebRTC native code? Another case, how set custom PK for WebRTC encryption work?
AndroidKeyStore
In Java I can open the KeyStore (AndroidKeyStore) and get the public key - which ready to transfer (has bytes of key with method - getEncoded()). Also I can get private Key for encryption data, but I can't send this key in bytes, because getEncoded() return null. In this case, I thought, I can get PublicKey and PrivateKey and save them in bytes array. And after, call prepared methods in native code.
UPDATE: There is something similar located in google.source.chromium. Where they get key from Android KeyStore and creating OpenSSL context in native code. Native class for getting and using AndroidKeyStore for TLS - Link 1 and Link 2.
Android Keystore does not expose the key material of private or secret keys, by design (see https://developer.android.com/training/articles/keystore.html). You options are:
Present Android Keystore PrivateKey + Signature or Cipher as OpenSSL EVP_PKEY.
Don't use Android Keystore. Perhaps you don't need the additional protections it offered compared to storing private keys inside your process?
Related
As i am new to Android, i am working on hiding my API keys and found Android keystore the way to go. But when i see examples of how to use Android Keystore, one thing i am not understanding is how to supply the unencrypted original key for encryption? if i am storing in the code, wouldn't that beat the purpose of using Android Keystore?
from an article on storing secrets:
https://medium.com/#ericfu/securely-storing-secrets-in-an-android-application-501f030ae5a3
Generate a random key when the app runs the first time;
When you want to store a secret, retrieve the key from KeyStore, encrypt the data with it, and then store the encrypted data in
Preferences.
When you want to read a secret, read the encrypted data from Preferences, get the key from KeyStore and then use the key to decrypt
the data
In second point, it says encrypt the data with it. How to supply the data without exposing to the code/application?
I apologize if this has been answered.
Thanks
private static final String KEYSTORE_PROVIDER = "AndroidKeyStore";
private static final String AES_MODE = "AES/GCM/NoPadding";
private static final String KEY_ALIAS = "MyNiceKey";
Load the default AndroidKeyStore:
KeyStore keyStore = KeyStore.getInstance(KEYSTORE_PROVIDER);
keyStore.load(null);
Generate AES key inside the KeyStore which in the latest verision of android, it is hardware-backed keystore; it means that it is very hard to extract the bytes of the key from it:
if (!keyStore.containsAlias(KEY_ALIAS)) {
KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, KEYSTORE_PROVIDER);
keyGenerator.init(new KeyGenParameterSpec.Builder(KEY_ALIAS,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setRandomizedEncryptionRequired(false)
.build());
keyGenerator.generateKey();
}
Anyway you should use .setRandomizedEncryptionRequired(true). There is no point to set up a faulty protocol. Otherwise, if you have to encrypt only few bytes(your API key) you could create an asymmetric public/private key and encrypt it with RSA so that you don't even need to provide the IV.
Haing said that, when you get the secret key from the KeyStore:
public static SecretKey getKeyStoreSecretKeyEntry(final String entryAlias)
throws GeneralSecurityException, IOException {
return ((KeyStore.SecretKeyEntry) getKeyStore().getEntry(entryAlias, null)).getSecretKey();
}
the returned SecretKey does not containt the Key Material (the real bytes of the key) but only its reference. So you can use it freely iside the Cipher to encrypt and decrypt what you want. In any case, you API key will be exposed enyway if you use it to make http request directly to you service. The best way to go in your case is to use a server like Google Firebase
P.s. there is very a simple library from google that will save you time and headache:
https://developer.android.com/jetpack/androidx/releases/security
https://developer.android.com/topic/security/data
Conclusion: The key you generate within the android Key Store is property of the user and it should be used to protect the user's private data. So it is not a good practice to encrypt an API Key, wich is the developer's private data, with the user key. Use a server to protect the API key.
I'm trying to decode a JWT token from my OAUTH server and I'm using examples from the following website.
I have tried quite a lot self designed solutions but can't solve an issue, I can't decode a RSA public key signed JWT.
The following code
Jwts.parser().setSigningKey("<<Oauth server RSA public key>>").parseClaimsJws(keySec.getTokenString());
I get the following Exception
java.lang.IllegalArgumentException: Key bytes cannot be specified for RSA signatures. Please specify a PublicKey or PrivateKey instance.
This question already has answers here:
Java - Encrypt String with existing public key file
(3 answers)
Closed 5 years ago.
To my knowledge a x509 certificate is used to distribute the public key, which in my case is a RSA key, thus I can encrypt a message with it, but without knowing the private key I couldn't get the message back. I created the keys on my linux virtual machine and copied them over to windows to use in my project and I obtain them this way:
InputStream inputStream = new FileInputStream("./certificates/cert" + LoginController.getLoggedUser().getID() + ".crt");
CertificateFactory cf = CertificateFactory.getInstance("X509");
Certificate c = cf.generateCertificate(inputStream);
myCert = (X509Certificate) c;
Now I use the certificate for two things, first to validate if a user can login into the app, and secondly I have to encrypt/decrypt a message I hide inside a picute using steganography. So I'd like to know which file contains my private key and how to load it into my program possibly using the Java SE API? (P.S. I have the CA body and everything still on my virtual machine).
The private key should be in the keystore generated by keytool (and ideally nowhere else -- private keys are not meant to be distributed, hence the name).
Looks like you can access keystores via an instance of java.security.KeyStore. You'll need the password you used when generating the keystore; it's one of the parameters to the load method.
I've been asked to create a jks keystore based on a certificate we had created. I've read a bit on the topic, but I'm still confused on a few items:
Is the private key of a certificate supposed to be stored in a .jks keystone?
If yes - where does this get entered in? Using the keytool, it doesn't require one for creating a jks file.
If no - what is the purpose of a jks file? Why would my application need it instead of just reading in a certificate directly? And why does the keytool require a password to create a jks if it just contains a public key?
The purpose of a key store is to protect the privacy and integrity of cryptographic keys using password-based algorithms. Privacy means that the keys are kept secret; they can only be used by someone who knows the password; this is useful for private keys and secret keys. Integrity means that alteration of the keys can be detected by someone who knows the password; this is useful for public keys and secret keys.
Whether you should include the private key or not depends on what you are trying to do. If you are creating a key store for your server so that it can authenticate itself to clients, for example, then it should contain the private key. If you created a self-signed certificate, and want to give clients a key store so that they can authenticate your service, then it should not contain the private key.
If you have a pre-existing key pair, and want to import it to a JKS format key store, the easiest way might be to use OpenSSL to create a PKCS #12 format key store, then use keytool to convert that to a JKS key store. Normally, keytool expects to do key pair generation itself, and so the private key will be stored there from the beginning.
You should verify the integrity of a public key or a certificate before you use it to encrypt a message or verify a signature. Otherwise, an attacker can replace the key with one he owns and act as a man in the middle. If you simply read a public key from a file, you don't know it really belongs to your intended recipient. But if you store a password-based message authentication code with the public key, you can ensure that it hasn't been tampered with.
Is the private key of a certificate supposed to be stored in a .jks keystone?
Yes, if you own the certificate and it is stored there.
If yes - where does this get entered in? Using the keytool, it doesn't require one for creating a jks file.
That's because you can also use it as a truststore, which only contains trusted certificates.
To get the private key in there you will need to first convert it and its certificate to a PKCS#12 file using openssl, as answered in numerous questions here such as this.
If no - what is the purpose of a jks file? Why would my application need it instead of just reading in a certificate directly?
Because your application also needs the private key of the certificate.
And why does the keytool require a password to create a jks if it just contains a public key?
A keystore has a password because it is a security-related entity.
I am using a smart card and the keystore instance is in PKCS11 format.
I wanted to create a .jks file with the Certificate from the smart card.
Is there a way to achieve it programmatically? Thanks.
You can, (HOWEVER, IT IS NOT ADVISABLE), provided if the hardware token manufacturer supports it and if you have created your PKCS#11 Objects as extractable.
WARNING: What you are trying to do is NOT secure. You are taking away the purpose of what the hardware tokens are meant to do. Once a secret Object is created in a hardware token, it doesn't see the light of the day.
For a PKCS11 Object to be extractable, you have to set the CKA_EXTRACTABLE to true, CKA_NEVER_EXTRACTABLE to false, CKA_SENSITIVE to false and CKA_ALWAYS_SENSITIVE to false.
Most hardware token manufacturer's don't support this. Assuming that you have found a vendor who supports this, and you have created the PKCS11 Objects with the above attributes, you can do it as below.
You can loop through your PKCS11 KeyStore instance entries by calling aliases() and find each entry in it. It can either be a KeyPair (PublicKey and PrivateKey) or a Certificate or a Data Object (if it is PIV SmartCard token). You can have another instance of JKS KeyStore and you can now do jksKS.setEntry(...) or jksKS.setCertificateEntry(...).
If the token doesn't support creation of non-sensitive data, you won't be able to create the PKCS11 Object with the above attributes in the first place.
If the token doesn't support extraction, the PKCS11 token would throw exception saying that sensitive data cannot be extracted.