NoClassDefFoundError: android.security.MessageDigest - android

I've got an app where I'm seeing the following stack trace in the play developer console:
java.lang.NoClassDefFoundError: android.security.MessageDigest
at com.google.android.maps.KeyHelper.getSignatureFingerprint(KeyHelper.java:60)
at com.google.android.maps.MapActivity.createMap(MapActivity.java:513)
at com.google.android.maps.MapActivity.onCreate(MapActivity.java:409)
...
the play console lists all these devices as type "OTHER". This is only happening to something like 1% of my users. What could be causing this? What could I do to fix it?
Thanks

android.security.MessageDigest was removed in Honeycomb, though there's no official record of this on android.com AFAIK
Try using java.security.MessageDigest in your import instead. Its been around since API 1 as well, so it will work on older devices, as well as Honeycomb and above. Just change the line:
import android.security.MessageDigest;
To
import java.security.MessageDigest;

The MessageDigest class is a helper class used to encode/decode keys, using common methods such as MD5 or SHA-1.
It seems that the class android.security.MessageDigest was removed from Honeycomb and later releases of Android, and must be replaced by java.security.MessageDigest (see this page)
Try downloading the latest version of the Google Maps API and rebuild your application with targetSDK set to the highest available (it should be 16 / Jelly Bean).
or
I have found simple work around! Just create in src directory package android\security and place MessageDigest.java inside.
package android.security;
import java.security.NoSuchAlgorithmException;
public class MessageDigest
{
private java.security.MessageDigest instance;
public MessageDigest() {}
private MessageDigest(java.security.MessageDigest instance)
{
this.instance = instance;
}
public static MessageDigest getInstance(String algorithm) throws NoSuchAlgorithmException
{
if (algorithm == null) return null;
try
{
if (algorithm.equals("SHA-1"))
return (MessageDigest) Class.forName("android.security.Sha1MessageDigest").newInstance();
else if (algorithm.equals("MD5"))
return (MessageDigest) Class.forName("android.security.Md5MessageDigest").newInstance();
}
catch (Exception e) {}
return new MessageDigest(java.security.MessageDigest.getInstance(algorithm));
}
public void update(byte[] input)
{
instance.update(input);
}
public byte[] digest()
{
return instance.digest();
}
public byte[] digest(byte[] input)
{
return instance.digest(input);
}
}

Related

SecurityException - GoogleCertificatesRslt: not allowed

