Private key is not getting generated in API-23 (Marshmallow) - android

I have been using the keystore to generate RSA key/pair and the code has been working for API levels 18-22.
Today when I ran it on API-23, I am not able to retrieve the Private key from the keystore.
Below is the code that I have been using:
KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(context)
.setAlias(utility.getConfigValue(configuration, OuterKeys.KEYSTORE_NAME))
.setSubject(
new X500Principal("CN=Sample Name, O=Android Authority"))
.setSerialNumber(BigInteger.ONE).setStartDate(start.getTime())
.setEndDate(end.getTime()).build();
KeyPairGenerator generator = null;
generator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
generator.initialize(spec);
KeyPair keyPair = generator.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
byte[] publicKeyBytes = publicKey.getEncoded();
String pubKeyStr = Base64.encodeToString(publicKeyBytes, Base64.NO_PADDING);
byte[] privKeyBytes = privateKey.getEncoded();
String privKeyStr = Base64.encodeToString(privKeyBytes, Base64.NO_PADDING);
Log.d("^^^^^^^^^1",pubKeyStr);
Log.d("^^^^^^^^^2",privKeyStr);
I debugged this and found that the private key generated is null.
Whereas I can print the public key string as it is being retrieved.
Can anyone help out please.

It looks like you are retrieving the PrivateKey instance from Android Keystore just fine. You should be able to use this PrivateKey instance with Cipher and Signature primitives just fine too.
What's "not working" is that that PrivateKey instance's getEncoded returns null. As James K Polk mentioned, this is working as intended. getEncoded is supposed to return the private key's key material (usually in PKCS#8 DER-encoded format) or null if key material export is not supported. Android Keystore by design does not reveal/export key material of private keys and thus getEncoded returns null. On older Android platform versions it may have been returning an empty byte array instead.

Related

3DES with AndroidKeyStore StrongBoxBacked crashes with Attempt to get length of null array when Cipher.init is called

I trying to insert 3DES key into AndroidKeyStore with setIsStrongBoxBacked(true) and then encrypt and decrypt some text. I understand that normal AndroidKeyStore dont support 3DES, but Hardware security module support Triple DES according this document https://developer.android.com/training/articles/keystore#HardwareSecurityModule
this is my test code:
KeyGenerator kg = KeyGenerator.getInstance("DESede");
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
keyStore.setEntry(
"TestAlias",
new KeyStore.SecretKeyEntry(kg.generateKey()),
new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setIsStrongBoxBacked(true)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
.build());
SecretKey key = (SecretKey) keyStore.getKey("TestAlias", null);
Cipher c = Cipher.getInstance("DESede/CBC/PKCS7Padding");
c.init(Cipher.ENCRYPT_MODE, key);
IvParameterSpec paramSpec = new IvParameterSpec(c.getIV());
byte[] encrypted = c.doFinal("hello, world".getBytes());
c = Cipher.getInstance("DESede/CBC/PKCS7Padding");
c.init(Cipher.DECRYPT_MODE, key, paramSpec);
String decrypted = new String(c.doFinal(encrypted));
But it always crash on line c.init(Cipher.ENCRYPT_MODE, key); with
java.lang.NullPointerException: Attempt to get length of null array
at com.android.org.bouncycastle.crypto.params.KeyParameter.(KeyParameter.java:17)
at com.android.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineInit(BaseBlockCipher.java:787)
at com.android.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineInit(BaseBlockCipher.java:1153)
at javax.crypto.Cipher.tryTransformWithProvider(Cipher.java:2985)
at javax.crypto.Cipher.tryCombinations(Cipher.java:2892)
at javax.crypto.Cipher$SpiAndProviderUpdater.updateAndGetSpiAndProvider(Cipher.java:2797)
at javax.crypto.Cipher.chooseProvider(Cipher.java:774)
at javax.crypto.Cipher.init(Cipher.java:1144)
at javax.crypto.Cipher.init(Cipher.java:1085)
....
I already tested AES instead 3DES and it complet without problems.
Testing on Pixel 6 with strongbox support.
Was create key successful? Also, it seems that the code you’re using does not have BouncyCastle but the logs have bouncycastle. Am I missing something?
It is possible that you’re using previously created key with wrong provider later on.

Generate symmetric key and store in android keystore

