apkの署名を確認しようとしてハマる

2021/02/07

複数のkeystoreファイルを使い分ける局面で、意図したものでちゃんと署名できているか確認しようとしてハマったので備忘を。

keytool じゃなくて apksigner を使おう

ググってパッと目についたので keytool コマンドを使ってみたんです。

F:\>keytool -printcert -jarfile app-dev-debug.apk
署名付きJARファイルではありません

F:\>

しばしここで悩んだんですが、apksigner を使うのが正解でした。

F:\>apksigner verify --print-certs -v app-dev-debug.apk
Verifies
Verified using v1 scheme (JAR signing): false
Verified using v2 scheme (APK Signature Scheme v2): true
Verified using v3 scheme (APK Signature Scheme v3): false
Number of signers: 1
Signer #1 certificate DN: C=US, O=Android, CN=Android Debug
Signer #1 certificate SHA-256 digest: 6797a8b56ab97666651c9ded96bdd068aad0d16519881732795df6fe8d8aa6c8
Signer #1 certificate SHA-1 digest: a01ca56c81987fdd462d1f62c1ea813265cc0e54
Signer #1 certificate MD5 digest: 4bf4a7d97c5033a0cea52ae81b7f803e
Signer #1 key algorithm: RSA
Signer #1 key size (bits): 2048
Signer #1 public key SHA-256 digest: 4340ed370f0086b2c7ac5ed8c433ebac031ae72074a24216948794316a785d5d
Signer #1 public key SHA-1 digest: dfb2fac7e33e2bb57519c3ea4f7c3624a3d82bcd
Signer #1 public key MD5 digest: 446e846deacf05fa86d2e8a17173532e
F:\>

apkの署名にはいくつかバージョンがあります。

アプリへの署名  |  Android オープンソース プロジェクト  |  Android Open Source Project より引用。

Android では、次の 3 つのアプリ署名方式がサポートされています。

  • v1 スキーム: JAR 署名に基づく
  • v2 スキーム: Android 7.0 で導入された APK 署名スキーム v2。
  • v3 スキーム: Android 9 で導入された APK 署名スキーム v3。

# ここには記載がありませんが、Android 11でv4スキームが追加されたっぽい……

apksigner の結果を見れば分かるように、今回のapkはv2で署名されています。

keytool コマンドはJDK付属のツールで、検証できるのはJAR署名(=v1スキーム)だけ。 v2スキームで署名されていたので検証できなかった、というわけです。

署名のバージョンはどうやって決まる?

上記サイトの記述内容をもとにざっくりまとめると

  • build.gradlesigningConfigsv1SigningEnabledv2SigningEnabled を使って明示的に設定できる
  • 明示しない場合は minSdkVersion をもとに自動判定される

ということのようです。

今回試したapkは特に明示しておらず、minSdkVersionは24でした。この場合は

  • v2 schemeはAPI Level24からの対応
  • minSdkVersionが24ということはすべての端末でv2に対応できる
  • v2だけ署名されていれば支障ないので、v1署名はしない

と判断され、v2署名だけになるようです。なるほど。

Javaのバージョンにも注意

これでOKと思ったらもうひとつハマりポイントが。

apksigner は SDK Build Tools に含まれています。せっかくなので最新版を、と思って使ってみたらエラーになりました。

F:\>D:\Android\sdk\build-tools\30.0.0\apksigner.bat verify --print-certs -v app-dev-debug.apk
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.UnsupportedClassVersionError: com/android/apksigner/ApkSignerTool has been compiled by a more recent version of the Java Runtime (class file version 53.0), this version of the Java Runtime only recognizes class file versions up to 52.0
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:756)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
        at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
        at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:495)
F:\>

Javaバージョンメモ(Hishidama’s Java version Memo) の表を見ると class file version 53.0 はJava9, 52.0 はJava1.8を指していることが分かります。

「ApkSignerToolはJava9でコンパイルされてるけど、Javaの実行環境はJava8までしか認識できないよ」というエラーですね。

f:\>java -version
openjdk version "1.8.0_252"
OpenJDK Runtime Environment Corretto-8.252.09.2 (build 1.8.0_252-b09)
OpenJDK 64-Bit Server VM Corretto-8.252.09.2 (build 25.252-b09, mixed mode)

f:\>

なので、JDKのバージョンアップ、という手もあるのですが、そうするとほかのところで不都合があるのですよね…

自分の場合はちょっと古い SDK Build Tools を使うのが手っ取り早い解決策でした。

F:\>D:\Android\sdk\build-tools\29.0.2\apksigner.bat verify --print-certs -v app-dev-debug.apk
Verifies
Verified using v1 scheme (JAR signing): false
Verified using v2 scheme (APK Signature Scheme v2): true
Verified using v3 scheme (APK Signature Scheme v3): false
Number of signers: 1
Signer #1 certificate DN: C=US, O=Android, CN=Android Debug
Signer #1 certificate SHA-256 digest: 6797a8b56ab97666651c9ded96bdd068aad0d16519881732795df6fe8d8aa6c8
Signer #1 certificate SHA-1 digest: a01ca56c81987fdd462d1f62c1ea813265cc0e54
Signer #1 certificate MD5 digest: 4bf4a7d97c5033a0cea52ae81b7f803e
Signer #1 key algorithm: RSA
Signer #1 key size (bits): 2048
Signer #1 public key SHA-256 digest: 4340ed370f0086b2c7ac5ed8c433ebac031ae72074a24216948794316a785d5d
Signer #1 public key SHA-1 digest: dfb2fac7e33e2bb57519c3ea4f7c3624a3d82bcd
Signer #1 public key MD5 digest: 446e846deacf05fa86d2e8a17173532e
F:\>

ということで無事解決。署名をサクッと確認したかっただけなのに、あれこれハマって大変だった、というおはなしでした。




関連(するかもしれない)記事


おススメ