Hello I want to read SHA and MD5 fingerprint value of keystore programmatically of my app from which it was signed.
I'll take either SHA or MD5 value as key for security. This key I will use in the code to encrypt something and decrypt same at server end.
Is there any way to find this or is there any way to do same using different good approach. This should be in such a way nobody other can find this key.
Thanks in advance.
PackageInfo info;
try {
info = getPackageManager().getPackageInfo(
"com.your.package.name", PackageManager.GET_SIGNATURES);
for (Signature signature : info.signatures) {
MessageDigest md;
md = MessageDigest.getInstance("SHA");
md.update(signature.toByteArray());
String hash_key = new String(Base64.encode(md.digest(), 0));
}
} catch (NameNotFoundException e1) {
} catch (NoSuchAlgorithmException e) {
} catch (Exception e) {
}
try this:
/**
*
* #param pkg packageName
* #return
*/
public String getSingInfo (String pkg) {
try {
PackageInfo packageInfo = getPackageManager().getPackageInfo(pkg, PackageManager.GET_SIGNATURES);
Signature[] signs = packageInfo.signatures;
Signature sign = signs[0];
String s = getMd5(sign);
return "md5:" + s ;
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
private String getMd5 (Signature signature) {
return encryptionMD5(signature.toByteArray());
}
public static String encryptionMD5(byte[] byteStr) {
MessageDigest messageDigest = null;
StringBuffer md5StrBuff = new StringBuffer();
try {
messageDigest = MessageDigest.getInstance("MD5");
messageDigest.reset();
messageDigest.update(byteStr);
byte[] byteArray = messageDigest.digest();
for (int i = 0; i < byteArray.length; i++) {
if (Integer.toHexString(0xFF & byteArray[i]).length() == 1) {
md5StrBuff.append("0").append(Integer.toHexString(0xFF & byteArray[i]));
} else {
md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i]));
}
}
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return md5StrBuff.toString();
}
Find the path of your application's APK file by calling Context.getPackageCodePath()
Copy that APK to a writeable directory of your choice
Use apk-parser to get the information you need from the APK (see example below)
That library is able to decompress the APK file and parse all of its content. An example extracted from the apk-parser's Github page, tailored to your needs:
try {
ApkParser apkParser = new ApkParser(new File(filePath));
ApkSignStatus signStatus = apkParser.verifyApk(); // not needed
List<CertificateMeta> certs = apkParser.getCertificateMetas();
for (CertificateMeta certificateMeta : certs) {
System.out.println(certificateMeta.getCertMd5());
}
} catch (Exception e) {
e.printStackTrace();
}
Added below solution in-case if someone is looking for it for the first time, and don't know how to get it from studio as well.
Many times we search and get suggestion links.
Easiest Way
Open Android Studio
Open Your Project
Click on Gradle (From Right Side Panel, you will see Gradle Bar)
Click on Refresh (Click on Refresh from Gradle Bar, you will see List Gradle scripts of your Project)
Click on Your Project (Your Project Name form List (root))
Click on Tasks
Click on android
Double Click on signingReport (You will get SHA1 and MD5 in Run Bar)
Check Screenshot below:
Related
I'm trying to implement a way to communicate with my backend-server and be sure that my backend only answers, if it's my application which is calling.
So my idea is, that i just send the SHA1/MD5 fingerprint with the HTTPS POST request and verify it on the backend server. If the fingerprint matches, the server will answer.
So my first question is: How do I get these programmatically at runtime? Is it even possible?
The second question is: Can it be that easy? Or do i really have to set up an OAuth-Server (or use the google-api)?...The thing is, that I think that OAuth is a bit overkill for my use case and I don't want to handle the expiration/refresh-token stuff.
I have complemented the solution, proposed by Zulqumain Jutt, to be able to get the the result in the common form, like:
KeyHelper: MD5 56:ff:2f:1f:55:fa:79:3b:2c:ba:c9:7d:e3:b1:d2:af
public class KeyHelper {
/**
* #param key string like: SHA1, SHA256, MD5.
*/
#SuppressLint("PackageManagerGetSignatures") // test purpose
static void get(Context context, String key) {
try {
final PackageInfo info = context.getPackageManager()
.getPackageInfo(BuildConfig.APPLICATION_ID, PackageManager.GET_SIGNATURES);
for (Signature signature : info.signatures) {
final MessageDigest md = MessageDigest.getInstance(key);
md.update(signature.toByteArray());
final byte[] digest = md.digest();
final StringBuilder toRet = new StringBuilder();
for (int i = 0; i < digest.length; i++) {
if (i != 0) toRet.append(":");
int b = digest[i] & 0xff;
String hex = Integer.toHexString(b);
if (hex.length() == 1) toRet.append("0");
toRet.append(hex);
}
Log.e(KeyHelper.class.getSimpleName(), key + " " + toRet.toString());
}
} catch (PackageManager.NameNotFoundException e1) {
Log.e("name not found", e1.toString());
} catch (NoSuchAlgorithmException e) {
Log.e("no such an algorithm", e.toString());
} catch (Exception e) {
Log.e("exception", e.toString());
}
}
}
You can generate one something like in below example:
private void getKeyHash(String hashStretagy) {
PackageInfo info;
try {
info = getPackageManager().getPackageInfo(BuildConfig.APPLICATION_ID, PackageManager.GET_SIGNATURES);
for (Signature signature : info.signatures) {
MessageDigest md;
md = MessageDigest.getInstance(hashStretagy);
md.update(signature.toByteArray());
String something = new String(Base64.encode(md.digest(), 0));
Log.e("KeyHash -->>>>>>>>>>>>" , something);
// Notification.registerGCM(this);
}
} catch (PackageManager.NameNotFoundException e1) {
Log.e("name not found" , e1.toString());
} catch (NoSuchAlgorithmException e) {
Log.e("no such an algorithm" , e.toString());
} catch (Exception e) {
Log.e("exception" , e.toString());
}
}
use Like This:
getKeyHash("SHA");
getKeyHash("MD5");
First Answer: You can use above method it's secure and unique i use it all the time.
Second Answer: You can Use Auth keys but that entirely depends on you , what are you comfortable with
What you're trying to do is impossible. Anything you send to the server as an id can be copied by another application. That's why you have user's with passwords that aren't in the application- the password from an outside source is the only way to be sure the request is valid. And that only proves the user is valid, not that its from your application.
Kotlin Version of Artur's
Example key string: "SHA1" or "SHA256" or "MD5".
fun getSig(context: Context, key: String) {
try {
val info = context.packageManager.getPackageInfo(
BuildConfig.APPLICATION_ID,
PackageManager.GET_SIGNATURES
)
for (signature in info.signatures) {
val md = MessageDigest.getInstance(key)
md.update(signature.toByteArray())
val digest = md.digest()
val toRet = StringBuilder()
for (i in digest.indices) {
if (i != 0) toRet.append(":")
val b = digest[i].toInt() and 0xff
val hex = Integer.toHexString(b)
if (hex.length == 1) toRet.append("0")
toRet.append(hex)
}
val s = toRet.toString()
Log.e("sig", s)
}
} catch (e1: PackageManager.NameNotFoundException) {
Log.e("name not found", e1.toString())
} catch (e: NoSuchAlgorithmException) {
Log.e("no such an algorithm", e.toString())
} catch (e: Exception) {
Log.e("exception", e.toString())
}
}
Developers or clients who want to use my skd should go to my website to apply for a APP_KEY.To apply for a APP_KEY,they should offer the app's package name,something like this "com.edward.myapp".Also the SHA-1 of the developers's certificate(generated from keytool).
Now I can only send the APP_KEY to my server to verify the APP_KEY,the only thing I know is that the APP_KEY is valid or invalid.But I don't know if it is my clients' app,it can be anyone else's app,and it can be any package name.I don't want to something like this happen.
So how can I verify it to ensure it is the right app to use the sdk?
Your SDK at runtime can obtain the SHA1 of the certificate used to sign the APK.
String getSignatureSha1(Context context) {
PackageManager pm = context.getPackageManager();
PackageInfo info = null;
try {
info = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES);
} catch (NameNotFoundException e) {
Log.e(TAG, "Could not find info for " + context.getPackageName());
return null;
}
byte[] signatureBytes = info.signatures[0].toByteArray();
MessageDigest md = MessageDigest.getInstance("SHA");
md.update(signatureBytes);
byte[] digestBytes = md.digest();
StringBuilder builder = new StringBuilder();
for (int i = 0; i < digestBytes.length; i++) {
// you can omit this if block if you don't care about the colon separators
if (i > 0) {
builder.append(':');
}
builder.append(String.format("%02X", digestBytes[i] & 0xFF));
}
return builder.toString();
}
You should do this once when the app starts and cache the result if you need it more than once.
I'm trying to put my debbug hash key, which is : "e3U9nzK7A8gyWoCiNUZQA/C+bZI=".
But every time i put it inside the key hash section on my Facebook App it changes to "e3U9nzK7A8gyWoCiNUZQA%2FC%2BbZI%3D" automatically, making my app useless.
I used two methods to get this key, and it returned the same : keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64
and :
private void getAppKeyHash() {
try {
PackageInfo info = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES);
for (Signature signature : info.signatures) {
MessageDigest md;
md = MessageDigest.getInstance("SHA");
md.update(signature.toByteArray());
String something = new String(Base64.encode(md.digest(), 0));
Log.d("Hash key", something);
}
}
catch (NameNotFoundException e1) {
// TODO Auto-generated catch block
Log.e("name not found", e1.toString());
}
catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
Log.e("no such an algorithm", e.toString());
}
catch (Exception e){
Log.e("exception", e.toString());
}
}
Try out this
try {
PackageInfo info = getPackageManager().getPackageInfo(com.domain,
PackageManager.GET_SIGNATURES);
for (Signature signature : info.signatures) {
MessageDigest md = MessageDigest.getInstance("SHA");
md.update(signature.toByteArray());
Log.i("PXR", com.domain.Base64.encodeBytes(md.digest()));
}
} catch (NameNotFoundException e) {
} catch (NoSuchAlgorithmException e) {
}
I have the same problem, and realised this is a bug on facebook´s end. See link. Very anoying.
Edit
The only working solution (but ugly) until it is solved seems to be to force login through web interface, since SSO is the one using the hashkey.
If using the login-button:
LoginButton authButton = (LoginButton) view.findViewById(R.id.authButton);
authButton.setLoginBehavior(SessionLoginBehavior.SUPPRESS_SSO);
Source: Android - Force Facebook connection - Stack Overflow
Edit 2
It can be solved though; I asked a friend (over Skype, he´s on a mac) to add them for me. And he managed to get it right (but I do not know how).
Edit 3
Now this issue seems to have solved itself for me. Entered hashkeys no longer gets rewritten. Whether it is solved by fb-team or just required a computer restart from me I do not know.
I have recently started working on facebook API, where I came under the situation of generating Hash key and registering it on facebook for further use.
For that, I used the following code
PackageInfo info;
try {
info = getPackageManager().getPackageInfo("com.you.name", PackageManager.GET_SIGNATURES);
for (Signature signature : info.signatures) {
MessageDigest md;
md = MessageDigest.getInstance("SHA");
md.update(signature.toByteArray());
String something = new String(Base64.encode(md.digest(), 0));
//String something = new String(Base64.encodeBytes(md.digest()));
Log.e("hash key", something);
}
} catch (NameNotFoundException e1) {
Log.e("name not found", e1.toString());
} catch (NoSuchAlgorithmException e) {
Log.e("no such an algorithm", e.toString());
} catch (Exception e) {
Log.e("exception", e.toString());
}
All worked well, as I was able to work with facebook in my app.
But, after publishing the app on playstore, I found the error Invalid_Android_key parameter. The key does not match any allowed key Configure your app key hashes at https://developers.facebook.com/apps/..........
Please, let me know the cause of this problem and how to handle this.
I had same Problem, after creating the apk, the key hash is changed! because using this code u get the debug keystore hash, but when creating apk, it's another hash, gotta capture it from log after trying ur apk on emulator , then delete code and export again without this log , i know it's a hassle but for me it was easier than keytool...
I would like to offer a md5 verifier in my android app which compares the server md5 and the just created one on the device.
The output should be like correct or incorrect and not that the user has to compare the hashes.
I already found out that it's possible to get the hash on android via
/system/xbin/busybox md5sum /sdcard/Download/FILENAME
. Of cause I can print the output of the command to screen but that's not what I want.
Because I don't want to reinvent the wheel is something like that already available? SHA1 would be possible too, both hashes are available.
Please help!
I have used this method to calculate md5 inside of Android Application
private String getMD5(String file){
String md5 = "";
try {
MessageDigest md = MessageDigest.getInstance("MD5");
FileInputStream is = this.openFileInput(file);
DigestInputStream dis = new DigestInputStream(is, md);
byte data[] = new byte[1024];
#SuppressWarnings("unused")
int count;
while ((count = dis.read(data)) != -1) {
}
byte[] digest = md.digest();
for (int i=0; i < digest.length; i++) {
md5 += Integer.toString( ( digest[i] & 0xff ) + 0x100, 16).substring( 1 );
}
return md5;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return md5;
}
With "the server md5" I guess you mean another file on the server containing an md5 hash.
So you could just download the md5 file, open it and compare the string inside with your calculated md5.