encoded text of secretkey from keystore is null in android M - android

I need to implement 256 bit AES encryption, I refer this- http://nelenkov.blogspot.jp/2015/06/keystore-redesign-in-android-m.html
The KeyGenerator looks like this .
KeyGenerator keyGenerator = KeyGenerator
.getInstance(KeyProperties.KEY_ALGORITHM_AES,"AndroidKeyStore");
KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keyName,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setUserAuthenticationValidityDurationSeconds(5 *11160)
.build();
keyGenerator.init(spec);
SecretKey key1 = keyGenerator.generateKey();
When I import encoded value of the key from keystore, it returns null to me.
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
SecretKey key3 = (SecretKey) keyStore.getKey(keyName, null);
Log.d("Test MM",key3.getEncoded()+",");
I found null value of key3.getEncoded() in logcat.Please give me some suggestions.

Symmetric keys generated in the keystore are unexportable in Android M. So it works exactly as it is supposed to. You can still use the key with a Cipher to encrypt/decrypt, but you cannot get the raw key bytes. Generally you should need to either.

Related

Decrypting message with RSA-OAEP and Android Keystore: IllegalBlockSizeException

I have the following code inside a try block that should generate a RSA public/private keypair use the public key to encrypt a message and decrypt again with the private key:
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore");
keyPairGenerator.initialize(new KeyGenParameterSpec.Builder(
"key1",
KeyProperties.PURPOSE_DECRYPT | KeyProperties.PURPOSE_ENCRYPT)
.setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP)
.build());
KeyPair keyPair = keyPairGenerator.generateKeyPair();
byte[] src = "hello world".getBytes();
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
byte[] cipherData = cipher.doFinal(src);
Cipher cipher2 = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
cipher2.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
byte[] msg = cipher2.doFinal(cipherData);
Taken mostly from here and here.
The final line throws an exception of type javax.crypto.IllegalBlockSizeException with no message/further details. The three lines in logcat before the exception are
E keymaster1_device: Finish send cmd failed
E keymaster1_device: ret: 0
E keymaster1_device: resp->status: -1000
in case that matters at all.
Does anyone have an idea what could be going wrong?
Using minSdkVersion 23
Edit:
I just realised, if I use PKCS#1 v1.5 padding it works. That helps me for now, but I'd still like to try get it work with OAEP.
You need to put into the cipher the algorithm parameter spec when you encrypt
if (algorithmParameterSpec != null) {
encrypter.init(Cipher.ENCRYPT_MODE, getKey(), algorithmParameterSpec)
}
algorithmParameterSpec is
OAEPParameterSpec("SHA-256",
"MGF1",
MGF1ParameterSpec.SHA256,
PSource.PSpecified.DEFAULT)

How to add a owner AES key to AndroidKeyStore?

I want to store my AES-256 key to AndroidKeyStore, this AES-256 key is raw key (a random 32 byte). I try some code like this.
public foo () {
SecureRandom sr = new SecureRandom();
byte[] key = new byte[32];
sr.nextBytes(key);
try {
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
SecretKeySpec sks = new SecretKeySpec(key, "AES");
SecretKeyFactory skf = SecretKeyFactory.getInstance("AES");
SecretKey sk = skf.generateSecret(sks);
ks.setEntry("key", new KeyStore.SecretKeyEntry(sk), new
KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT).build());
KeyStore.SecretKeyEntry entry = (KeyStore.SecretKeyEntry) ks.getEntry("key", null);
SecretKey skLoad = (SecretKey) ks.getKey("key", null);
Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, skLoad);
Log.i(TAG, Arrays.toString(cipher.doFinal(plainBytes)));
} catch (Exception e) {
e.printStackTrace();
}
}
I get the exception at line SecretKey sk = skf.generateSecret(sks);
java.security.spec.InvalidKeySpecException: To generate secret key in Android Keystore, use KeyGenerator initialized with android.security.keystore.KeyGenParameterSpec
I know we can save key with using KeyGenerator with KeyGenParameterSpec, but I have some reason to use owner key and KeyGenParameter seem can't import my owner key. So have any idea for this problem, thank all!
Generally you should not import keys from outside the key store, as they are insecure before they enter. So adding them later has limited benefits.
However, you can do a little trick: create a wrapping key in the key store and use it to wrap your symmetric key, and store the result. Then you can simply reverse the process when the key is needed again.
Unfortunately the best methods for storing keys such as (GCM-)SIV mode is generally not implemented, but hey, now you've at least heard about it.

Android log encryption using AES and RSA

