{"id":17160212,"url":"https://github.com/obfusk/apksigtool","last_synced_at":"2025-04-07T05:11:55.635Z","repository":{"id":54364285,"uuid":"399899459","full_name":"obfusk/apksigtool","owner":"obfusk","description":"apksigtool - parse/verify/clean/sign android apk (signing block)","archived":false,"fork":false,"pushed_at":"2024-10-15T21:04:04.000Z","size":2517,"stargazers_count":44,"open_issues_count":49,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-30T21:08:49.088Z","etag":null,"topics":["android","apk","reproducible-builds","signing"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/obfusk.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.AGPLv3","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-08-25T17:14:18.000Z","updated_at":"2025-02-26T02:26:01.000Z","dependencies_parsed_at":"2024-08-09T22:45:16.777Z","dependency_job_id":"92885941-efbc-46a7-9d6e-21a3196e8c8a","html_url":"https://github.com/obfusk/apksigtool","commit_stats":{"total_commits":132,"total_committers":1,"mean_commits":132.0,"dds":0.0,"last_synced_commit":"82b7be08f9f39c584a82b26a620be641a1227428"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/obfusk%2Fapksigtool","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/obfusk%2Fapksigtool/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/obfusk%2Fapksigtool/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/obfusk%2Fapksigtool/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/obfusk","download_url":"https://codeload.github.com/obfusk/apksigtool/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247595335,"owners_count":20963943,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","apk","reproducible-builds","signing"],"created_at":"2024-10-14T22:24:05.131Z","updated_at":"2025-04-07T05:11:55.596Z","avatar_url":"https://github.com/obfusk.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!-- {{{1\n\n    File        : README.md\n    Maintainer  : FC Stegerman \u003cflx@obfusk.net\u003e\n    Date        : 2022-11-08\n\n    Copyright   : Copyright (C) 2022  FC Stegerman\n    Version     : v0.1.0\n    License     : AGPLv3+\n\n}}}1 --\u003e\n\n[![GitHub Release](https://img.shields.io/github/release/obfusk/apksigtool.svg?logo=github)](https://github.com/obfusk/apksigtool/releases)\n[![PyPI Version](https://img.shields.io/pypi/v/apksigtool.svg)](https://pypi.python.org/pypi/apksigtool)\n[![Python Versions](https://img.shields.io/pypi/pyversions/apksigtool.svg)](https://pypi.python.org/pypi/apksigtool)\n[![CI](https://github.com/obfusk/apksigtool/workflows/CI/badge.svg)](https://github.com/obfusk/apksigtool/actions?query=workflow%3ACI)\n[![AGPLv3+](https://img.shields.io/badge/license-AGPLv3+-blue.svg)](https://www.gnu.org/licenses/agpl-3.0.html)\n\n\u003c!-- FIXME\n\u003ca href=\"https://repology.org/project/apksigtool/versions\"\u003e\n  \u003cimg src=\"https://repology.org/badge/vertical-allrepos/apksigtool.svg?header=\"\n    alt=\"Packaging status\" align=\"right\" /\u003e\n\u003c/a\u003e\n\n\u003ca href=\"https://repology.org/project/python:apksigtool/versions\"\u003e\n  \u003cimg src=\"https://repology.org/badge/vertical-allrepos/python:apksigtool.svg?header=\"\n    alt=\"Packaging status\" align=\"right\" /\u003e\n\u003c/a\u003e\n--\u003e\n\n# apksigtool\n\n## parse/verify/clean android apk signing blocks \u0026 apks\n\n`apksigtool` is a tool for parsing [android APK Signing\nBlocks](https://source.android.com/docs/security/features/apksigning/v2#apk-signing-block)\n(either embedded in an APK or extracted as a separate file, e.g. using\n[`apksigcopier`](https://github.com/obfusk/apksigcopier)) and verifying [APK\nsignatures](https://source.android.com/docs/security/features/apksigning).  It\ncan also clean them (i.e. remove everything that's not an APK Signature Scheme\nv2/v3 Block or verity padding block), which can be useful for [reproducible\nbuilds](https://reproducible-builds.org).\n\n**WARNING: verification is considered EXPERIMENTAL and SHOULD NOT BE RELIED ON, please use\n[`apksigner`](https://developer.android.com/studio/command-line/apksigner) instead.**\n\n### Parse\n\nParse tree (some output elided):\n\n```bash\n$ apksigtool parse some.apk\nPAIR ID: 0x7109871a\n  APK SIGNATURE SCHEME v2 BLOCK\n  SIGNER 0\n    SIGNED DATA\n      DIGEST 0\n        SIGNATURE ALGORITHM ID: 0x104 (RSASSA-PKCS1-v1_5 with SHA2-512 digest)\n  [...]\n  VERIFIED (1 signer(s))\nPAIR ID: 0xf05368c0\n  APK SIGNATURE SCHEME v3 BLOCK\n  SIGNER 0\n    SIGNED DATA\n      DIGEST 0\n        SIGNATURE ALGORITHM ID: 0x104 (RSASSA-PKCS1-v1_5 with SHA2-512 digest)\n  [...]\n  VERIFIED (1 signer(s))\nPAIR ID: 0x42726577\n  VERITY PADDING BLOCK\n```\n\nExtracted `APKSigningBlock` instead of APK:\n\n```bash\n$ mkdir meta\n$ apksigcopier extract some.apk meta\n$ apksigtool parse --block meta/APKSigningBlock\n[...]\n```\n\nv1 (JAR) signature (some output elided):\n\n```bash\n$ apksigtool parse-v1 some.apk\nJAR MANIFEST\n  VERSION: 1.0\n  CREATED BY: Android Gradle 7.1.3\n  BUILT BY: Signflinger\nJAR SIGNATURE FILE\n  FILENAME: META-INF/CERT.SF\n  VERSION: 1.0\n  CREATED BY: Android Gradle 7.1.3\n  SHA256 MANIFEST DIGEST: [...]\n  ANDROID APK SIGNED: 2\nJAR SIGNATURE BLOCK FILE\n  FILENAME: META-INF/CERT.RSA\n  CERTIFICATE\n    [...]\n  SIGNATURE\n    VALUE (HEX): [...]\n  HASH ALGORITHM: SHA256\nVERIFIED (1 signature(s))\n```\n\n#### JSON\n\nNB: elided binary values (`digest`, `fingerprint`, `raw_data`, `signature`) are\nrepresented as hex (e.g. `foo` would be represented as `666f6f`).\n\n```bash\n$ apksigtool parse --json some.apk\n```\n\n\u003c!-- {{{1 --\u003e\n\u003cdetails\u003e\n\u003csummary\u003efull JSON output (long, some data elided)\u003c/summary\u003e\n\n```json\n{\n  \"_type\": \"APKSigningBlock\",\n  \"pairs\": [\n    {\n      \"_type\": \"Pair\",\n      \"id\": 1896449818,\n      \"length\": 1437,\n      \"value\": {\n        \"_type\": \"APKSignatureSchemeBlock\",\n        \"signers\": [\n          {\n            \"_type\": \"V2Signer\",\n            \"public_key\": {\n              \"_type\": \"PublicKey\",\n              \"public_key_info\": {\n                \"_type\": \"PublicKeyInfo\",\n                \"algorithm\": \"RSA\",\n                \"bit_size\": 2048,\n                \"fingerprint\": \"[...]\",\n                \"hash_algorithm\": null\n              },\n              \"raw_data\": \"[...]\"\n            },\n            \"signatures\": [\n              {\n                \"_type\": \"Signature\",\n                \"algoritm_id_info\": \"RSASSA-PKCS1-v1_5 with SHA2-256 digest, content digested using SHA2-256 in 1 MB chunks\",\n                \"signature\": \"[...]\",\n                \"signature_algorithm_id\": 259\n              }\n            ],\n            \"signed_data\": {\n              \"_type\": \"V2SignedData\",\n              \"additional_attributes\": [\n                {\n                  \"_type\": \"AdditionalAttribute\",\n                  \"id\": 3203395597,\n                  \"is_proof_of_rotation_struct\": false,\n                  \"is_stripping_protection\": true,\n                  \"value\": \"03000000\"\n                }\n              ],\n              \"certificates\": [\n                {\n                  \"_type\": \"Certificate\",\n                  \"certificate_info\": {\n                    \"_type\": \"CertificateInfo\",\n                    \"fingerprint\": \"[...]\",\n                    \"hash_algorithm\": \"SHA256\",\n                    \"issuer\": \"Common Name: [...], Organizational Unit: [...]\",\n                    \"not_valid_after\": \"2022-10-27 12:34:56+00:00\",\n                    \"not_valid_before\": \"2022-10-26 12:34:56+00:00\",\n                    \"serial_number\": 42,\n                    \"signature_algorithm\": \"RSASSA_PKCS1V15\",\n                    \"subject\": \"Common Name: [...], Organizational Unit: [...]\"\n                  },\n                  \"public_key_info\": {\n                    \"_type\": \"PublicKeyInfo\",\n                    \"algorithm\": \"RSA\",\n                    \"bit_size\": 2048,\n                    \"fingerprint\": \"[...]\",\n                    \"hash_algorithm\": null\n                  },\n                  \"raw_data\": \"[...]\"\n                }\n              ],\n              \"digests\": [\n                {\n                  \"_type\": \"Digest\",\n                  \"algoritm_id_info\": \"RSASSA-PKCS1-v1_5 with SHA2-256 digest, content digested using SHA2-256 in 1 MB chunks\",\n                  \"digest\": \"[...]\",\n                  \"signature_algorithm_id\": 259\n                }\n              ],\n              \"raw_data\": \"[...]\"\n            }\n          }\n        ],\n        \"verification_error\": null,\n        \"verified\": 1,\n        \"version\": 2\n      }\n    },\n    {\n      \"_type\": \"Pair\",\n      \"id\": 4031998144,\n      \"length\": 1437,\n      \"value\": {\n        \"_type\": \"APKSignatureSchemeBlock\",\n        \"signers\": [\n          {\n            \"_type\": \"V3Signer\",\n            \"max_sdk\": 2147483647,\n            \"min_sdk\": 24,\n            [...]\n            \"signed_data\": {\n              [...]\n              \"max_sdk\": 2147483647,\n              \"min_sdk\": 24,\n              [...]\n            }\n          }\n        ],\n        \"verification_error\": null,\n        \"verified\": 1,\n        \"version\": 3\n      }\n    },\n    {\n      \"_type\": \"Pair\",\n      \"id\": 1114793335,\n      \"length\": 1166,\n      \"value\": {\n        \"_type\": \"VerityPaddingBlock\"\n      }\n    }\n  ]\n}\n```\n\n\u003c/details\u003e\n\u003c!-- }}}1 --\u003e\n\nTo extract e.g. pair types or IDs:\n\n```bash\n$ apksigtool parse --json some.apk | jq -r '.pairs[].value._type'\nAPKSignatureSchemeBlock\nAPKSignatureSchemeBlock\nVerityPaddingBlock\n$ apksigtool parse --json some.apk | jq -r '.pairs[].id' | awk '{printf \"0x%x\\n\", $1}'\n0x7109871a\n0xf05368c0\n0x42726577\n```\n\nTo extract e.g. public key info:\n\n```bash\n$ apksigtool parse --json some.apk | jq '.pairs[].value.signers[]?.public_key.public_key_info'\n```\n\n```json\n{\n  \"_type\": \"PublicKeyInfo\",\n  \"algorithm\": \"RSA\",\n  \"bit_size\": 2048,\n  \"fingerprint\": \"[...]\",\n  \"hash_algorithm\": null\n}\n[...]\n```\n\nTo extract e.g. certificate info:\n\n```bash\n$ apksigtool parse --json some.apk | jq '.pairs[].value.signers[]?.signed_data.certificates[].certificate_info'\n```\n\n```json\n{\n  \"_type\": \"CertificateInfo\",\n  \"fingerprint\": \"[...]\",\n  \"hash_algorithm\": \"SHA256\",\n  \"issuer\": \"Common Name: [...], Organizational Unit: [...]\",\n  \"not_valid_after\": \"2022-10-27 12:34:56+00:00\",\n  \"not_valid_before\": \"2022-10-26 12:34:56+00:00\",\n  \"serial_number\": 42,\n  \"signature_algorithm\": \"RSASSA_PKCS1V15\",\n  \"subject\": \"Common Name: [...], Organizational Unit: [...]\"\n}\n[...]\n```\n\nv1 (JAR) signature:\n\n```bash\n$ apksigtool parse-v1 --json some.apk | jq -r .manifest.created_by\nAndroid Gradle 7.1.3\n```\n\n### Verify\n\n**WARNING: verification is considered EXPERIMENTAL and SHOULD NOT BE RELIED ON, please use\n[`apksigner`](https://developer.android.com/studio/command-line/apksigner) instead.**\n\n```bash\n$ apksigtool verify some.apk\nWARNING: verification is considered EXPERIMENTAL, please use apksigner instead.\nv2 verified (1 signer(s))\nv3 verified (1 signer(s))\n```\n\n```bash\n$ apksigtool verify-v1 some.apk\nWARNING: verification is considered EXPERIMENTAL, please use apksigner instead.\nv1 verified (1 signature(s))\nWarning: rollback protections require v2, v3 signature(s) as well.\n```\n\n### Clean\n\nNB: modifies in place!\n\n```bash\n$ cp some.apk cleaned.apk\n$ apksigtool clean cleaned.apk\ncleaned\n$ apksigtool clean cleaned.apk\nnothing to clean\n```\n\nUse `--check` to get errors when parsing or verification (when not\nusing `--block`) fails:\n\n``` bash\n$ cp some.apk cleaned.apk\n$ apksigtool clean --check cleaned.apk\n[...]\n```\n\nExtracted `APKSigningBlock` instead of APK:\n\n```bash\n$ mkdir meta\n$ apksigcopier extract some.apk meta\n$ apksigtool clean --block meta/APKSigningBlock\ncleaned\n```\n\n### Help\n\n```bash\n$ apksigtool --help\n$ apksigtool parse --help       # verify --help, clean --help, etc.\n```\n\n\u003c!--\n$ man apksigtool                # requires the man page to be installed\n--\u003e\n\n## Python API\n\n### APK Signing Block\n\n```python\n\u003e\u003e\u003e import apksigtool\n\u003e\u003e\u003e _, data = apksigtool.extract_v2_sig(apk)\n\u003e\u003e\u003e blk = apksigtool.APKSigningBlock.parse(data)    # parse APK Signing Block\n\u003e\u003e\u003e blk = apksigtool.parse_apk_signing_block(data)  # same as above\n\n\u003e\u003e\u003e apksigtool.show_parse_tree(blk)                 # print parse tree\n\u003e\u003e\u003e apksigtool.show_json(blk)                       # JSON\n\n\u003e\u003e\u003e blk.verify(apk)                                 # [EXPERIMENTAL] raises on failure\n\u003e\u003e\u003e result = verified, failed = blk.verify_results(apk)\n\u003e\u003e\u003e result = apksigtool.verify_apk(apk)             # uses .verify_results()\n```\n\n### Cleaning\n\n```python\n\u003e\u003e\u003e import apksigtool\n\u003e\u003e\u003e _, data = apksigtool.extract_v2_sig(apk)\n\u003e\u003e\u003e data_cleaned = apksigtool.clean_apk_signing_block(data)\n\n\u003e\u003e\u003e apksigtool.clean_apk(some_apk)                  # NB: modifies existing APK!\n```\n\n### v1 (JAR) signatures\n\n```python\n\u003e\u003e\u003e import apksigcopier, apksigtool\n\u003e\u003e\u003e meta = tuple(apksigcopier.extract_meta(apk))\n\u003e\u003e\u003e sig = apksigtool.JARSignature.parse(meta)       # parse v1 signature\n\u003e\u003e\u003e sig = apksigtool.parse_apk_v1_signature(meta)   # same as above\n\n\u003e\u003e\u003e apksigtool.show_v1_signature(sig)               # print parse tree\n\u003e\u003e\u003e apksigtool.show_json(sig)                       # JSON\n\n\u003e\u003e\u003e result = sig.verify(apk)                        # [EXPERIMENTAL] raises on failure\n```\n\n\u003c!--\n## FAQ\n\n... FIXME ...\n--\u003e\n\n## Tab Completion\n\nNB: the syntax for the environment variable changed in click \u003e= 8.0,\nuse e.g. `source_bash` instead of `bash_source` for older versions.\n\nFor Bash, add this to `~/.bashrc`:\n\n```bash\neval \"$(_APKSIGTOOL_COMPLETE=bash_source apksigtool)\"\n```\n\nFor Zsh, add this to `~/.zshrc`:\n\n```zsh\neval \"$(_APKSIGTOOL_COMPLETE=zsh_source apksigtool)\"\n```\n\nFor Fish, add this to `~/.config/fish/completions/apksigtool.fish`:\n\n```fish\neval (env _APKSIGTOOL_COMPLETE=fish_source apksigtool)\n```\n\n## Installing\n\n\u003c!-- FIXME\n### Using pip\n\n```bash\n$ pip install apksigtool\n```\n\nNB: depending on your system you may need to use e.g. `pip3 --user`\ninstead of just `pip`.\n--\u003e\n\n### From git\n\nNB: this installs the latest development version, not the latest\nrelease.\n\n```bash\n$ git clone https://github.com/obfusk/apksigtool.git\n$ cd apksigtool\n$ pip install -e .\n```\n\nNB: you may need to add e.g. `~/.local/bin` to your `$PATH` in order\nto run `apksigtool`.\n\nTo update to the latest development version:\n\n```bash\n$ cd apksigtool\n$ git pull --rebase\n```\n\n## Dependencies\n\n* Python \u003e= 3.8 + [apksigcopier](https://github.com/obfusk/apksigcopier) +\n  asn1crypto + click + cryptography + pyasn1 + pyasn1-modules + simplejson.\n\n### Debian/Ubuntu\n\n```bash\n$ apt install apksigcopier python3-{asn1crypto,click,cryptography,pyasn1{,-modules},simplejson}\n```\n\n## License\n\n[![AGPLv3+](https://www.gnu.org/graphics/agplv3-155x51.png)](https://www.gnu.org/licenses/agpl-3.0.html)\n\n\u003c!-- vim: set tw=70 sw=2 sts=2 et fdm=marker : --\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fobfusk%2Fapksigtool","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fobfusk%2Fapksigtool","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fobfusk%2Fapksigtool/lists"}