Password from keystore password prompt is not used, placeholder "__unset" used as actual keystore password
Bug Report
Problem
What is expected to happen?
If we don't specify "storePassword" or "password" in build.json, then cordova build android --release will prompt for the password. That password should be used to access the keystore.
What does actually happen?
We get an error, even if the password was typed correctly:
> com.android.ide.common.signing.KeytoolException: Failed to read key my_key from store "my.keystore": Keystore was tampered with, or password was incorrect
If I change both the store and the key password to __unset (which is used in app/build.gradle as a temporary placeholder), then the signing step completes successfully, regardless of which password I entered in the prompt. So it seems that the password from the prompt does not successfully replace this placeholder.
Information
Command or Code
$ cordova create my_app
$ cd my_app
$ cordova platform add android
$ echo '{"android": {"release": {"keystore": "my.keystore", "alias": "my_key"}}}' > build.json
$ keytool -genkey -keystore my.keystore -alias my_key -v -keyalg RSA -keysize 2048 -validity 10000 -keypass testtest -storepass testtest
# Press Enter until "[no]" appears, then type "[yes]"
$ cordova build android --release
# Enter "testtest" at both password prompts
...
Execution failed for task ':app:packageRelease'.
> com.android.ide.common.signing.KeytoolException: Failed to read key my_key from store "/tmp/repro/my_app/my.keystore": Keystore was tampered with, or password was incorrect
But if the passwords happen to be __unset, it's better:
$ rm my.keystore
$ keytool -genkey -keystore my.keystore -alias my_key -v -keyalg RSA -keysize 2048 -validity 10000 -keypass __unset -storepass __unset
# Press Enter until "[no]" appears, then type "[yes]"
$ cordova build android --release
...
BUILD SUCCESSFUL in 7s
43 actionable tasks: 2 executed, 41 up-to-date
Built the following apk(s):
/.../my_app/platforms/android/app/build/outputs/apk/release/app-release.apk
Environment, Platform, Device
Arch Linux on x86_64
Version information
- Cordova CLI 9.0.0
- Cordova lib 9.0.1
- Cordova Android 8.0.0
- Android SDK build tools 29.0.0
Checklist
- [x] I searched for existing GitHub issues
- [x] I updated all Cordova tooling to most recent version
- [x] I included all the necessary information above
I seem to have the same problem with my own app:
- Cordova CLI 8.1.2
- Cordova lib 8.1.1
- Cordova Android 8.0.0
- Android SDK build tools 29.0.0
Cannot build a release version, passwords entered seem to be ignored, getting error Keystore was tampered with, or password was incorrect
When creating a new app (following the code above) using these software versions I get the same error. When I remove platform android 8.0.0 and add platform android version 7.1.1 building succeeds.
@robvandijk Can you confirm that using __unset as input works for you as well?
That works for me as well. But this is likely due to the contents of the file signing-config.json at location platforms/android/app/intermediates/signing_config/release/out which always has contents
"mStorePassword":"__unset","mKeyPassword":"__unset"
I expect that the passwords provided by the user should end up in there, but they don't. Since these values always contain '__unset' this explains the behaviour you see.
Yes, but we don't understand yet why that is happening unfortunately. We'll have to look deeper into that.
I took a quick look at the Gradle source but I'm afraid I'm out of my depth here... As a workaround, just to be able to build a release version I made the following changes locally to platforms/android/app/build.gradle:
Add the following definition at the top of the file:
ext {
inputStorePassword = '__unset'
inputKeyPassword = '__unset'
}
Add the following method (key password and store password are assumed to be the same here):
def promptForReleaseKeyPasswordHack() {
if ('__unset'.equals(inputStorePassword)) {
inputStorePassword = privateHelpers.promptForPassword('Enter key store and key password: ')
inputKeyPassword = inputStorePassword
}
}
Add the following code to the start of the "android {" block so that you're only prompted for the password for release builds:
if (project.gradle.startParameter.taskNames.any { it.toLowerCase().contains('release') }) {
promptForReleaseKeyPasswordHack()
}
Use the variables inputStorePassword and inputKeyPassword instead of the hardcoded '__unset' in the definition of signingConfigs.
Restart Gradle and remove the platforms/android/app/build directory (required, because once generated the signing-config.json file does not get overwritten).
After these hacks at least I'm able to build again for now.