Android сравнить подпись текущего пакета с debug.keystore
Как и все, что мы делаем, у меня есть приложение, которое подписывается debug.keystore(по умолчанию), когда оно находится в режиме разработки (сборка). Когда это происходит, мы подписываем его с помощью нашего закрытого ключа.
Есть ли способ определить во время выполнения, что текущий пакет подписан с debug.keystore(находится в режиме разработки) или подписан с нашим личным ключом (находится в режиме производства).
Я пробовал что-то вроде
PackageManager packageManager = getPackageManager();
try {
Signature[] signs = packageManager.getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES).signatures;
for (Signature signature : signs) {
Log.d(TAG, "sign = " + signature.toCharsString());
}
} catch (NameNotFoundException e) {
e.printStackTrace();
}
Я не знаю, что делать дальше? Правильно ли это? Как получить сопоставимую подпись debug.keystore?
Я знаю, что существует MD5 Fingerprint keytool -list -keystore ~/.android/debug.keystore
, но в классе Signature не существует метода "md5 fingerprint".
Я хочу сделать это из-за MapView Key, Logging, LicenseChecker и т.д.
Ответы
Ответ 1
Подпись в PackageInfo
, похоже, не имеет имени, так как в этом поле не содержится подпись пакета, а цепочка сертификатов подписчика X509. Обратите внимание, что (большую часть времени) эта цепочка, по-видимому, ограничивается одним самозаверяющим сертификатом.
Согласно странице разработчика Android Подписывание ваших приложений сертификат сертификата отладки создается с помощью этого DN: CN=Android Debug,O=Android,C=US
Поэтому легко проверить, было ли приложение подписано в режиме отладки:
private static final X500Principal DEBUG_DN = new X500Principal("CN=Android Debug,O=Android,C=US");
/* ... */
Signature raw = packageManager.getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES).signatures[0];
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(raw.toByteArray()));
boolean debug = cert.getSubjectX500Principal().equals(DEBUG_DN);
Ответ 2
Основываясь на ответе Jcs, мы используем это, чтобы узнать во время выполнения, который создал запущенный пакет:
private enum BuildSigner {
unknown,
Joe,
Carl,
Linda
}
private BuildSigner whoBuiltThis() {
try {
PackageManager packageManager = getPackageManager();
PackageInfo info = packageManager.getPackageInfo(getPackageName(),
PackageManager.GET_SIGNATURES);
Signature[] signs = info.signatures;
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate)cf.generateCertificate(
new ByteArrayInputStream(signs[0].toByteArray()));
PublicKey key = cert.getPublicKey();
int modulusHash = ((RSAPublicKey)key).getModulus().hashCode();
switch (modulusHash) {
case 123456789:
return BuildSigner.Joe;
case 424242424:
return BuildSigner.Carl;
case -975318462:
return BuildSigner.Linda;
}
} catch (Exception e) {
}
return BuildSigner.unknown;
}
Для любого задействованного сертификата вам просто нужно найти хэш один раз и добавить его в список.
Простейшим способом "найти хэш один раз" может быть просто добавить всплывающий тост перед оператором switch, который отображает modulusHash
, скомпилировать ваше приложение, запустить его, записать хеш, удалить тост-код и добавить хэш в список.
В качестве альтернативы, когда я это осуществил, я создал небольшое приложение шаблонов с одним действием и один TextView
с идентификатором tv
в основном макете, поместив его в действие:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
int hash = 0;
try{
PackageManager packageManager = getPackageManager();
PackageInfo info = packageManager.getPackageInfo(
"com.stackexchange.marvin", PackageManager.GET_SIGNATURES);
Signature[] signs = info.signatures;
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(
new ByteArrayInputStream(signs[0].toByteArray()));
PublicKey key = cert.getPublicKey();
hash = ((RSAPublicKey) key).getModulus().hashCode();
}catch(Exception e){}
TextView tv = ((TextView)findViewById(R.id.tv));
tv.setText("The Stack Exchange app signature hash is " + hash + ".");
tv.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 24);
}
(измените com.stackexchange.marvin
на ваше имя приложения), скомпилировали это мини-приложение и отправили APK всем участвующим разработчикам, попросив их запустить его на своем устройстве и сообщить мне отображаемый хеш.