Visual Studio's AndroidApkSigner does not find key in keystore

跟風遠走 提交于 2020-05-11 10:57:45

问题


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?


回答1:


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.




回答2:


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.



来源:https://stackoverflow.com/questions/51481342/visual-studios-androidapksigner-does-not-find-key-in-keystore

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!