diff --git a/README.md b/README.md index 28ad403..98358b4 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # ApkGolf -This repository hosts the smallest Android APK in the world. The current size of the APK is *678 bytes*. +This repository hosts the smallest Android APK in the world. The current size of the APK is *677 bytes*. To learn more about how this was achieved, please read the [blog post](https://fractalwrench.co.uk/posts/playing-apk-golf-how-low-can-an-android-app-go/). @@ -34,8 +34,8 @@ Further byte-level optimisation of what remains of the manifest. Contributed by [Madis Pink](https://github.com/madisp) in this [Pull Request](https://github.com/fractalwrench/ApkGolf/pull/6) -## Minimising APK Signing Certificate (678 bytes, 18% reduction) -Manual removal of unnecessary fields present in the certificate used to sign the APK. +## Minimising APK Signing Certificate (677 bytes, 18% reduction) +Remove unnecessary fields present in the certificate used to sign the APK. Contributed by [klyubin](https://github.com/klyubin) in this [Pull Request](https://github.com/fractalwrench/ApkGolf/pull/15) - +Automated by [Adam Yi](https://github.com/adamyi) diff --git a/build.sh b/build.sh index 5da6b8a..980a193 100755 --- a/build.sh +++ b/build.sh @@ -1,7 +1,5 @@ #!/usr/bin/env bash -set -e - rm -rf build mkdir -p build/apk @@ -18,6 +16,41 @@ recompress() { set -x +echo "Compiling certificate generation program" + +success=0 + +gcc -o build/generate_cert generate_cert.c -lssl -lcrypto -ldl + +if [ $? -eq 0 ]; then + echo "Generating cert" + cd build + ./generate_cert + if [ $? -eq 0 ]; then + cd .. + openssl x509 -in build/cert.pem -noout -text + if [ $? -eq 0 ]; then + openssl pkcs8 -topk8 -in build/key.pem -out build/key.pk8 -outform DER -nocrypt + if [ $? -eq 0 ]; then + echo "Success" + success=1 + fi + fi + else + cd .. + fi +fi + +if [ $success -eq 0 ]; then + echo "Failed to generate cert. Using pre-generated cert." + rm build/cert.pem + rm build/key.pk8 + cp cert.pem build/ + cp key.pk8 build/ +fi + +set -e + echo "Creating base apk" cp app/AndroidManifest.xml build/apk/ @@ -27,7 +60,7 @@ zip -j -r build/app-unsigned.apk build/apk recompress build/app-unsigned.apk echo "Signing archive" -$ANDROID_HOME/build-tools/26.0.2/apksigner sign --v1-signing-enabled false --key key.pk8 --cert key.x509.pem --in build/app-unsigned.apk --out build/signed-release.apk --min-sdk-version 24 +$ANDROID_HOME/build-tools/26.0.2/apksigner sign --v1-signing-enabled false --key build/key.pk8 --cert build/cert.pem --in build/app-unsigned.apk --out build/signed-release.apk --min-sdk-version 24 set +x diff --git a/cert.pem b/cert.pem new file mode 100644 index 0000000..d98f3db --- /dev/null +++ b/cert.pem @@ -0,0 +1,6 @@ +-----BEGIN CERTIFICATE----- +MIGgMIGVAgEBMAMGAQAwCTEHMAUGAQATADAaFwswMDAxMDEwMDAwWhcLMDAwMTAx +MDAwMFowCTEHMAUGAQATADBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABOYMo2Ld +mbwCoefiz7NRQ+du9obnpJNhRK11XPZHhk6jSRdFiOkqMhko2YI/XWlq6BkC3OPS +r3QkiEeT3i+EXj8wAwYBAAMBAA== +-----END CERTIFICATE----- diff --git a/generate_cert.c b/generate_cert.c new file mode 100644 index 0000000..c67440d --- /dev/null +++ b/generate_cert.c @@ -0,0 +1,91 @@ +// Generate minimal ECC cert +// Required OpenSSL version < 1.0.1i +// author: Adam Yi + +#include + +#include +#include +#include + +EVP_PKEY * generate_key_ecc() +{ + BIO *outbio = NULL; + + int eccgrp = OBJ_txt2nid("prime256v1"); + EC_KEY *myecc = EC_KEY_new_by_curve_name(eccgrp); + + //EC_KEY_set_asn1_flag(myecc, OPENSSL_EC_NAMED_CURVE); + EC_KEY_set_asn1_flag(myecc, 1); + + if (! (EC_KEY_generate_key(myecc))) + BIO_printf(outbio, "Error generating the ECC key."); + + EVP_PKEY *pkey = EVP_PKEY_new(); + if (!EVP_PKEY_assign_EC_KEY(pkey, myecc)) + BIO_printf(outbio, "Error assigning ECC key to EVP_PKEY structure."); + + return pkey; +} + +X509 * generate_x509(EVP_PKEY * pkey) +{ + X509 * x509 = X509_new(); + + ASN1_INTEGER_set(X509_get_serialNumber(x509), 1); + + ASN1_TIME_set_string(X509_get_notBefore(x509), "0001010000Z"); + ASN1_TIME_set_string(X509_get_notAfter(x509), "0001010000Z"); + + X509_set_pubkey(x509, pkey); + + // X509v1 cannot have empty issuer & subject DN + X509_NAME * name = X509_get_subject_name(x509); + + X509_NAME_add_entry_by_NID(name, 0, V_ASN1_APP_CHOOSE, "", 0, 0, 0); + + X509_set_issuer_name(x509, name); + + return x509; +} + +void write_to_disk(EVP_PKEY * pkey, X509 * x509) +{ + FILE * pkey_file = fopen("key.pem", "wb"); + + PEM_write_PKCS8PrivateKey(pkey_file, pkey, NULL, NULL, 0, NULL, NULL); + fclose(pkey_file); + + FILE * x509_file = fopen("cert.pem", "wb"); + + PEM_write_X509(x509_file, x509); + fclose(x509_file); + + return; +} + +int main(int argc, char ** argv) +{ + printf("Generating ECC key...\n"); + + EVP_PKEY * pkey = generate_key_ecc(); + if(!pkey) + return 1; + + printf("Generating X509 cert...\n"); + + X509 * x509 = generate_x509(pkey); + if(!x509) + { + EVP_PKEY_free(pkey); + return 1; + } + + printf("Writting files....\n"); + + write_to_disk(pkey, x509); + EVP_PKEY_free(pkey); + X509_free(x509); + + printf("Done!\n"); +} diff --git a/key.pk8 b/key.pk8 index 7a959ac..8c0356c 100644 Binary files a/key.pk8 and b/key.pk8 differ diff --git a/key.x509.pem b/key.x509.pem deleted file mode 100644 index 3c6b53c..0000000 --- a/key.x509.pem +++ /dev/null @@ -1,6 +0,0 @@ ------BEGIN CERTIFICATE----- -MIGgMIGVAgEBMAMGAQEwCTEHMAUGAQETADAaFwsxNzEwMTAyMjUwWhcLMTcxMDEw -MjI1MFowCTEHMAUGAQETADBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLAoWrpy -dzdU6PN096BcSaDRFuC+/8MjLhgeFUiogqlrZFocHudWRHJALK08ge+x0n3nwCVB -wJ4Ybfhm0sf9nowwAwYBAQMBAA== ------END CERTIFICATE----- diff --git a/signed-release.apk b/signed-release.apk index 001279d..af51ce2 100644 Binary files a/signed-release.apk and b/signed-release.apk differ