Android сравнивает подпись текущего пакета с debug.keystore - PullRequest
14 голосов
/ 25 мая 2011

Как все, что у нас есть, у меня есть приложение, которое подписано debug.keystore (по умолчанию), когда оно находится в режиме разработки (build). Когда начинается производство, мы подписываем его своим закрытым ключом. Есть ли способ определить во время выполнения, что текущий пакет подписан с помощью 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 keytool -list -keystore ~/.android/debug.keystore, но в классе Signature нет метода, похожего на «отпечаток md5». Я хочу сделать это из-за MapView Key, Logging, LicenseChecker и тому подобного.

Ответы [ 2 ]

17 голосов
/ 01 июня 2011

Подпись в 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);
3 голосов
/ 16 июля 2013

Основываясь на ответе 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's signature hash is " + hash + ".");
    tv.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 24);
}

(измените com.stackexchange.marvin на название вашего приложения), скомпилируйте это мини-приложение и отправьте APK всем вовлеченным разработчикам, попросив их запустить его на своем устройстве dev и сообщите мне отображаемый хэш.

...