decodeHex method not found on Device, but working on Emulator - android

I'm working on the project with RSA encryption, and need to use the method from Apache commons-codec, which is:
Hex.encodeHex(byte[])
Hex.decodeHex(String)
Both methods are working fine on Android emulator, but it will return NoSuchMethodError on Device
public String RSADecrypt(final String message) {
try {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, getPrivateKey());
byte[] decryptedBytes = cipher.doFinal(Hex.decodeHex(message));
return new String(decryptedBytes);
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (DecoderException e) {
e.printStackTrace();
}
return "";
}
java.lang.NoSuchMethodError: No static method decodeHex(Ljava/lang/String;)[B in class Lorg/apache/commons/codec/binary/Hex; or its super classes (declaration of 'org.apache.commons.codec.binary.Hex' appears in /system/framework/org.apache.http.legacy.boot.jar)
My emulator run on Pie, Oreo, & Nougat
My device run on Nougat & Marshmallow

Some Android versions contain an older version of the Apache commons-codec library (1.3) where the decodeHex(String) method didn't yet exist. Try calling decodeHex(char[]) instead. I.e. modify your code like this:
byte[] decryptedBytes = cipher.doFinal(Hex.decodeHex(message.toCharArray()));
That should work with commons-codec v1.3.

Related

Android fingerprint on SDK<23

I have a project on Android with minSDK=17 and targetSDK=23. We have a fingerprint authentication in this project made using FingerprintManager class (it was added in SDK23). We added SDK version check, so we are not using anything related to fingerprint if SDK<23. But in older SDK versions app behaviour is unpredictable: on some versions app just crashing, on other -- fingerprint not working (so, it's ok).
My question:
1) Is it any good and easy-to-implement libraries for minSDK=17, that can recognize fingerprints?
2) How can I avoid app crashing in devices with SDK<23?
Crash error:
E/dalvikvm: Could not find class 'android.hardware.fingerprint.FingerprintManager', referenced from method nl.intratuin.LoginActivity.loginByFingerprint
E/AndroidRuntime: FATAL EXCEPTION: main java.lang.VerifyError:
LoginActivity at java.lang.Class.newInstanceImpl(Native Method)
Some new info: created HelloWorld fingerprint project using this tutorial:
http://www.techotopia.com/index.php/An_Android_Fingerprint_Authentication_Tutorial
Found the root of the problem:
FingerprintDemoActivity->cipherInit:
try {
keyStore.load(null);
SecretKey key = (SecretKey) keyStore.getKey(KEY_NAME,
null);
cipher.init(Cipher.ENCRYPT_MODE, key);
return true;
} catch (KeyPermanentlyInvalidatedException e) {
return false;
} catch (KeyStoreException | CertificateException
| UnrecoverableKeyException | IOException
| NoSuchAlgorithmException | InvalidKeyException e) {
throw new RuntimeException("Failed to init Cipher", e);
}
First catch block breacking whole app with error I mentioned above. Of course, I can just remove this catch (this exception extends InvalidKeyException, so it will be handled), and return false in case of any exceptions. Is it any better way?
I think, I found acceptable solution: catch not KeyPermanentlyInvalidatedException, but InvalidKeyException. Everything working fine this way. Still have no idea how this exception crashed whole app...
It happened to me also..even when i used : if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M).. my app crashes on android 4.4- kitkat. so eventually the problem was in the initCipher method in the catches part - see the following code (even though i m not suppose to get there as it targeted to M and above... very strange behaviour..) :
#TargetApi(Build.VERSION_CODES.M)
private boolean initCipher() {
try {
mKeyStore.load(null);
SecretKey key = (SecretKey) mKeyStore.getKey(KEY_NAME, null);
mCipher.init(Cipher.ENCRYPT_MODE, key);
return true;
} catch (KeyStoreException | CertificateException | UnrecoverableKeyException | IOException
| NoSuchAlgorithmException e) {
throw new RuntimeException("Failed to init Cipher", e);
} catch (InvalidKeyException e) {
e.printStackTrace();
return false;
}
}
apparently the order off the catches matter..so just make sure to write it as i mentioned.
Reason for Crash:
The FingerprintManager class works with Android version 23 and Higher.
If your app is using FingerprintManager class and runs on older version of Android then you will encounter this exception.
Supporting older versions of Android:
Use FingerprintManagerCompat instead of FingerprintManager if you are planning to support Android <23. The FingerprintManagerCompat class internally checks for the Android version and handle Authentication part with ease.
How to Use it:
Replace android.hardware.fingerprint.FingerprintManager With android.support.v4.hardware.fingerprint.FingerprintManagerCompat
Replace android.os.CancellationSignal With android.support.v4.os.CancellationSignal
See Sample Code
https://github.com/hiteshsahu/FingerPrint-Authentication-With-React-Native-Android/blob/master/android/app/src/main/java/com/aproject/view/Fragments/FingerprintAuthenticationDialogFragment.java
Have a look at a library created by afollestad called digitus.
This library can fall back to a password if fingerprints are not available.
Any devices prior to SDK 23 need to use their own separate device manufacturer based sdk.
just follow android studio hint, it will be OK.
try {
mKeyStore.load(null);
SecretKey key = (SecretKey) mKeyStore.getKey(keyName, null);
cipher.init(Cipher.ENCRYPT_MODE, key);
return true;
} catch (IOException | NoSuchAlgorithmException | CertificateException
| UnrecoverableKeyException | KeyStoreException | InvalidKeyException e) {
e.printStackTrace();
throw new RuntimeException("Failed to init Cipher", e);
}
To answer the second part of the question
How can I avoid app crashing in devices with SDK<23?
This simplistic logic check will suffice:
if (Build.VERSION.SDK_INT < 23) {
// Handle the mechanism where the SDK is older.
}else{
// Handle the mechanism where the SDK is 23 or later.
}
I solved this by moving all the fingerprint code to a helper class so that the classes related to the fingerprint code are not imported in the activity and by instantiating the helper class only when the SDK_INT is greater than 23 (In my case, as I'm supporting only Android 6+)
I also had this problem.Even when i used : if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M).. my app crashes on lower API's. I solved that as follow:
Replaced these codes:
try {
keyStore.load(null);
SecretKey key = (SecretKey) keyStore.getKey(KEY_NAME,
null);
cipher.init(Cipher.ENCRYPT_MODE, key);
return true;
} catch (KeyPermanentlyInvalidatedException e) {
return false;
} catch (KeyStoreException | CertificateException
| UnrecoverableKeyException | IOException
| NoSuchAlgorithmException | InvalidKeyException e) {
throw new RuntimeException("Failed to init Cipher", e);
}
with:
try {
keyStore.load(null);
} catch (CertificateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
SecretKey key = null;
try {
key = (SecretKey) keyStore.getKey(KEY_NAME,
null);
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
}
try {
cipher.init(Cipher.ENCRYPT_MODE, key);
} catch (InvalidKeyException e) {
e.printStackTrace();
}
return true;

SMACK 4.1 Account manager: Private Access Error in account registration

I am getting a strange error while working with account manager in Smack 4.1 for android.
Below is the code snippet:
am = new AccountManager(connection);
Map<String, String> mp = new HashMap<String, String>();
// adding or set elements in Map by put method key and value
// pair
mp.put("username", "user3");
mp.put("password", "ps3");
mp.put("name", "user3");
mp.put("email", "user3#user.com");
try {
am.createAccount("user3", "user3", mp);
} catch (SmackException.NoResponseException e) {
e.printStackTrace();
} catch (XMPPException.XMPPErrorException e) {
e.printStackTrace();
} catch (SmackException.NotConnectedException e) {
e.printStackTrace();
}
The code I've used to connect to Openfire Server is:
XMPPTCPConnectionConfiguration.Builder configBuilder = XMPPTCPConnectionConfiguration.builder();
configBuilder.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);
configBuilder.setServiceName("host_name");
configBuilder.setHost("host_name");
configBuilder.setPort(5222);
configBuilder.setCompressionEnabled(false).build();
AbstractXMPPConnection connection = new XMPPTCPConnection(configBuilder.build());
try {
System.out.println("connecting");
connection.setPacketReplyTimeout(10000);
connection.connect();
System.out.println("connected");
SASLAuthentication.unBlacklistSASLMechanism("PLAIN");
SASLAuthentication.blacklistSASLMechanism("DIGEST-MD5");
} catch (SmackException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (XMPPException e) {
e.printStackTrace();
}
and is running perfect.
The exact error is: "Error:(66, 18) error: AccountManager(XMPPConnection) has private access in AccountManager"
I've wasted like 2-3 hours trying to find it but got no answers. I'm a noob so please forgive me if this is a basic question. Also please reply on that as I am stuck and can not move forward.
Thanks alot for the time!!
You need to get an instance from the accountManager that's relevant to your Xmpp connection.
AccountManager ac = AccountManager.getInstance(XMPPConnection connection)

Integrating Smack 4.1 in android

I have gone through smack 4.1 documentation as given https://github.com/igniterealtime/Smack/tree/master/documentation . But I'm not getting connected when try to connect to openfire server. Can anyone give me a working code. My openfire configuration is working. I have checked it using mac IM client.
I had the same issue when I tried exactly as in documentation.
But I found some changes needed after a research. Here is the code that I've used.
public void connect() throws IOException, XMPPException, SmackException {
XMPPTCPConnectionConfiguration.Builder config = XMPPTCPConnectionConfiguration.builder();
config.setUsernameAndPassword("username","password");
config.setServiceName(Config.XMPP_DOMAIN);
config.setHost(Config.XMPP_HOST);
config.setPort(Config.XMPP_PORT);
mConnection = new XMPPTCPConnection(config.build());
try {
mConnection.connect();
mConnection.login();
} catch (SmackException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (XMPPException e) {
e.printStackTrace();
}
//ChatManager.getInstanceFor(mConnection).addChatListener(this);
}
check out the link working example http://developer.samsung.com/technical-doc/view.do?v=T000000119

setLayerType substitute for Android 2.3.3?

How can I make my Android app compatible with previous Android versions if I use API from the view class like setLayerType that are not on the Android 2.3.3 API? What can I substitute this method with?
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
// only for gingerbread and newer versions
// setLayerType
}
or through reflection
try {
Method setLayerTypeMethod = mWebView.getClass().getMethod("setLayerType", new Class[] {int.class, Paint.class});
if (setLayerTypeMethod != null)
setLayerTypeMethod.invoke(yourView, new Object[] {LAYER_TYPE_SOFTWARE, null});
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
to disable hardware acceleraton you can use android:hardwareAccelerated="false"
more detail here: http://developer.android.com/guide/topics/graphics/hardware-accel.html#controlling
but pay attention with android:hardwareAccelerated="false" because you will pay the cost with app performance
i think the best deal is to use reflection as described by blackbelt

setPin() shows error in eclipse that "setPin() is undefined for BluetoothDevice"

I don't find many BluetoothDevice methodes such as , setPasskey(), setPin(), setPairingConfirmation(), setRemoteOutOfBandData().
I searched on Android site as well but I don't find it. When I use these methods in my program in eclipse it shows me an error: its undefined for the type BluetoothDevice.
Are these obsolete now? If yes then what are the new methods of same type.
It is assumed that paring process is performed only by applications delivered with a platform!
This means that this application have access to hidden API. For example you can find hidden API for Bluetooth here.
It is strongly recommended to not use hidden API since it can change without warning in next Android release.
If you are still planning to use this API safest way is to use reflection:
try {
Class<? extends BluetoothDevice> c = device.getClass(); // BluetoothDevice.class
Method createBond = c.getMethod("createBond");
Object result = createBond.invoke(device);
Boolean castedResult = (Boolean)result;
Log.d(TAG, "Result: " + castedResult.toString());
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
There is also alternative way to easy use hidden API, but I didn't try it.

Categories

Resources