I am attempting to do the following,
Generate a secret key for sqlcipher.
Store the secret in android keystore.
Retrieve secret from keystore.
I've found nearly everything I need, but I'm having trouble getting the below pieces of code working together.
Pre: Setup keystore
private void InitialiseKeystore() throws ... {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
boolean containsAlias = keyStore.containsAlias("com.example.myapp");
KeyPairGenerator kpg = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
if (!containsAlias) {
kpg.initialize(new KeyGenParameterSpec.Builder(
alias,
KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
.setDigests(KeyProperties.DIGEST_SHA256,
KeyProperties.DIGEST_SHA512)
.build());
KeyPair kp = kpg.generateKeyPair();
}
Generating symmetric key
I found these good examples but they're creating public/private keys, as the same with many others, so a bit confused there, but I have the following.
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(128); //<------------------------------------- [ERRORS HERE]
SecretKey secretKey = keyGen.generateKey();
Storing in keystore
Reviewing the documentation, it seems I should use KeyStore.SecretKeyEntry to store secrets, so this is what I currently have,
KeyStore.SecretKeyEntry secretKeyEntry = new KeyStore.SecretKeyEntry(secretKey);
keyStore.setKeyEntry("key1", secretKeyEntry.getSecretKey().getEncoded(), null);
Retrieving from keystore
private static byte[] getRawSecret() throws Exception {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
byte[] raw = keyStore.getKey("key1", null).getEncoded();
return raw;
}
Here's where it goes wrong, in another function I'm trying to call getRawSecret().
SQLiteDatabase.openOrCreateDatabase(databaseFile, getRawSecret().toString(), null);
ERROR: Cannot initialize without a android.security.keystore.KeyGenParameterSpec parameter
So question, how do I create a symmetric key and store in keystore? As the error is telling me to use KeyGenParameterSpec but as in the examples linked above, this wants to create public/private keys. What am I doing wrong?
I used this to solve my issue,
Guide: https://medium.com/#josiassena/using-the-android-keystore-system-to-store-sensitive-information-3a56175a454b
Code: https://gist.github.com/JosiasSena/3bf4ca59777f7dedcaf41a495d96d984

How to store a created private key into Security KeyStore Android?

I have followed this below code that I need to generate a keypair stored in KeyStore
// generate a key pair
Context ctx = getContext();
Calendar notBefore = Calendar.getInstance()
Calendar notAfter = Calendar.getInstance();
notAfter.add(1, Calendar.YEAR);
KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(ctx)
.setAlias("key1")
.setSubject(
new X500Principal(String.format("CN=%s, OU=%s", alais,
ctx.getPackageName())))
.setSerialNumber(BigInteger.ONE).setStartDate(notBefore.getTime())
.setEndDate(notAfter.getTime()).build();
KeyPairGenerator kpGenerator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
kpGenerator.initialize(spec);
KeyPair kp = kpGenerator.generateKeyPair();
By this way, my keypair is generated and stored into Keystore but when calling this function: getPrivateKey.encoded() , it will return a null bytes array.
My will is I want generate normally, I can get both PrivateKey and PublicKey Encode (This is my own purpose). Then I want to store them into KeyStore to keep secret.
I have tried this: keyStore.setEntry(alias, privateKey, cert) but I got exception due to wrong params maybe. I don't understand what certificate I should get from?
I really appreciate your comments

encode() with private key in "AndroidKeyStore" return null

With Android 4.3, this code return null.
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
keyStore.setKeyEntry(alias, privateKey, null, certificateChain);
PrivateKeyEntry entry=(PrivateKeyEntry)keyStore.getEntry(alias, new PasswordProtection(password));
assert(entry.getPrivateKey().getEncoded()!=null);
How it's possible to get the encoded version of private key ?
Or, is it possible to transmit the private key handler to another application ?
Thank's
The Android KeyChain API prevents you from being able to get an encoded private key.
See the method at line 158 of OpenSSLRSAPrivateKey.java
#Override
public final BigInteger getPrivateExponent() {
if (key.isEngineBased()) {
throw new UnsupportedOperationException("private exponent cannot be extracted");
}
But the benefit of using the KeyChain API is that it provides system-wide credential storage. Any app should be able to retrieve the key pair and certificate by its alias. Refer to the KeyStore docs.

How to get Projective coordinates using spongy castle in Android

I am able to generate Public key and Private key using spongy castle in Android by using the following code
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("ECDH", "SC");
ECGenParameterSpec ecSpecCurve163k1 = new ECGenParameterSpec("sect163r2"); // Curve: B-163
keyGen.initialize(ecSpecCurve163k1);
aKeyPair = keyGen.generateKeyPair();
String pubStr = Crypto.base64Encode(aKeyPair.getPublic().getEncoded());
String privStr = Crypto.base64Encode(aKeyPair.getPrivate().getEncoded());
I get Affine coordinates by using the following code
PublicKey otherKey // key generated by the code above
ECPublicKey ecPubKey = (ECPublicKey) otherKey;
Log.d("public key Wx", ecPubKey.getW().getAffineX().toString(16));
Log.d("public key Wy", ecPubKey.getW().getAffineY().toString(16));
I am trying to get the projective coordinates for the above coordinates by using spongy castle. Is there any way to get it?

Categories

Resources