From 5cbf474d7eab5a05b3bce519ad9125a591fcd46e Mon Sep 17 00:00:00 2001 From: Adam Yi Date: Fri, 13 Oct 2017 23:24:07 +0800 Subject: [PATCH] Generate minimal ecc certificate on the fly --- README.md | 8 ++-- build.sh | 39 +++++++++++++++++-- cert.pem | 6 +++ generate_cert.c | 91 +++++++++++++++++++++++++++++++++++++++++++++ key.pk8 | Bin 67 -> 138 bytes key.x509.pem | 6 --- signed-release.apk | Bin 678 -> 677 bytes 7 files changed, 137 insertions(+), 13 deletions(-) create mode 100644 cert.pem create mode 100644 generate_cert.c delete mode 100644 key.x509.pem 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 7a959acbdfb509b58e29087d40579339be50293d..8c0356c6503cc168f496fcc8b6797cbfbc3bc67b 100644 GIT binary patch literal 138 zcmV;50CoQ`frkPC05B5<2P%e0&OHJF1_&yKNX|V20S5$aFlzz<0R$ky-r$7?iG$@M zGvW-P^74BX#(^b literal 67 zcmXqTWMX765N2c7YV$Z}%f!gW0cJ2Wva_fgs4_7!vM8)KyKNw<6R~*jpS6>1wr=6~ VpTohlqUXN>P4hif>|GW?E`-iC#r+PU^v} z3!MxZ7!G)UvVUjCU}~zm_`y2^p36#qcYAZiaj>a*Ff=MI=+Wb9z5HfR^m;k}pMOfX zS)4J`*3@<5PRfut{pt_ff#>Q9iyXQ<7A7jZ=03s*vWMW`Y0Md`_OE&)49q0b@*4Hn~-H*?E|973UdhbJC^LZS16x*^NF9)hw48#VF z3k({kGBGk5Ftaf-7;qZ08?XWy!VCsd;@k!X28KWg1W_m)WMz>C!ffnXZ64=rnHbqP zzzk+ac4j9AmS;SRlkU#k!?f`Eqw|{souB7@YkR(Aa-z%H(wJ}VZGMYA#a%mIY8gpt z+-$Os&CGfs$#m!OrS&B$9qyCw>9@q$gI&Z7@ox~&seV8V@}3*W*)B{9W!uYE?=?JR zyrXZu@qgiBW(zBa<96?(_t76&NgO1W{O0 VSAaJw8%T-~2pxg6A23uH7yy(6)p!5^ literal 678 zcmWIWW@Zs#U}E54$jJ8gz8avD9mK%EFawB%f!HxGr6@l$#Wyi8GcC2aM6V(@C-tBq z*C7W1h66WmE3untihN?o&i3A4BopW&;wb+(-}l#Ke?VN>kfb1DSd><&T z1H>9Y%*e#Rpa7&((q?bi=DHxG^`MGP$?r-5nfO;K4~;uoRCca>&&Ekp{wS>{@Le=WLl6 z**L%qW=3{qCkB=c8d1B7%FRPwd@lLEAjWgSMX?9_{vTG>laLejSkbgHJ0(g+?s=F? zk%P`!o5uGWFV#Ljpz3&Fo<#1Cv`feT&g%iYh#BHvPG_zt%3-R8U;IM&ZefjfIhcxm_U##G-yNDOl-D`KS8xE%w(vQH-%a z_XPJA+u&Wk$5?JegG{2G2VimL7~riCoSClRl#`#Ftzcpl;LXS+$Ba8c0bK