Skip to content

Commit c14822b

Browse files
Update expected signature in MainActivity and related changes for v0.2.2
1 parent 8ee7ac7 commit c14822b

File tree

3 files changed

+79
-36
lines changed

3 files changed

+79
-36
lines changed

app/src/main/java/com/webileapps/protect/sample/MainActivity.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class MainActivity : AppActivity() {
3636
SecurityChecker.SecurityCheckState.WARNING, // ongoingCallCheck
3737
SecurityChecker.SecurityCheckState.WARNING, // appSignatureCheck
3838
"com.webileapps.protect.sample", // expectedPackageName
39-
"" // expectedSignature
39+
"2A36434023EECADABE4F43B09C4BF95AB2594256BD0A2577424B85BC2C6E0CBB" // expectedSignature
4040
)
4141
)
4242

protect/src/main/java/com/webileapps/safeguard/FridaDetection.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,9 @@ public boolean detectFridaDebugging() {
123123
boolean fridaTracer = detectFridaTracer();
124124

125125
boolean detected = fridaServer || fridaPort || fridaLibrary || fridaTracer;
126-
Log.e("Security>>>", "Frida detection result: Server=" + fridaServer + ", Port=" + fridaPort + ", Library=" + fridaLibrary + ", Tracer=" + fridaTracer);
126+
if (detected) {
127+
Log.e("Security>>>", "Frida detection result: Server=" + fridaServer + ", Port=" + fridaPort + ", Library=" + fridaLibrary + ", Tracer=" + fridaTracer);
128+
}
127129

128130
return detected;
129131
}

protect/src/main/java/com/webileapps/safeguard/SignatureComparison.java

Lines changed: 75 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -7,54 +7,95 @@
77
import android.os.Build;
88
import android.util.Log;
99
import java.security.MessageDigest;
10+
import java.security.NoSuchAlgorithmException;
1011

1112
public class SignatureComparison {
1213
private static final String TAG = "AppSignatureVerifier";
13-
14+
private static final String HASH_ALGORITHM = String.join("-", "SHA", "256");
15+
1416
public boolean isAppSignatureValid(Context context, String expectedSignatureHash) {
1517
try {
16-
PackageManager packageManager = context.getPackageManager();
17-
String packageName = context.getPackageName();
18-
android.content.pm.PackageInfo packageInfo;
19-
20-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
21-
packageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNING_CERTIFICATES);
22-
} else {
23-
packageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
24-
}
25-
26-
Signature[] signatures;
27-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
28-
SigningInfo signingInfo = packageInfo.signingInfo;
29-
if (signingInfo != null) {
30-
signatures = signingInfo.getApkContentsSigners();
31-
} else {
32-
signatures = null;
33-
}
34-
} else {
35-
signatures = packageInfo.signatures;
18+
// Validate input parameters
19+
if (context == null || expectedSignatureHash == null) {
20+
throw new IllegalArgumentException("Null context or expected hash");
3621
}
3722

38-
if (signatures == null || signatures.length == 0) {
39-
Log.e(TAG, "No signatures found for the app.");
23+
final String packageName = context.getPackageName();
24+
final Signature signature = getAppSignature(context, packageName);
25+
26+
if (signature == null) {
27+
Log.e(TAG, "No valid signature found");
4028
return false;
4129
}
4230

43-
MessageDigest md = MessageDigest.getInstance("SHA-1");
44-
byte[] originalDigest = md.digest(expectedSignatureHash.getBytes());
45-
byte[] currentDigest = md.digest(signatures[0].toByteArray());
31+
final String currentHash = calculateSignatureHash(signature);
32+
final String normalizedExpected = normalizeHash(expectedSignatureHash);
33+
final String normalizedCurrent = normalizeHash(currentHash);
4634

47-
boolean isValid = MessageDigest.isEqual(originalDigest, currentDigest);
48-
if (isValid) {
49-
Log.d(TAG, "App signature is valid.");
50-
} else {
51-
Log.e(TAG, "App signature is invalid! Possible tampering detected.");
35+
final boolean isValid = constantTimeEquals(normalizedExpected, normalizedCurrent);
36+
37+
if (!isValid) {
38+
Log.w(TAG, "Signature mismatch!\n" +
39+
"Expected: " + normalizedExpected + "\n" +
40+
"Actual: " + normalizedCurrent);
5241
}
53-
42+
5443
return isValid;
5544
} catch (Exception e) {
56-
Log.e(TAG, "Error verifying app signature", e);
45+
Log.e(TAG, "Signature verification failed: " + e.getMessage());
5746
return false;
5847
}
5948
}
60-
}
49+
50+
private Signature getAppSignature(Context context, String packageName)
51+
throws PackageManager.NameNotFoundException {
52+
final PackageManager pm = context.getPackageManager();
53+
final int flags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P ?
54+
PackageManager.GET_SIGNING_CERTIFICATES :
55+
PackageManager.GET_SIGNATURES;
56+
57+
final android.content.pm.PackageInfo packageInfo = pm.getPackageInfo(packageName, flags);
58+
59+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
60+
final SigningInfo signingInfo = packageInfo.signingInfo;
61+
return (signingInfo != null && signingInfo.hasMultipleSigners()) ?
62+
signingInfo.getApkContentsSigners()[0] :
63+
signingInfo != null ? signingInfo.getSigningCertificateHistory()[0] : null;
64+
}
65+
return packageInfo.signatures != null ? packageInfo.signatures[0] : null;
66+
}
67+
68+
private String calculateSignatureHash(Signature signature)
69+
throws NoSuchAlgorithmException {
70+
final MessageDigest md = MessageDigest.getInstance(HASH_ALGORITHM);
71+
final byte[] hashBytes = md.digest(signature.toByteArray());
72+
return bytesToHex(hashBytes);
73+
}
74+
75+
// Constant-time comparison to prevent timing attacks
76+
private boolean constantTimeEquals(String a, String b) {
77+
if (a.length() != b.length()) {
78+
return false;
79+
}
80+
81+
int result = 0;
82+
for (int i = 0; i < a.length(); i++) {
83+
result |= a.charAt(i) ^ b.charAt(i);
84+
}
85+
return result == 0;
86+
}
87+
88+
private String normalizeHash(String hash) {
89+
return hash.replaceAll("[^A-Fa-f0-9]", "").toUpperCase();
90+
}
91+
92+
private static String bytesToHex(byte[] bytes) {
93+
final char[] hexChars = new char[bytes.length * 2];
94+
for (int i = 0; i < bytes.length; i++) {
95+
final int v = bytes[i] & 0xFF;
96+
hexChars[i * 2] = "0123456789ABCDEF".charAt(v >>> 4);
97+
hexChars[i * 2 + 1] = "0123456789ABCDEF".charAt(v & 0x0F);
98+
}
99+
return new String(hexChars);
100+
}
101+
}

0 commit comments

Comments
 (0)