Search code examples
javaspringencryptionencryption-symmetricspring-boot-2

Upgrade Spring Boot 1.x to 2.x (update ENCRYPT KEY VM argument if using {cipher} texts)


If {cipher} encrypted text is being used in your spring-boot application property file.

application.yml or application.properties

my.password='{cipher}68e78a954bfa0297ecc733`

Above is start failing in SpringBoot2 with error message Cannot decrypt: key=my.password

Stack Trace

java.lang.IllegalStateException: Cannot decrypt: key=enterpriseInventoryService.password
    at org.springframework.cloud.bootstrap.encrypt.EnvironmentDecryptApplicationInitializer.decrypt(EnvironmentDecryptApplicationInitializer.java:292)
    at org.springframework.cloud.bootstrap.encrypt.EnvironmentDecryptApplicationInitializer.lambda$decrypt$0(EnvironmentDecryptApplicationInitializer.java:270)
    at java.util.LinkedHashMap.replaceAll(Unknown Source)
    at org.springframework.cloud.bootstrap.encrypt.EnvironmentDecryptApplicationInitializer.decrypt(EnvironmentDecryptApplicationInitializer.java:265)
    at org.springframework.cloud.bootstrap.encrypt.EnvironmentDecryptApplicationInitializer.decrypt(EnvironmentDecryptApplicationInitializer.java:190)
    at org.springframework.cloud.bootstrap.encrypt.EnvironmentDecryptApplicationInitializer.initialize(EnvironmentDecryptApplicationInitializer.java:124)
    at org.springframework.cloud.bootstrap.BootstrapApplicationListener$DelegatingEnvironmentDecryptApplicationInitializer.initialize(BootstrapApplicationListener.java:413)
    at org.springframework.boot.SpringApplication.applyInitializers(SpringApplication.java:623)
.
.
Caused by: java.lang.IllegalStateException: Unable to invoke Cipher due to bad padding
    at org.springframework.security.crypto.encrypt.CipherUtils.doFinal(CipherUtils.java:142)


Solution

  • Spring-boot-1

    Any one of the following VM arguments is valid to provide the secret key so that spring can decrypt '{cipher}f75146b2d391aa6' while loading the properties.

    1. encrypt.key (default key)
    2. encrypt_key
    3. encryptKey
    4. encryptkey
    5. ENCRYPT.KEY
    6. ENCRYPT_KEY
    7. ENCRYPTKEY

    Spring use org.springframework.boot.bind.RelaxedPropertyResolver to resolve above keys to get secret key, but this class has been deprecated and removed in spring-boot-2.

    Code snippet in spring-cloud-context-1.x.jar from class org.springframework.cloud.bootstrap.encrypt.EncryptionBootstrapConfiguration

    Environment environment = context.getEnvironment();
    RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(environment);
    hasProperty(propertyResolver, environment, "encrypt.key");
    
    private boolean hasProperty(RelaxedPropertyResolver propertyResolver, Environment environment, String key) {
            String value = propertyResolver.getProperty(key);
            if (value == null) {
                return false;
            }
            return StringUtils.hasText(environment.resolvePlaceholders(value));
        }
    

    Spring-boot-2

    Only encrypt.key is valid VM argument to pass the secret key.

    Code snippet in spring-cloud-context-2.x.jar from class org.springframework.cloud.bootstrap.encrypt.EncryptionBootstrapConfiguration

    Environment environment = context.getEnvironment();
    hasProperty(environment, "encrypt.key");
    
    private boolean hasProperty(Environment environment, String key) {
                String value = environment.getProperty(key);
                if (value == null) {
                    return false;
                }
                return StringUtils.hasText(environment.resolvePlaceholders(value));
            }