Is there any way to get the private key that current APK was signed with?
The operation is completely safe, since any modification (injection) to app would need a new signing and new key pair. So if private key (that developer is aware of that) is accessible to the running code, it's only accessible to the original code not a malicious one.
X509Certificate allows access to PublicKey, but I need access to PrivateKey.
public static X509Certificate GetCertificate(Context context) {
PackageManager pm = context.getPackageManager();
String packageName = context.getPackageName();
PackageInfo packageInfo = null;
try {
packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
Signature[] signatures = packageInfo.signatures;
byte[] cert = signatures[0].toByteArray();
InputStream input = new ByteArrayInputStream(cert);
CertificateFactory cf = null;
try {
cf = CertificateFactory.getInstance("X509");
} catch(CertificateException e) {
e.printStackTrace();
}
X509Certificate c = null;
try {
c = (X509Certificate) cf.generateCertificate(input);
} catch(CertificateException e) {
}
return c;
}
Edit:
A side question can be:
Is there any way to ensure that currently running code is running inside the APK with the original certificate?
(Everybody have access to public key, so it's not a good candidate to check against, but private key is only known by original developer which can protect it (in some way) and check package certification against that.)
The private key is used only for signing the APK and never (in theory) leaves the place of signing. So it's not possible to recover it from the APK.
Update: and no, the code itself can't check the validity of its own image. If the image has been altered, it's trivial to remove the check as well.
Related
I want to sign the pdf using pdf digest. I have created the hash using below code,
byte[] buffer = new byte[1024];
int numOfBytesRead =0;
MessageDigest md = null;
md = MessageDigest.getInstance("SHA256","BC");
while((numOfBytesRead = content.read(buffer)) != -1 ){
md.update(buffer, 0, numOfBytesRead);
}
byte[] digest = md.digest();
At the end I need to attach this signature to my pdf. I have found one solution Create pkcs7 signature from file digest, but the algorithm used in the link is SHA256withRSA. My privatekey is genearted using EC algorithm and I need to use SHA256withECDSA.Is it possible to just sign the Hash using SHA256withECDSA and attach the signature to the pdf using PDFBox ExternalSigning Interface.
There are several situations in which Adobe calls a signer's certificate invalid even though apparently it is valid; in the case at hand in particular:
Key usage or Extended key usage values not appropriate
PAdES signature misses an ESS signing-certificate-v2 attribute
Key usage or Extended key usage values not appropriate
This is based on the information the OP first published as an answer
I tried below code still the pdf says Signature is invalid. Can you please check the code,
[...]
I have attached the pdf . Pdf file created
Indeed, Adobe Reader says the signature is invalid, but look more closely:
It says "Document has not been modified since this signature was applied" - This means that the signature is mathematically correct!
The issue is that the "Signer's certificate is invalid", and the reason for this can be seen when digging into the signature property dialogues:
Thus, the problem is that your signer certificate is Not valid for usage.
This is due to the highlighted attribute, while the Key Usage Digital Signature is ok, the "Extended key usage" 1.3.6.1.5.5.8.2.2 (OID for IPSEC Protection) is not!
According to the Adobe Digital Signatures Guide for IT, Adobe Acrobat accepts only
one or more of the following Key usage values (if any)
nonRepudiation
signTransaction (11.0.09 only)
digitalSignature (11.0.10 and later)
and one or more of the following Extended key usage values (if any)
emailProtection
codeSigning
anyExtendedKeyUsage
1.2.840.113583.1.1.5 (Adobe Authentic Documents Trust)
Due to its IPSEC Protection extended key usage value, therefore, your certificate is not considered valid for signing PDF documents.
This probably only is an issue in legacy ISO 32000-1 signatures, probably not in PAdES signatures.
PAdES signature misses an ESS signing-certificate-v2 attribute
This is based on the information the OP first published as an answer
I have created 2 pdf files, PDFA is signed using the digest of the pdf content with below code,
[...]
PDFA
PDFB is created with the same private key and certificate, but instead of digest I am using pdf document content directly which gives me valid signed pdf, PDFB code below,
[...]
PDFB
I think something is missing in the signing part of PDFA which I couldn't figure out.
Here the main difference is not whether you explicitly calculate the hash yourself or allow it to be calculated implicitly, the main difference is that the signature in PDFB includes an ESS signing-certificate-v2 attribute while the one in PDFA does not. This attribute is generated between
//PAdES - PDF Advanced Electronic Signature
and
//PAdES-end
As the comments already hint, this is only necessary for PAdES signatures, not for legacy ISO 32000-1 ones. The answer the OP took his original code from referred to creating a legacy ISO 32000-1 signature (and, therefore, works alright) while the OP creates a PAdES signature.
The presence of an ESS signing certificate attribute is required by the PAdES specification ETSI EN 319 142-1:
e) Generators shall use either the signing certificate or the signing-certificate v2 attribute, depending on the hash function, in accordance with ETSI EN 319 122-1.
(ETSI EN 319 142-1, section 6.3 PAdES baseline signatures)
It references the CAdES specification ETSI EN 319 122-1 which in turn requires
h) Requirement for SPO: ESS signing-certificate. The ESS signing-certificate attribute shall be used if the SHA-1 hash algorithm is used.
i) Requirement for SPO: ESS signing-certificate-v2. The ESS signing-certificate-v2 attribute shall be used when another hash algorithms than SHA-1 is used.
(ETSI EN 319 122-1, section 6.3 Requirements on components and services)
I tried below code still the pdf says Signature is invalid. Can you please check the code,
System.out.println("Hash Signing started");
List<Certificate> certList = getFormatCertificate(strCertificate);
PrivateKey privateKey;
CMSSignedData s = null;
Security.addProvider(new BouncyCastleProvider());
byte[] signature = null;
try {
privateKey = loadPrivateKey(strPrivatekey);
byte[] buffer = new byte[1024];
int numOfBytesRead =0;
MessageDigest md = null;
md = MessageDigest.getInstance("SHA256","BC");
while((numOfBytesRead = content.read(buffer)) != -1 ){
md.update(buffer, 0, numOfBytesRead);
}
byte[] digest = md.digest();
// Separate signature container creation step
JcaCertStore certs = new JcaCertStore(certList);
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
Attribute attr = new Attribute(CMSAttributes.messageDigest,
new DERSet(new DEROctetString(digest)));
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(attr);
SignerInfoGeneratorBuilder builder = new SignerInfoGeneratorBuilder(new BcDigestCalculatorProvider())
.setSignedAttributeGenerator(new DefaultSignedAttributeTableGenerator(new AttributeTable(v)));
//AlgorithmIdentifier sha256withECDSA = new DefaultSignatureAlgorithmIdentifierFinder().find(signerAlgorithm);
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
InputStream in = new ByteArrayInputStream(certList.get(certList.size()-1).getEncoded());
X509Certificate cert = (X509Certificate) certFactory.generateCertificate(in);
gen.addSignerInfoGenerator(builder.build(
new JcaContentSignerBuilder(signerAlgorithm).build(privateKey),
new JcaX509CertificateHolder(cert)));
//DErse
// gen.addSignerInfoGenerator(builder.build(
// new JcaContentSignerBuilder(sha256withRSA,
// new DefaultDigestAlgorithmIdentifierFinder().find(sha256withRSA))
// .build(PrivateKeyFactory.createKey(privateKey.getEncoded())),
// new JcaX509CertificateHolder(cert)));
gen.addCertificates(certs);
s = gen.generate(new CMSAbsentContent(), false);
System.out.println("Hash sign completed");
signature = s.getEncoded();// ConstructEcdsaSigValue(s.getEncoded());
} catch (GeneralSecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("GeneralSecurityException ::"+e.toString());
} catch (OperatorCreationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("OperatorCreationException ::"+e.toString());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("IOException ::"+e.toString());
} catch (CMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("CMSException ::"+e.toString());
}finally{
return signature;
}
I have attached the pdf . Pdf file created
#Mkl/Tilman : I have created 2 pdf files, PDFA is signed using the digest of the pdf content with below code,
System.out.println("Hash Signing started");
List<Certificate> certList = getFormatCertificate(strCertificate);
PrivateKey privateKey;
CMSSignedData s = null;
Security.addProvider(new BouncyCastleProvider());
byte[] signature = null;
try {
privateKey = loadPrivateKey(strPrivatekey);
/*byte[] buffer = new byte[1024];
int numOfBytesRead =0;
MessageDigest md = null;
//md = MessageDigest.getInstance("SHA256","BC");
md = MessageDigest.getInstance("SHA-256");
while((numOfBytesRead = content.read(buffer)) != -1 ){
md.update(buffer, 0, numOfBytesRead);
}
byte[] digest = md.digest();*/
MessageDigest md = MessageDigest.getInstance("SHA256", "BC");
byte[] digest = md.digest(IOUtils.toByteArray(content));
// Separate signature container creation step
JcaCertStore certs = new JcaCertStore(certList);
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
Attribute attr = new Attribute(CMSAttributes.messageDigest,
new DERSet(new DEROctetString(digest)));
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(attr);
SignerInfoGeneratorBuilder builder = new SignerInfoGeneratorBuilder(new BcDigestCalculatorProvider())
.setSignedAttributeGenerator(new DefaultSignedAttributeTableGenerator(new AttributeTable(v)));
//AlgorithmIdentifier sha256withECDSA = new DefaultSignatureAlgorithmIdentifierFinder().find(signerAlgorithm);
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
InputStream in = new ByteArrayInputStream(certList.get(certList.size()-1).getEncoded());
X509Certificate cert = (X509Certificate) certFactory.generateCertificate(in);
gen.addSignerInfoGenerator(builder.build(
new JcaContentSignerBuilder(signerAlgorithm).build(privateKey),
new JcaX509CertificateHolder(cert)));
//DErse
// gen.addSignerInfoGenerator(builder.build(
// new JcaContentSignerBuilder(sha256withRSA,
// new DefaultDigestAlgorithmIdentifierFinder().find(sha256withRSA))
// .build(PrivateKeyFactory.createKey(privateKey.getEncoded())),
// new JcaX509CertificateHolder(cert)));
gen.addCertificates(certs);
s = gen.generate(new CMSAbsentContent(), false);
System.out.println("Hash sign completed");
signature = s.getEncoded();// ConstructEcdsaSigValue(s.getEncoded());
} catch (GeneralSecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("GeneralSecurityException ::"+e.toString());
} catch (OperatorCreationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("OperatorCreationException ::"+e.toString());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("IOException ::"+e.toString());
} catch (CMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("CMSException ::"+e.toString());
}finally{
return signature;
}
PDFA
PDFB is created with the same private key and certificate, but instead of digest I am using pdf document content directly which gives me valid signed pdf, PDFB code below,
SignatureInterface signatureInterface = new SignatureInterface() {
#SuppressWarnings("rawtypes")
#Override
public byte[] sign(InputStream content) throws IOException {
try {
byte[] certificateByte = null;
Store certs = new JcaCertStore(certificates);
//PAdES - PDF Advanced Electronic Signature
//ESS - Enhanced Security Services
//ASN1 - Abstract Syntax Notation One-standard interface description language for defining data structures that can be serialized and deserialized in a cross-platform way
// Generating certificate hash
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(certificates.get(certificates.size()-1).getEncoded());
byte[] certHash = md.digest();
// Generating certificate hash ends
System.out.println("Cert hash generated");
//ESSCertIDv2 identifies the certificate from the hash
ESSCertIDv2 essCert1 =
new ESSCertIDv2(new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256), certHash);
ESSCertIDv2[] essCert1Arr =
{
essCert1
};
SigningCertificateV2 scv2 = new SigningCertificateV2(essCert1Arr);
Attribute certHAttribute =
new Attribute(PKCSObjectIdentifiers.id_aa_signingCertificateV2, new DERSet(scv2));
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(certHAttribute);
AttributeTable at = new AttributeTable(v);
//Create a standard attribute table from the passed in parameters - certhash
CMSAttributeTableGenerator attrGen = new DefaultSignedAttributeTableGenerator(at){
protected Hashtable createStandardAttributeTable(Map parameters)
{
Hashtable result = super.createStandardAttributeTable(parameters);
result.remove(CMSAttributes.signingTime);
return result;
}
};
//PAdES-end
System.out.println("CMSAttributeTableGenerator generated");
SignerInfoGeneratorBuilder genBuild =
new SignerInfoGeneratorBuilder(new BcDigestCalculatorProvider());
genBuild.setSignedAttributeGenerator(attrGen);
//Get single certificate
org.spongycastle.asn1.x509.Certificate certas1 = org.spongycastle.asn1.x509.Certificate.getInstance(ASN1Primitive.fromByteArray(certificates.get(certificates.size()-1).getEncoded()));
// ContentSigner interface creates SHA256withECDSA signer using PvtKey
ContentSigner sha1Signer = new JcaContentSignerBuilder(signerAlgorithm).build(privateKey);
//Creates SignerInfoGenerator using X.509 cert and ContentSigner
SignerInfoGenerator sifGen = genBuild.build(sha1Signer, new X509CertificateHolder(certas1));
// CMSSignedDataGenerator generates a pkcs7-signature message
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
gen.addCertificates(certs);
gen.addSignerInfoGenerator(sifGen);
//Creates CMS message from PDF
CMSProcessableInputStream msg = new CMSProcessableInputStream(content);
//Generate a CMS Signed Data object which can be carrying a detached CMS signature
//msg - content to be signed
CMSSignedData signedData = gen.generate(msg, false);
System.out.println("CMSSignedData is done");
return signedData.getEncoded();
} catch (GeneralSecurityException e) {
throw new IOException(e);
} catch (CMSException e) {
throw new IOException(e);
} catch (OperatorCreationException e) {
throw new IOException(e);
}
}
};
System.out.println("CMSSignedData is done2");
PDDocument pdDocument = PDDocument.load(inputfile);
System.out.println("pdDocument loaded");
pdDocument.addSignature(signature, signatureInterface);
PDFB
I think something is missing in the signing part of PDFA which I couldn't figure out.
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 want to check if installed android application has self signed or trusted certificate. The problem is that my code listed below raises CertificateException for all installed (including Google made) apps. Could you help me to find a problem why it doesn't work correctly?
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
List<ResolveInfo> runningServices = getPackageManager().queryIntentActivities(intent, 0);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance("AndroidCaStore");
ks.load(null, null);
tmf.init(ks);
X509TrustManager trustManager = (X509TrustManager)tmf.getTrustManagers()[0];
PackageManager manager = getPackageManager();
try {
for (ResolveInfo runningService : runningServices) {
PackageInfo info = manager.getPackageInfo(runningService.activityInfo.packageName,
PackageManager.GET_SIGNATURES);
Signature signature = info.signatures[0];
Signature[] arrSignatures = info.signatures;
for (Signature sig : arrSignatures) {
byte[] rawCert = sig.toByteArray();
InputStream certStream = new ByteArrayInputStream(rawCert);
CertificateFactory certFactory;
X509Certificate x509Cert;
try {
certFactory = CertificateFactory.getInstance("X509");
x509Cert = (X509Certificate) certFactory.generateCertificate(certStream);
trustManager.checkServerTrusted(new X509Certificate[] { x509Cert }, "RSA");
}
catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
}
}
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
The answer is pretty obvious: we can't validate android app certificate using trusted certificates chain (what normally do ssl guts to check web resource certificate), because they are self-signed. That is why checkServerTrusted function raises CertificateException during such check. This book gives following information:
Because a process is tied to a package name, and a package name is
tied to its signature, signatures play a role in securing the data
belonging to a package. A package is typically signed with a
self-signed PKI (Public Key Infrastructure) certificate. A certificate
identifies who the author of the package is. These certificates need
not be issued by a certificate authority. This means the information
in the certificate is not approved or validated by any authority. This
means one can create a certificate that says that their name is
Google. The only assurance is that this package name is reserved to
that user if no one had claimed it in the marketplace before, and any
subsequent updates to that package are given only to that user
(identified by that certificate).
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:
I have a home made logging system in my app. Of the things that it does is preform alot of logging (to file and logcat) while in development and can be turned off completely with one varible change. For a functionality example:
static public final boolean DEVELOPMENT_VERBOSE = true;
public static void developmentLogMessage(String message) {
if (DEVELOPMENT_VERBOSE)
Log.i("com.xxx.app", message);
}
The problem (maybe more an annoyance) I have is that I must remember to set DEVELOPMENT_VERBOSE = false for release. Is there a way in code to detect when the app is finalized for release (say checking for a signed apk for example) so I can set DEVELOPMENT_VERBOSE to false programmatically?
I looked at Detect if app was downloaded from Android Market but it seems my app has a signature even before signing it for the market.
try {
PackageManager manager = context.getPackageManager();
PackageInfo appInfo = manager.getPackageInfo(
"com.xxx.app", PackageManager.GET_SIGNATURES
);
System.out.println(appInfo.signatures[0].toCharsString());
} catch (NameNotFoundException e) {
}
I was hoping the signatures array would be empty and I could key of of that. But no go.
You can use ProGuard to completely turn appropriate logs off when building a release. ProGuard can do a lot of interesting stuff. Among other things it can shrink unneeded code during the building process. For example, if you use debug log (Log.d()) during development, but want to disable it in release then you can add these lines to your proguard.cfg:
-assumenosideeffects class android.util.Log {
public static int d(...);
}
To enable ProGuard, set the property
proguard.config=proguard.cfg
to your project.properties (if you use default locations). Be noted that ProGuard will also do some other things by default so you probably should take some additional steps when releasing your project. At least you certainly want to save generated mapping.txt file. See the ProGuard guide for more details.
You can look at which certificate was used to sign the app, and act accordingly.
For example:
for (Signature sig : getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES).signatures) {
// Get some (pseudo)uniqe value:
long sigHash = Arrays.hashCode(sig.toByteArray());
if (sigHash == releaseSigHash) DEVELOPMENT_VERBOSE = false;
}
Here is what I do for Google MapView, to decide which API Key to use, which is a similar problem
for (Signature sig : getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES).signatures) {
MessageDigest m = MessageDigest.getInstance("MD5");
m.update(sig.toByteArray());
md5 = new BigInteger(1, m.digest()).toString(16);
Log.d("findApiNøgle", "md5fingerprint: "+md5);
// Jacobs debug-nøgle
if (md5.equals("5fb3a9c4a1ebb853254fa1aebc37a89b")) return "0osb1BfVdrk1u8XJFAcAD0tA5hvcMFVbzInEgNQ";
// Jacobs officielle nøgle
if (md5.equals("d9a7385fd19107698149b7576fcb8b29")) return "0osb1BfVdrk3etct3WjSX-gUUayztcGvB51EMwg";
// indsæt din egen nøgle her:
}
After some research/work we can up with a solution that checks against the singed cert.
static public boolean DEVELOPMENT_VERBOSE = false;
static private final X500Principal RELEASE_DN = new X500Principal(
"CN=aaa,OU=bbb,O=ccc,L=ddd,ST=eee,C=fff"
);
// auto disable the development logs if the apk is signed with a cert
try {
PackageManager manager = context.getPackageManager();
PackageInfo appInfo = manager.getPackageInfo("com.xxx.app",
PackageManager.GET_SIGNATURES);
Signature raw = appInfo.signatures[0];
try {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(raw.toByteArray()));
//DEVELOPMENT_VERBOSE = cert.getSubjectX500Principal().equals(DEBUG_DN);
if (!cert.getSubjectX500Principal().equals(RELEASE_DN))
DEVELOPMENT_VERBOSE = true;
} catch (CertificateException e) {
}
} catch (NameNotFoundException e) {
}
As long as you use the same cert from version to version of the app this will always work.