We have an app with some million users. Over the past week we have gotten around 30 "velocity alerts" from Firebase Crashlytics from older versions of the app with error messages like this:
Fatal Exception: java.lang.SecurityException
GoogleCertificatesRslt: not allowed: pkg=com.example.app, sha1=<sha1 redacted>, atk=false, ver=203914019.true (go/gsrlt)
android.os.Parcel.readException (Parcel.java:1959)
android.os.Parcel.readException (Parcel.java:1905)
com.google.android.gms.common.internal.s.r (s.java:37)
com.google.android.gms.common.internal.W.u (W.java:90)
com.google.android.gms.common.api.internal.At.q (At.java:17)
com.google.android.gms.common.api.internal.rt.run (rt.java:5)
java.util.concurrent.Executors$RunnableAdapter.call (Executors.java:457)
java.util.concurrent.FutureTask.run (FutureTask.java:266)
java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1162)
java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:636)
com.google.android.gms.internal.ef.run (ef.java:6)
java.lang.Thread.run (Thread.java:764)
It isn't impacting that many users, maybe a few hundreds to a thousand. Normally we wouldn't really notice that small a problem, but because it seems to happen over and over again for those users we have gotten all those velocity alerts - making it more apparent.
Why is this happening? The stacktraces varies a bit, but it does look like it's related to Google's GMS.
Is there anything we or our users can do to avoid it?
The issue seem to be spread out among Android versions and device vendors.
This was an issue in Google Play services as confirmed from someone in dev relations. A fix was rolled out for this on 2nd Oct and we should see a decreasing trend for this as more devices auto update to the latest version(20.39.15).
If anyone still having this error using play-services-maps using MapView, not fragment implementation, you could try when initialise to add this code:
MapsInitializer.initialize(context, MapsInitializer.Renderer.LATEST, listener)
Google started to progressively update default render since June 2022 and this maybe could crash using MapsInitializer.Render.LEGACY. In my case, it does.
Annoying, but works. More details here.
Below solution is work for me, Can you try
Added dependancy in 'app/build.gradle' for android
dependencies {
...
implementation 'com.google.android.gms:play-services-maps:18.1.0'
}
If you are trying to run your application for the first time, make sure to turn on android device's Wi-fi.
Try to put this before the creation of the MapView object (before the layout be inflated):
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
MapsInitializer.initialize(this, MapsInitializer.Renderer.LATEST) {
//println(it.name)
}
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
...
}
The issue tracker link:
https://issuetracker.google.com/issues/228091313
And a Flutter issue
https://github.com/flutter/flutter/issues/109115
Make sure your API_KEY is correctly fetching from your project
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="API_KEY" />
For those who's getting this error AND the map doesn't load at all, try with a Google Play device, not a Google API device. Worked for me!
For me i downgrade gradle from:
com.android.tools.build:gradle:7.1.2
to
com.android.tools.build:gradle:4.1.0
I found in com.google.android.gms:play-services-basement#17.1.0
someting like this:
package com.google.android.gms.common;
import javax.annotation.Nullable;
#javax.annotation.CheckReturnValue
class zzl { zzl(boolean paramBoolean, #Nullable String paramString, #Nullable Throwable paramThrowable) { this.zzap = paramBoolean;
this.zzaq = paramString;
this.cause = paramThrowable; }
static zzl zze() { return zzao; }
static zzl zza(java.util.concurrent.Callable<String> paramCallable) { return new zzn(paramCallable, null); }
static zzl zzb(#androidx.annotation.NonNull String paramString) { return new zzl(false, paramString, null); }
static zzl zza(#androidx.annotation.NonNull String paramString, #androidx.annotation.NonNull Throwable paramThrowable) { return new zzl(false, paramString, paramThrowable); } #Nullable
String getErrorMessage() { return this.zzaq; }
final void zzf() { if ((!this.zzap) && (android.util.Log.isLoggable("GoogleCertificatesRslt", 3))) {
if (this.cause != null) {
android.util.Log.d("GoogleCertificatesRslt", getErrorMessage(), this.cause);return; }
android.util.Log.d("GoogleCertificatesRslt", getErrorMessage()); } }
static String zzc(String paramString, zzd paramzzd, boolean paramBoolean1, boolean paramBoolean2) { String str = paramBoolean2 ? "debug cert rejected" : "not whitelisted";
zzd localzzd = paramzzd;{ str, paramString }[2] =
com.google.android.gms.common.util.Hex.bytesToStringLowercase(com.google.android.gms.common.util.AndroidUtilsLight.zzj("SHA-1").digest(localzzd.getBytes())); Object[]
tmp50_28 = tmp28_24;tmp50_28[3] =
Boolean.valueOf(paramBoolean1); Object[] tmp57_50 = tmp50_28;tmp57_50[4] = "12451009.false";
return String.format("%s: pkg=%s, sha1=%s, atk=%s, ver=%s", tmp57_50); }
private static final zzl zzao = new zzl(true, null, null);
final boolean zzap;
private final String zzaq;
private final Throwable cause;
}
Similar error message.

Realm Encryption with Android

Realm is using AES-256 for encryption and decryption. And, I am trying to use Android KeyStore to generate/store the keys, but as per this page - https://developer.android.com/training/articles/keystore.html#SecurityFeatures, Android supports this only on APIs 23 and above.
Can someone please point me to an example or any other related info on how I can use realm with encryption to support APIs 4.0 and above?
Thanks.
We recently ran into the same problem and decided to simply store the key in private Shared Preferences, because if the phone is not rooted, you will not be able to get it and if it is rooted, then there are some ways to get data even from secure keyStore.
We use next Realm configuration inside Application subclass:
RealmConfiguration config = new RealmConfiguration.Builder()
.deleteRealmIfMigrationNeeded()
.name(DB_NAME)
.encryptionKey(mKeyProvider.getRealmKey())
.build();
And mKeyProvider is our helper class that is used to get the key:
public class SharedPrefsKeyProvider implements KeyProvider {
private static final String REALM_KEY = "chats.realm_key";
SharedPreferences mAppSharedPrefs;
public SharedPrefsKeyProvider(SharedPreferences aAppSharedPrefs) {
mAppSharedPrefs = aAppSharedPrefs;
}
#Override
public byte[] getRealmKey() {
byte[] key;
String savedKey = getStringFromPrefs(REALM_KEY);
if (savedKey.isEmpty()) {
key = generateKey();
String keyString = encodeToString(key);
saveStringToPrefs(keyString);
} else {
key = decodeFromString(savedKey);
}
return key;
}
#Override
public void removeRealmKey() {
mAppSharedPrefs.edit().remove(REALM_KEY).apply();
}
#NonNull
private String getStringFromPrefs(String aKey) {
return mAppSharedPrefs.getString(aKey, "");
}
private void saveStringToPrefs(String aKeyString) {
mAppSharedPrefs.edit().putString(REALM_KEY, aKeyString).apply();
}
private String encodeToString(byte[] aKey) {
Timber.d("Encoding Key: %s", Arrays.toString(aKey));
return Base64.encodeToString(aKey, Base64.DEFAULT);
}
private byte[] decodeFromString(String aSavedKey) {
byte[] decoded = Base64.decode(aSavedKey, Base64.DEFAULT);
Timber.d("Decoded Key: %s", Arrays.toString(decoded));
return decoded;
}
private byte[] generateKey() {
byte[] key = new byte[64];
new SecureRandom().nextBytes(key);
return key;
}
}
A KeyProvider is just a custom interface. An example of KeyProvider can be:
package xxx.com;
interface KeyProvider {
byte[] getRealmKey();
void removeRealmKey();
}
AES 256 encryption is symmetric Encryption, try RSA encryption which is asymmetric. And if you are trying to encrypt sensitive user data to store in preferences or sqlite, i would suggest you try Android keystore system.
The Android Keystore system lets you store cryptographic keys in a container to make it more difficult to extract from the device. Once keys are in the keystore, they can be used for cryptographic operations with the key material remaining non-exportable.
check my sample gist to achieve this encryption and decryption here.
And better part is it works on android 18 and above.

Android N Developer Preview: Camera support takes a third value

I have a Nexus 6P. I'm investigating why OpenCamera has stopped working on Android N Developer Preview (I'm not a developer, just a user). I have found the following piece of code that might be causing the problem: CameraControllerManager2.java:62
I created a new Android project, and added the following function:
...
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
...
public class MainActivity extends AppCompatActivity {
private String TAG = "MainActivity";
...
public void test(int cameraId) {
CameraManager manager = (CameraManager)this.getSystemService(Context.CAMERA_SERVICE);
try {
String cameraIdS = manager.getCameraIdList()[cameraId];
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraIdS);
int support = characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
Log.d(TAG, "Camera support: " + support);
}
catch (CameraAccessException e) {
e.printStackTrace();
}
}
...
}
Calling test(0), the console output on my device is:
04-22 15:16:54.263 11578-11578/test.myapplication D/MainActivity: Camera support: 3
When I look up the possible values of support (docs), they must be 0, 1 or 2, but how is support taking the value of 3? Is it supposed to be a bitmask or something worse is happening?
You are looking at the docs for the shipping version of Android. At the present time, Android N is in a developer preview, and the docs are elsewhere.
There is a new INFO_SUPPORTED_HARDWARE_LEVEL_3 value for that characteristic, described as:
...devices additionally support YUV reprocessing and RAW image capture, along with additional output stream configurations.

