Visual Studio's AndroidApkSigner does not find key in keystore
Asked Answered
G

4

6

I am getting this error when creating an APK within Visual Studio:

Failed to load signer "signer #1": C:\...\googleplay.keystore entry "googleplay" does not contain a key

I am a longtime ASP.NET developer who is familiar with Visual Studio but this is my first Xamarin project. (I am not using Android Studio.) I am trying to deploy the Android build to Google Play. I have never uploaded an APK to Google Play so I cannot use Visual Studio's automatic deployment; I must perform a manual deployment first per Google's and Microsoft's instructions.

I am running Visual Studio 2017 15.7.5 (latest) with JDK 1.8. My project is using NETStandard.Library 2.0.3, Xamarin.Forms 3.1.0, and Microsoft.EntityFrameworkCore 2.1.1.

This question is similar to this question that has no answers but I am getting the error from within Visual Studio. If this is a duplicate, I apologize but I am unable to add additional details on that question.

I am using Google Play App Signing. I have created a key through Google Play. I downloaded the certificate in .der format. I have used keytool (from c:\Program Files\Java\jdk1.8.0_172\bin) to convert the .der file to .keystore with the following command:

keytool -importcert -alias googleplay -file "C:\...\deployment_cert.der"

I have re-run this utility a few times changing the options thinking perhaps that there might be a problem with case sensitivity on the alias or special characters in the password that keytool prompts for. In this instance, the alias is all alpha, all lowercase, and the password is alpha-numeric all lowercase. keytool asks to trust this certificate and I press "y".

This results in a file named .keystore. I renamed this to googleplay.keystore and I moved it to a more appropriate place.

I can double-check that the googleplay alias is present in the keystore file by running this command:

C:\Program Files\Java\jdk1.8.0_172\bin>keytool -v -list -keystore "C:\...\googleplay.keystore" -alias googleplay
Enter keystore password:
Alias name: googleplay
Creation date: Jul 23, 2018
Entry type: trustedCertEntry

Owner: CN=Android, OU=Android, O=Google Inc., L=Mountain View, ST=California, C=US
Issuer: CN=Android, OU=Android, O=Google Inc., L=Mountain View, ST=California, C=US
Serial number: e8************************************8a
Valid from: Thu Jul 19 14:18:56 EDT 2018 until: Sun Jul 19 14:18:56 EDT 2048
Certificate fingerprints:
         MD5:  0D:**:**:**:**:**:**:**:**:**:**:**:**:**:**:C8
         SHA1: 11:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:CD
         SHA256: D0:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:74
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 4096-bit RSA key
Version: 3

Extensions:

#1: ObjectId: 2.5.29.19 Criticality=false
BasicConstraints:[
  CA:true
  PathLen:2147483647
]

The "googleplay" alias most definitely exists! The certificate fingerprints match the keys that Google gave me (redacted).

In Visual Studio, I set the solution configuration to Release mode, I cleaned my entire solution (successful), rebuilt my entire solution (successful), and then right-clicked my Android project and clicked Archive... per these instructions.

As a side-note, that Microsoft article is extremely frustrating because it does not mention signing or this issue, and their articles on signing do not match how Google Play operates and seem to assume you have a correct APK uploaded to Google Play already (bypassing the chicken-or-egg Catch-22).

At first all I got was The archiving process has failed. Please see the Errors section for more details. The Error List panel is empty. The Output panel just says "java.exe" exited with code 2. I went to Tools -> Options -> Projects and Solutions -> Build and Run and changed MSBuild project build output verbosity from Minimal to Diagnostic and repeated the last few steps (clean, rebuild, archive). Now, the Output panel (slightly redacted) says:

Using "AndroidApkSigner" task from assembly "C:\...\MSBuild\Xamarin\Android\Xamarin.Android.Build.Tasks.dll".
Task "AndroidApkSigner"
AndroidApkSigner:
  ApkSignerJar: C:\Program Files (x86)\Android\android-sdk\build-tools\27.0.3\lib\apksigner.jar
  ApkToSign: bin\Release\com.mycompany.myproject.apk
  ManifestFile: obj\Release\android\AndroidManifest.xml
  AdditionalArguments: 
