Подтвердить что ты не робот

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 и т.д.

4b9b3361

Ответ 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 всем участвующим разработчикам, попросив их запустить его на своем устройстве и сообщить мне отображаемый хеш.