Programming languages
Keystore was tampered with, or password was incorrect: fixes
java.io.IOException: Keystore was tampered with, or password was incorrectjava.io.IOException: Keystore was tampered with, or password was incorrect means the integrity check Java computed with your password did not match the value stored in the keystore file. Usually the store password is wrong. Otherwise the file was damaged in transit, most often by Maven resource filtering or a text-mode copy. Real tampering is rare.
What the error means
The integrity check failed: the password differs from the one used to write the file, or the file changed. A JKS file ends with a keyed digest computed over its contents and the store password. When you load the keystore with a non-null password, the JDK recomputes that digest; if it differs, JavaKeyStore throws this exact IOException, with an UnrecoverableKeyException: Password verification failed as the cause. The JDK cannot tell a wrong password from a modified file, which is why the message names both.
You will usually see it wrapped by keytool or a server:
keytool error: java.io.IOException: Keystore was tampered with, or password was incorrect
Caused by: java.security.UnrecoverableKeyException: Password verification failed
Since JDK 9 the default keystore type is PKCS12, and keystore.type.compat=true lets the JKS and PKCS12 types load either format. A PKCS12 file with a wrong password produces a different message, keystore password was incorrect. The fixes below apply to both.
Causes, most common first
A wrong store password is the most common cause.
1. The store password is wrong
A typo, a password from another environment, the default changeit used for a custom store, or a value mangled before it reaches Java: $ expanded by the shell, # treated as a comment in a properties file, or an unquoted YAML value.
- Confirm: test the exact file with the exact password, quoted:
keytool -list -keystore /opt/app/keystore.jks -storepass 'the-password'
If keytool succeeds, the file is fine and the application is receiving a different password or file.
- Fix: correct the value where the application reads it (
server.ssl.key-store-password, Tomcat'scertificateKeystorePassword,javax.net.ssl.trustStorePasswordand so on), and quote it in shells and YAML.
2. The keystore and truststore settings are mixed up
A common mix-up is javax.net.ssl.trustStore pointing at the server keystore, or trustStorePassword=changeit used for a custom truststore created with another password.
- Confirm: print the JVM options the process runs with (
ps -ef | grep javaorjcmd <pid> VM.system_properties | grep javax.net.ssl). - Fix: point each property at the right file with its own password.
3. The file was corrupted on the way
Binary files break when a build or transfer treats them as text. The Maven documentation warns that filtering files with binary content will most likely corrupt them. Git line-ending conversion, FTP in ASCII mode, a Git LFS pointer committed instead of the file, or a Kubernetes Secret that is base64-encoded twice cause the same symptom.
- Confirm: compare checksums of the original and the deployed file, and check the first bytes:
sha256sum keystore.jks /opt/app/keystore.jks
xxd -l 4 /opt/app/keystore.jks # a JKS file starts with feed feed
- Fix: exclude keystores from filtering, mark them binary in Git, and copy them in binary mode:
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<nonFilteredFileExtensions>
<nonFilteredFileExtension>jks</nonFilteredFileExtension>
<nonFilteredFileExtension>p12</nonFilteredFileExtension>
</nonFilteredFileExtensions>
</configuration>
</plugin>
# .gitattributes
*.jks binary
*.p12 binary
4. The application loads a different file than you think
A relative path resolved against another working directory, or a keystore of the same name packaged inside the JAR, can shadow the one you edited. Use absolute paths and log the resolved path at startup.
5. The file was modified
This is rare. If checksums differ and nobody can explain why, treat it as a security incident: rotate the private key and reissue the certificate.
Fix commands by platform
Test the password with keytool -list first; only a file that fails with the correct password needs replacing.
Linux and macOS:
keytool -list -v -keystore /opt/app/keystore.jks -storepass 'the-password' | head -20
keytool -storepasswd -keystore /opt/app/keystore.jks # change password (needs the old one)
keytool -importkeystore -srckeystore keystore.jks -destkeystore keystore.p12 -deststoretype pkcs12
Windows (PowerShell): use single quotes so $ is not expanded:
& "$env:JAVA_HOME\bin\keytool.exe" -list -keystore C:\app\keystore.jks -storepass 'the-password'
JDK truststore: keytool -list -cacerts -storepass changeit lists the default trust store, using the documented initial password.
Spring Boot:
server.ssl.key-store=file:/opt/app/keystore.p12
server.ssl.key-store-type=PKCS12
server.ssl.key-store-password=${KEYSTORE_PASSWORD}
To build a PKCS12 file from PEM files, see the PKCS#12 cookbook or the SSL converter, and confirm the key belongs to the certificate with the key matcher.
Don't disable certificate verification
Never replace an unreadable truststore with a trust-all TrustManager. When the failing file is a truststore, a common shortcut is to drop the truststore settings and install a trust-all TrustManager "until the password is found". That removes server authentication entirely: any certificate is accepted, so credentials and data can be intercepted. Likewise, do not commit the password in plain text to make deployments easier.
Safer alternatives: rebuild the truststore from the CA certificates you need with keytool -importcert, keep passwords in your secret store or environment, and convert to PKCS12 so all tools handle the file the same way.
Verify the fix
keytool -list -keystore /opt/app/keystore.p12 -storepass "$KEYSTORE_PASSWORD" >/dev/null && echo "keystore OK"
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -subject -enddate
keytool must succeed with the same password the application uses, the application must start without the IOException, and for a server keystore, the certificate presented on port 443 must be the one you expect. Check it from the outside with the SSL checker.
FAQ
I forgot the keystore password. Can I recover it?
No supported tool recovers it; the password is what protects the file. For a truststore that holds only public CA certificates, rebuild it by importing the same certificates into a new store. For a keystore with a private key, recreate it from the original key and certificate files, or generate a new key and have the certificate reissued.
What is the default password of cacerts?
The keytool documentation states that the initial password of the cacerts keystore file is changeit, and that administrators should change it. Some distributions and corporate images do change it, so use the value your platform documents.
Why does keytool work but my application fails?
The application is not using the same file or password you tested. Common differences are a relative path resolved from another working directory, an environment variable that is not set in the service, a different keystore inside the packaged JAR, or a password with characters such as $ or # that the shell or a YAML file interpreted.
Is the store password the same as the key password?
Not necessarily. The store password protects the file; each private key entry can have its own key password. A wrong key password gives a different error (UnrecoverableKeyException: Cannot recover key, or Get Key failed). Tomcat and Spring Boot have separate settings for both.