C:\Program Files\Java\jdk1.8.0_172\\bin\java.exe -jar "C:\Program Files (x86)\Android\android-sdk\build-tools\27.0.3\lib\apksigner.jar" sign --ks "C:\...\googleplay.keystore" --ks-pass pass:******** --ks-key-alias googleplay --key-pass pass:******** --min-sdk-version 19 --max-sdk-version 27  C:\...\myproject.Android\bin\Release\com.mycompany.myproject.apk 
Failed to load signer "signer #1": C:\...\googleplay.keystore entry "googleplay" does not contain a key
"java.exe" exited with code 2.
Done executing task "AndroidApkSigner" -- FAILED.
Done building target "_Sign" in project "myproject.Android.csproj" -- FAILED.
Done building project "myproject.Android.csproj" -- FAILED.
Build FAILED.

From the above output you can see what the (redacted) values are in my project's property's Android Package Signing tab. Through trial and error I discovered that the Keystore Password, Alias, and Alias Password are all required. I set the Keystore Password and Alias Password to be the same, since there is only one password associated with this keystore. As mentioned above, the password is lower-alpha-numeric (no special characters following the advice from another SO question).

Why is AndroidApkSigner failing to find the key in the keystore for the provided alias when keytool finds the key without problem?

And, I can't be the only one with this problem? Deploying from Visual Studio to Google Play should be a fairly common workflow, but I am not finding anybody else (besides this other unanswered SO question) who is experiencing this issue. What am I doing wrong?

Goles answered 23/7, 2018 at 14:33 Comment(5)
since 15.6, signing is broken. I can't even deploy my xamarin app any longer to a physical device for debugging.Colincolinson
How are you generating your app's keystore/key prior to uploading to Google Play? If this is a new app, you shouldn't have to do anything but upload a Release APK. When you opt-in to the app signing program, the key used for the Release APK will become the upload key and Google Play will then generate a new key to sign the APK before it gets to users.Sabelle
@JonDouglas, the first APK I created was not signed. VS created it just fine, but when I uploaded it to Google, it said the APK was not zip-aligned, which led me to zipalign.exe. I uploaded that to Google and then it said the APK needed to be signed, which is congruent with this page that says "app signing by Google Play is required." Which brings me to here. I opted into Google Play App Signing which gives me a certificate (the .der file described in the question). Should I be doing something different?Goles
You should be able to upload a Release APK that was signed with a local keystore. The key in that store will then become the upload key. It will then generate a new upload key resigned with the original key for any future APK updates.Sabelle
Okay, I just created my own .keystore independent from Google Play. keytool -genkeypair -v -keystore mykey.keystore -alias eric -keyalg RSA -keysize 2048 -validity 10000. I updated my project to use this keystore. Clean, rebuild, archive, and I get a similar error as detailed above: Failed to load signer "signer #1", except this time it says on the next line, java.io.IOException: Failed to obtain key with alias "eric" from C:\...\mykey.keystore. Wrong password? As in the question above, I can verify alias "eric" exists and the password is correct.Goles
G
4

I have discovered the answer to my question. The documentation on the Android Developer site will not work with Visual Studio. The ApkSigner that comes with Xamarin does not know what to do with it. Instead, use this to create your own release key:

keytool -v -list -keystore c:\temp\myreleasekey.keystore -alias myalias -storetype pkcs12

Note the -storetype pkcs12 at the end. This command is also modified to (1) write the file somewhere besides Program Files, (2) uses .keystore extension which Visual Studio likes, and (3) avoids special characters in the alias, which Visual Studio does not like, from what I've read. (Avoid special characters in the password, too.)

Note, keytool is located in c:\Program Files\Java\jdk[version]\bin.

