Android compare signature of current package with debug.keystore

前端 未结 2 951
無奈伤痛
無奈伤痛 2020-12-04 18:53

As all we do I have application which is signed by debug.keystore (by default) when it is in development mode (build). When it goes production we sign it with our private ke

相关标签:
2条回答
  • 2020-12-04 19:13

    Based on Jcs' answer, we use this to find out at runtime who built the running package:

    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;
    }
    

    For any involved certificate, you then just have to find the hash once and add it to the list.

    The simplest way to "find the hash once" may be to just add a popup toast before the switch statement that displays modulusHash, compile your app, run it, write down the hash, remove the toast code and add the hash to the list.

    Alternatively, when I implemented this, I created a little boilerplate app with a single activity and a single TextView with the ID tv in the main layout, put this into the activity:

    @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);
    }
    

    (change com.stackexchange.marvin to your app's name), compiled this mini-app, and sent the APK to all involved developers, asking them to run it on their dev device and let me know the displayed hash.

    0 讨论(0)
  • 2020-12-04 19:19

    The signature in PackageInfo does not seem to be well named since tha field does not contain the package signature but the signer X509 certificate chain. Note that (most of the time) this chain seems to be limited to one single self-signed certificate.

    According to the Android developer page Signing Your Applications the debug signature certificate is generated with this DN: CN=Android Debug,O=Android,C=US

    Therefore it is easy to test if the application has been signed in debug mode:

    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);
    
    0 讨论(0)
提交回复
热议问题