问题
A user run my application in Android Pie, he got the crash.There was fix for Android N (fix from varotariya vajsi):
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", new CryptoProvider());
...
public final class CryptoProvider extends Provider {
/**
* Creates a Provider and puts parameters
*/
public CryptoProvider() {
super("Crypto", 1.0, "HARMONY (SHA1 digest; SecureRandom; SHA1withDSA signature)");
put("SecureRandom.SHA1PRNG",
"org.apache.harmony.security.provider.crypto.SHA1PRNG_SecureRandomImpl");
put("SecureRandom.SHA1PRNG ImplementedIn", "Software");
}
But it gives error for Android Pie:
java.security.NoSuchAlgorithmException: class configured for SecureRandom (provider: Crypto) cannot be found.
回答1:
Here is a solution for compatibility in Android Pie.
This could be considered as last method for compatibility if you need to decrypt something encrypted before.
From the method from Jabari https://stackoverflow.com/a/12039611/5330492 First, get the string from SecretKey on machines below Pie
SecretKey secretKey;
String stringKey;
try {secretKey = KeyGenerator.getInstance("AES").generateKey();}
catch (NoSuchAlgorithmException e) {/* LOG YOUR EXCEPTION */}
if (secretKey != null) {
stringKey = Base64.encodeToString(secretKey.getEncoded(), Base64.DEFAULT);
Log.i(TAG, "stringKey = " + stringKey);
}
With the SecretKey string from above, the final code is
SecretKey secretKey;
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
String stringKey = "string got from machines below Pie";
byte[] encodedKey = Base64.decode(stringKey, Base64.DEFAULT);
secretKey= new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
} else {
/* get the SecretKey as before Pie */
}
/* Continue the decryption process */
回答2:
I am using a code decrypt, how to convert compile with android PIE :
KeyGenerator kgen = KeyGenerator.getInstance("AES");
// SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
SecureRandom sr;
if (Build.VERSION.SDK_INT >= 24) {
sr = SecureRandom.getInstance("SHA1PRNG", new CryptoProvider());
} else {
sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
}
sr.setSeed(seed);
kgen.init(128, sr); // 192 and 256 bits may not be available
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
Thanks HieuHD
回答3:
I also encountered this problem in the actual process.
Google explanation of this issue
If you specify the provider by name or by instance—for example, Cipher.getInstance("AES/CBC/PKCS7PADDING", "BC") or Cipher.getInstance("AES/CBC/PKCS7PADDING", Security.getProvider("BC"))—the behavior you get in Android P will depend on what API level your application targets. For apps targeting an API level before P, the call will return the BC implementation and log a warning in the application log. For apps targeting Android P or later, the call will throw NoSuchAlgorithmException.
To resolve this, you should stop specifying a provider and use the default implementation.
before
public static byte[] getAESKey(){
String seed = UUID.randomUUID().toString();
try{
KeyGenerator kgen = KeyGenerator.getInstance("AES");
String SHA1PRNG = "SHA1PRNG";
SecureRandom sr;
CryptoProvider provider = new CryptoProvider();
sr = SecureRandom.getInstance(SHA1PRNG, provider);
sr.setSeed(seed.getBytes());
int keyLength = 128;
kgen.init(keyLength,sr);
SecretKey sKey = kgen.generateKey();
byte[] aesKey = sKey.getEncoded();
return aesKey;
}catch(Exception e){
e.printStackTrace();
}
return null;
}
after
public static byte[] getAESKey(){
String seed = UUID.randomUUID().toString();
try{
KeyGenerator kGen = KeyGenerator.getInstance("AES");
SecureRandom sr;
sr = new SecureRandom();
sr.setSeed(seed.getBytes());
int keyLength = 128;
kGen.init(keyLength,sr);
SecretKey sKey = kGen.generateKey();
return sKey.getEncoded();
}catch(Exception e){
e.printStackTrace();
}
return null;
}
and it's work for me
来源:https://stackoverflow.com/questions/51799526/fix-for-security-crypto-on-nougat-does-not-work-for-pie