The Clue

When I followed the instructions on the documentation, I got a warning from keytool:

Warning: The JKS keystore uses a proprietary format. It is recommended to migrate to PKCS12 which is an industry standard format using keytool -importkeystore -srckeystore c:\temp\myreleasekey.jks -destkeystore c:\temp\myreleasekey.jks -deststoretype pkcs12.

I also got this warning when verifying the key is correct:

keytool -v -list -keystore c:\temp\myreleasekey.jks -alias myalias

If you have an existing key and need to convert it, follow the command in the warning.

Thank you:

I want to thank Nick for explaining the reasoning behind signing and differentiating between all the keys.

And thank you, Jon, for pointing me toward how to create my own private key.

Goles answered 24/7, 2018 at 16:38 Comment(1)
i get the error exception "Alias XX does not exist"Maje
C
3

The important fact you are missing:

Google Play never gives you a key you use to sign things. It only ever gives you certificates to verify with.

I'll start with the basics you probably know. In public key cryptography, there is a private key and a public key. Only the person who signs has the private key. Otherwise anyone could sign. The public key anyone can have. They can use it to check the signature is valid.

The upload_cert.der download only contains the public key. The reason Google Play lets you download it for verification. You can verify offline your signatures match what the Play Store expects. You probably never need to do this.

Why doesn't Google give you the signing key?

Google Play doesn't give you the private key for the upload certificate for 2 reasons.

  1. Google doesn't have the private part of your upload key! You created the private key part of the upload key, when you enrolled in Google Play App signing. You never gave it to Google. All Google has is the public key part.
  2. If Google did give it to you, the key would have no value. The whole point of the upload key is that even if a hacker breaks into you Play Console account they still cannot upload a new version of your app. They would need the upload key as well. The upload key means Google Play knows the app came from you. If they let you download the signing key from your account, then a hacker could just download it too. Then it would be worthless.

How do I get the upload key I need for signing?

So now the question you probably have is "how do I get the public key I need for signing?". The answer is "you create it". When you first upload your APK, that APK was signed with a key (Google insists on it). It was probably stored in your Visual Studio. That key becomes your upload key. Find where you kept it.

What if I lost it?

Now you might be in a place where you don't know where the key is that you originally used. This is the great thing about Google Play App Signing. If you were signing your app yourself and lost the signing key you would be stuck, you'd have to create a new app. But with Google Play App Signing you can contact Play Console support and they can help you. The process is on the help page.

Look at the section entitled "Create a new upload key". Notice step 1 is you create the key. Google still never has it.

Cusped answered 24/7, 2018 at 7:41 Comment(3)
Thank you for the explanation, Nick. I am new to Google Play and so, as you write, I need to create my own key (I haven't lost anything). Your link takes me to this page. This is a little hard to follow because it is for Android Studio, not Visual Studio. Also, as I wrote to Jon Douglas above, I created my own key (see above for details; I followed the keytool instructions from this link) and the ApkSigner still did not like it. What am I doing wrong? How do I do it right?Goles
Well down the page you link to is a section "Build and sign your app from command line" developer.android.com/studio/publish/app-signing That gives instructions for generating a key, and signing the APK on the command line. Does that help?Cusped
"Build and sign your app from command line" is precisely what I followed when writing to Jon above. I have done this. I set Visual Studio to use this key I made. When building the APK, ApkSigner fails to find a key in the keystore.Goles
F
0

Disable the option "sign the .APK file using the following keystore details."

you will get this option

right click on android project select properties goto Android Package Signing.

Example

Faltboat answered 25/1, 2021 at 6:53 Comment(0)
T
0

For me, the issue had something to do with the packaging/signing screen. I ended up removing everything from the signing screen, then building the archive.

Once built, I then clicked on the archive and hit distribute. At this point it asked me for the keystore and the password. I entered them and it signed the apk. I used that one to sideload the app and it worked great.

Tyr answered 19/2, 2021 at 11:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.