tozny/java-aes-crypto

java.security.NoSuchAlgorithmException: SecretKeyFactory PBKDF2WithHmacSHA1 implementation not found

orhanobut opened this issue · 8 comments

java.lang.RuntimeException: java.security.NoSuchAlgorithmException: SecretKeyFactory PBKDF2WithHmacSHA1 implementation not found

Some phones especially samsung ones, do not support this algorithm. Any work around for this issue?

samsung GT-S5282 - 4.1.2
samsung GT-I8190 - 4.1.2
samsung GT-S5300 - 2.3.6

Your best bets is to try to bundle the BouncyCastle provider directly with your app to add support.

If there is absolutely no way to do this, then you can try changing the PBE_ALGORITHM to PBEWithMD5AndTripleDES, which should work, but is far less secure.

You might also have some trouble with the HMAC algorithm. You might have change it from HmacSHA256 to HmacSHA1, for example. (This is slightly less secure.)

I agree with @swenson I had this issue with one of my libs before recently switching to use java-aes-crypto for that used a backup PBE_ALGORITHM of PBEWithMD5AndDES

Thanks, I'll try this week to make a fallback for unsupported algorithms. @scottyab did you get any problem afterwards? Currently this unsupported issue creates kind of inconsistency.

It seemed to work fine, it was a over a year ago and can't remember the devices we tested on, from memory it was some cheap chinese devices. In the back of my mind I was concerned that if an OS upgrade added support for PBKDF2WithHmacSHA1 then an existing app with any previously encrypted data wouldn't be able to be decrypted. I guess you could set a flag in shared prefs to say using fall back PBE_ALGORITHM. In our use case at the time we just discarded the data in this edge case, but of course depends on the data.

I finally had time and tried fallback approach, but apparently this algorithm(PBEWithMD5AndTripleDES) has the same problem as well, it couldn't be found. I tried PBEWithMD5AndDES, it is ok but i face another issue which is

byte[] keyBytes = keyFactory.generateSecret(keySpec).getEncoded();
byte[] confidentialityKeyBytes = copyOfRange(keyBytes, 0, AES_KEY_LENGTH_BITS / 8);

AES_KEY_LENGTH_BITS = 128;

keyBytes has 8 bytes, which the next line crashes, because it requires at least 16 bytes.

I wonder what would happen if I just fallback to generateKey instead of generateKeyFromPassword or I might need to change more lines in order to fix this issue.

Maybe a better option would be to have a fallback class or version of this code that uses PBEWithMD5AndDES? I'm kinda :( on regular DES and MD5 though, but it's better than nothing.

I use a fallback to

AesCbcWithIntegrity.generateKey()
when there is no such PBE algorithm in the device. That would be great to have fallback version though.

@orhanobut @scottyab I am handling this like -

try {

                    AesCbcWithIntegrity.SecretKeys myKey = AesCbcWithIntegrity.generateKeyFromPassword(Build.SERIAL, AesCbcWithIntegrity.generateSalt(), 1000);
                /*SecurePreferences.Editor editor = sharedPreferences.edit();
                editor.putString("realmkey", myKey.toString().substring(0, 64));
                editor.commit();*/
                    settings.edit().putString("rm", myKey.toString().substring(0, 64)).apply();

                } catch (NoSuchAlgorithmException e) {

                    AesCbcWithIntegrity.SecretKeys myKey = AesCbcWithIntegrity.generateKey();
                    if (myKey.toString().length() > 64) {
                        settings.edit().putString("rm", myKey.toString().substring(0, 64)).apply();
                    }
                }

is this the right way of handling?