How to encrypt password using md5 with key in android

I am currently using the following code to encrypt password but it is without using key.
package com.MD5Check;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import android.app.Activity;
import android.os.Bundle;
public class MD5Check extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
getSignature();
}
public void getSignature()
{
try {
String s = "aditi9970";
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(s.getBytes(),0,s.length());
String signature = new BigInteger(1,md5.digest()).toString(16);
System.out.println("Signature: "+signature);
} catch (final NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
}
I would like to hash the password using md5 with key in android.
Can anybody suggest the right way to do this?
MD5 is a hashing algorithm - meaning that the function will only transform data one way (from the original into an md5 hash). I am a little unclear what you mean by 'key' in these circumstances. If you are looking to salt the string before hashing it then you can simply concatenate your original string and your salt.
Alternatively you may wish to look at alternative android encryption techniques. I would start here http://developer.android.com/reference/javax/crypto/package-summary.html

Using java.util.regex in Android apps - are there issues with this?

In an Android app I have a utility class that I use to parse strings for 2 regEx's. I compile the 2 patterns in a static initializer so they only get compiled once, then activities can use the parsing methods statically.
This works fine except that the first time the class is accessed and loaded, and the static initializer compiles the pattern, the UI hangs for close to a MINUTE while it compiles the pattern! After the first time, it flies on all subsequent calls to parseString().
My regEx that I am using is rather large - 847 characters, but in a normal java webapp this is lightning fast. I am testing this so far only in the emulator with a 1.5 AVD.
Could this just be an emulator issue or is there some other reason that this pattern is taking so long to compile?
private static final String exp1 = "(insertratherlong---847character--regexhere)";
private static Pattern regex1 = null;
private static final String newLineAndTagsExp = "[<>\\s]";
private static Pattern regexNewLineAndTags = null;
static {
regex1 = Pattern.compile(exp1, Pattern.CASE_INSENSITIVE);
regexNewLineAndTags = Pattern.compile(newLineAndTagsExp);
}
public static String parseString(CharSequence inputStr) {
String replacementStr = "replaceMentText";
String resultString = "none";
try {
Matcher regexMatcher = regex1.matcher(inputStr);
try {
resultString = regexMatcher.replaceAll(replacementStr);
} catch (IllegalArgumentException ex) {
} catch (IndexOutOfBoundsException ex) {
}
} catch (PatternSyntaxException ex) {
}
return resultString;
}
please file a reproduceable test case at http://code.google.com/p/android/issues/entry and i'll have a look. note that i will need a regular expression that reproduces the problem. (our regular expressions are implemented by ICU4C, so the compilation actually happens in native code and this may end up being an ICU bug, but if you file an Android bug i'll worry about upstream.)
If you launched with debugging you can expect it to be about twice as slow as a regular launch. However a minute does seem extraordinary. Some things to suggest, i. look at the console output to see if warnings are being spat out, ii. when it is doing the compile, in the debugger press 'pause' and just see what it is doing. There are ways to get the source, but even so just looking at the call stack may reveal something.

Categories

Resources