I want to mail encrypted log file from my app. Since logs can be larger I have encrypted data using AES and encrypted the key using RSA. Since the AES key is required to decrypt the log, I am sending the encrypted key and logs in the same file.
Question 1: Is this right approach ? If not what is the best approach to follow in this scenario.Below is the code for the same.
public static String encrypt(String data) {
StringBuilder encryptedData = new StringBuilder();
try {
// Generate AES key.
KeyGenerator generator = KeyGenerator.getInstance("AES");
// The AES key size in number of bits.
generator.init(256);
SecretKey secKey = generator.generateKey();
// Initialize AES Cipher, IV and encrypt string.
Cipher aesCipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
aesCipher.init(Cipher.ENCRYPT_MODE, secKey, new IvParameterSpec(new byte[16]));
byte[] byteCipherText = aesCipher.doFinal(data.getBytes());
String encryptedText = Base64.encodeToString(byteCipherText, Base64.DEFAULT);
// Initialize RSA Cipher and generate public key.
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
X509EncodedKeySpec publicSpec = new X509EncodedKeySpec(Base64.decode(PUBLIC_KEY, Base64.DEFAULT));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey puKey = keyFactory.generatePublic(publicSpec);
cipher.init(Cipher.PUBLIC_KEY, puKey);
// Encrypt key and text.
byte[] encryptedKey = cipher.doFinal(secKey.getEncoded());
String aesKey = Base64.encodeToString(encryptedKey, Base64.DEFAULT);
encryptedData.append(aesKey);
encryptedData.append(encryptedText);
} catch (Exception e) {
e.printStackTrace();
}
return encryptedData.toString();
}
Since the AES key is required to decrypt the log, I am sending the encrypted key and logs in the same file.
Question 1: Is this right approach ? If not what is the best approach to follow in this scenario.Below is the code for the same.
The approach is correct, what I'm missing is authentication (HMAC, GCM, ...).
There are some standards how to bundle the encrypted key, content and authentication together (e.g. CMS, PKCS7, OpenPGP, ..) however if it's for your own application, you may do it your way (don't bother with standards).
If you want to use RSA use RSA-KEM
Well, using RSA KEM you may save a little of performance skipping the padding, but I'd try if it is feasible for you. As well there's an issue when encrypting the same key material with different public keys.
I'd keep it simple - just use the properly padded RSA encryption.
I'd suggest to use OAEP padding RSA/ECB/OAEPWithSHA-256AndMGF1Padding instead of PKCS1Padding (OAEP is considered newer/safer)

Android Q bouncy castle issue

From API level 28, Google has restricted Security provider feature(bouncy castle issue).
So alternatively we have added Security provider using spongy castle
Now we can able to generate a keypair. But the key pair is not matching with the previous one. We can't get Private keyThis is we used previously, Old codeapi 27:
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC", "BC");
SecureRandom random =SecureRandom.getInstance("SHA1PRNG");
keyGen.initialize(256, random);KeyFactory kaif = KeyFactory.getInstance("EC", "BC");
KeyPair pair = keyGen.generateKeyPair();
PrivateKey privateKey = pair.getPrivate();
PublicKey publicKey = pair.getPublic();
After the API level issue, we have removed "BC" and added Bouncy Castle manually by adding the below lineSecurity.insertProviderAt(BouncyCastleProvider(), 1);
by implementing Bouncy castle in dependencies,
implementation "com.madgag.spongycastle:core:1.58.0.0"
implementation "com.madgag.spongycastle:prov:1.58.0.0"
But the key pair is not matching with the previous one.
New Code:api 28
Security.insertProviderAt(new org.spongycastle.jce.provider.BouncyCastleProvider(), 1);
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
keyGen.initialize(256, random);
KeyFactory kaif = KeyFactory.getInstance("EC");
KeyPair pair = keyGen.generateKeyPair();
PrivateKey privateKey = pair.getPrivate();
PublicKey publicKey = pair.getPublic();
But the key pair is not matching with the previous one.
Image:
try insert new BouncyCastleProvider() on the first row of your security provider and remove all setprovider("BC") from your code.

Android KeyStore: Unsupported secret key algorithm: AES/CBC/PKCS5Padding

I am trying to store an AES key in the Android KeyStore using following code:
SecretKey AESkey = new SecretKeySpec(
byteKey, 0, byteKey.length, "AES/CBC/PKCS5Padding");
if (ks == null)
{
ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
}
ks.deleteEntry("aes_key");
ks.setEntry("aes_key",
new KeyStore.SecretKeyEntry(AESkey),
new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT |
KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
.build());
The line with 'setEntry(...)' fails throwig:
java.security.KeyStoreException: java.lang.IllegalArgumentException: Unsupported secret key algorithm: AES/CBC/PKCS5Padding
How can I store my key in the Android.KeyStore?
CBC and PKCS5Padding are not part of a key but key size is.
Somewhat guessing given the error message just use "AES".
SecretKey AESkey = new SecretKeySpec(byteKey, 0, byteKey.length, "AES");
The documentation is thin at best and the closest I can find is SecretKeyFactory Algorithms: "AES" Constructs secret keys for use with the AES algorithm. See: SecretKeyFactory Algorithms.

Categories

Resources