Spring Boot: How to encrypt properties in application.properties

Sometimes you don’t want your properties to stay as plain text in application.properties file. Maybe you are connecting to a database and you have to write your database password in application.properties. In this tutorial, I am going to use Jasypt library for that purpose. Jasypt (Java Simplified Encryption) is a java library which allows the developer to add basic encryption capabilities to his/her projects with minimum effort, and without the need of having deep knowledge on how cryptography works.

Let’s begin,
First, add the related dependency to the project. I am using maven, so I will add the maven dependency to my pom.xml

<!-- https://mvnrepository.com/artifact/com.github.ulisesbocchio/jasypt-spring-boot-starter -->
<dependency>
    <groupId>com.github.ulisesbocchio</groupId>
    <artifactId>jasypt-spring-boot-starter</artifactId>
    <version>2.0.0</version>
</dependency>
In the application.properties (or yaml), we will write our encrypted properties between parenthesis and put ENC keyword before it. Like;

MyProperty=ENC(23ClLWiedLx8v6XT6Wk+Bg==)
How to generate those encrpyted values? We will use Jasypt for that! Go to http://www.jasypt.org/ and download the latest version. When you are done, go into jasypt\bin and use the encrypt.sh or encrypt.bat to encrypt your variables. There are several algorithms to pick but I will leave it as default and only give my property value and secret to encrpyt it.

We only need to add @EnableConfigurationProperties annotation to our application and jasypt will automaticly detect encrypted values and decrypt them before they are being used. The CommandLineRunner I have added below is just to test the decryption mechanism.

@EnableEncryptableProperties
@SpringBootApplication
public class JasyptExampleApplication {

  public static void main(String[] args) {
    SpringApplication.run(JasyptExampleApplication.class, args);
  }
 
  @Component
  public class MyRunner implements CommandLineRunner {
   
    @Value("${myProperty}")
    private String myProperty;

    @Override
    public void run(String... args) throws Exception {
      System.out.println("My property is = " + myProperty);
    }
   
  }
}
But if you run your code like this, you will get the below error:

Error creating bean with name 'demo.JasyptExampleApplication$MyRunner': Injection of autowired dependencies failed; nested exception is java.lang.IllegalStateException: Required Encryption configuration property missing: jasypt.encryptor.password

This is because Jasypt needs to know the secret(password) to decrypt the property. We can tell this to our program several ways:
1- We can give it as a command line argument when running the application;
–jasypt.encryptor.password=MY_SECRET
2- We can set it as an environment variable, this is also useful when you are running your application on Tomcat. You can give it to Tomcat’s setenv.sh file;
export CATALINA_OPTS=”-Djasypt.encryptor.password=MY_SECRET”
You can also unset the environment variable after running the application, so there will be no doorway left behind, at least in a human-readable sense.
3- You can give it in application.properties but this might be the dumbest way as it has no difference with giving the property as plain text.
If you know a better way, write a comment below!

Now let’s look at the final output:

2018-04-25 14:03:26.413 INFO 10028 --- [ main] c.u.j.EncryptablePropertySourceConverter : Converting PropertySource configurationProperties [org.springframework.boot.context.properties.source.ConfigurationPropertySourcesPropertySource] to AOP Proxy
2018-04-25 14:03:26.413 INFO 10028 --- [ main] c.u.j.EncryptablePropertySourceConverter : Converting PropertySource commandLineArgs [org.springframework.core.env.SimpleCommandLinePropertySource] to EncryptableEnumerablePropertySourceWrapper
2018-04-25 14:03:26.414 INFO 10028 --- [ main] c.u.j.EncryptablePropertySourceConverter : Converting PropertySource systemProperties [org.springframework.core.env.MapPropertySource] to EncryptableMapPropertySourceWrapper
2018-04-25 14:03:26.414 INFO 10028 --- [ main] c.u.j.EncryptablePropertySourceConverter : Converting PropertySource systemEnvironment [org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor$OriginAwareSystemEnvironmentPropertySource] to EncryptableMapPropertySourceWrapper
2018-04-25 14:03:26.414 INFO 10028 --- [ main] c.u.j.EncryptablePropertySourceConverter : Converting PropertySource random [org.springframework.boot.env.RandomValuePropertySource] to EncryptablePropertySourceWrapper
2018-04-25 14:03:26.415 INFO 10028 --- [ main] c.u.j.EncryptablePropertySourceConverter : Converting PropertySource applicationConfig: [classpath:/application.properties] [org.springframework.boot.env.OriginTrackedMapPropertySource] to EncryptableMapPropertySourceWrapper
2018-04-25 14:03:26.468 INFO 10028 --- [ main] c.u.j.r.DefaultLazyPropertyResolver : Property Resolver custom Bean not found with name 'encryptablePropertyResolver'. Initializing Default Property Resolver
2018-04-25 14:03:26.470 INFO 10028 --- [ main] c.u.j.d.DefaultLazyPropertyDetector : Property Detector custom Bean not found with name 'encryptablePropertyDetector'. Initializing Default Property Detector
2018-04-25 14:03:26.472 INFO 10028 --- [ main] c.u.j.encryptor.DefaultLazyEncryptor : String Encryptor custom Bean not found with name 'jasyptStringEncryptor'. Initializing Default String Encryptor
2018-04-25 14:03:26.478 INFO 10028 --- [ main] c.u.j.encryptor.DefaultLazyEncryptor : Encryptor config not found for property jasypt.encryptor.algorithm, using default value: PBEWithMD5AndDES
2018-04-25 14:03:26.479 INFO 10028 --- [ main] c.u.j.encryptor.DefaultLazyEncryptor : Encryptor config not found for property jasypt.encryptor.keyObtentionIterations, using default value: 1000
2018-04-25 14:03:26.479 INFO 10028 --- [ main] c.u.j.encryptor.DefaultLazyEncryptor : Encryptor config not found for property jasypt.encryptor.poolSize, using default value: 1
2018-04-25 14:03:26.479 INFO 10028 --- [ main] c.u.j.encryptor.DefaultLazyEncryptor : Encryptor config not found for property jasypt.encryptor.providerName, using default value: null
2018-04-25 14:03:26.479 INFO 10028 --- [ main] c.u.j.encryptor.DefaultLazyEncryptor : Encryptor config not found for property jasypt.encryptor.providerClassName, using default value: null
2018-04-25 14:03:26.479 INFO 10028 --- [ main] c.u.j.encryptor.DefaultLazyEncryptor : Encryptor config not found for property jasypt.encryptor.saltGeneratorClassname, using default value: org.jasypt.salt.RandomSaltGenerator
2018-04-25 14:03:26.480 INFO 10028 --- [ main] c.u.j.encryptor.DefaultLazyEncryptor : Encryptor config not found for property jasypt.encryptor.stringOutputType, using default value: base64
2018-04-25 14:03:26.934 INFO 10028 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2018-04-25 14:03:26.948 INFO 10028 --- [ main] demo.JasyptExampleApplication : Started JasyptExampleApplication in 1.264 seconds (JVM running for 2.06)
My property is MBcoder

As you can see it picked up the PBEWithMD5AndDES algorithm as default value and with the given password, MY_SECRET, it successfully decrypted myProperty
I hope this article was useful, see you another time!

If you liked the content please share it!

You may also like...

9 Responses

  1. Poorna chandra says:

    how can we handle this if i need to maintain 2 encrypted passwords in application.properties file

    • MBcoder says:

      You can store them in different variables. And use in your application. Like;
      Password1=ENC(…)
      Password2=ENC(…)
      But of course secret key for generating those values should be same for both. By secret key, I mean the password field of Jasypt.If you were talking about that password, I think it is not possible to give different secret keys at the same time.

  2. Elijah says:

    If it is not a spring application that runs but is a service that is called how do you get JASypt to automatically detect and convert the values? Mine stay as ENC(…).

    We have a Spring application project as well where it works just fine as you stated above.

    • MBcoder says:

      Hello,
      You can do this without Spring Boot. Jasypt provides java based configuration. I will copy a part from Jasypt.org, hope this is what you are looking for:

      By using an org.jasypt.properties.EncryptableProperties object, an application would be able to correctly read and use a .properties file like this:

      datasource.driver=com.mysql.jdbc.Driver
      datasource.url=jdbc:mysql://localhost/reportsdb
      datasource.username=reportsUser
      datasource.password=ENC(G6N718UuyPE5bHyWKyuLQSm02auQPUtm)
      Note that the database password is encrypted (in fact, any other property could also be encrypted, be it related with database configuration or not).

      How do we read this value? like this:

      /*
      * First, create (or ask some other component for) the adequate encryptor for
      * decrypting the values in our .properties file.
      */
      StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
      encryptor.setPassword(“jasypt”); // could be got from web, env variable…

      /*
      * Create our EncryptableProperties object and load it the usual way.
      */
      Properties props = new EncryptableProperties(encryptor);
      props.load(new FileInputStream(“/path/to/my/configuration.properties”));

      /*
      * To get a non-encrypted value, we just get it with getProperty…
      */
      String datasourceUsername = props.getProperty(“datasource.username”);

      /*
      * …and to get an encrypted value, we do exactly the same. Decryption will
      * be transparently performed behind the scenes.
      */
      String datasourcePassword = props.getProperty(“datasource.password”);

      // From now on, datasourcePassword equals “reports_passwd”…

      For decrypting the encrypted value, we just had to access it with getProperty, just as with any other non-encrypted value.

      EncryptableProperties objects can receive as a constructor argument both an org.jasypt.encryption.StringEncryptor implementation or an org.jasypt.util.TextEncryptor object.

  3. Gerard Jongerhuis says:

    A good place to save your secreet password is the home directory of the user

    Path path = Paths.get(System.getProperty(“user.home”)+”/.mySecret”);
    String secret = new String(Files.readAllBytes(path));
    secret = secret.trim();
    System.setProperty(“jasypt.encryptor.password”, secret);

  4. Prasanth says:

    Is it safe to use third party library in our application: com.github.ulisesbocchio? Do we have any alternate way?

    • MBcoder says:

      I don’t know if there is any other way. I mean of course you can implement your own encryption utility and you can use that on to encrypt and decrypt data. Shouldn’t be that hard.
      About if it is safe to use that 3rd party library. It is an open source project on Github so you can go and check if there is something dangerous in the code. Or you can check how they achieved it and try to implement it yourself to be super safe.

      • Prasanth says:

        ok.. Thanks for the reply.. one more query.. I need to create war file of the application with above configuration. How could I achieve that? I am getting error.
        Required Encryption configuration property missing: jasypt.encryptor.password

        • MBcoder says:

          In the above tutorial it exactly tells you why you get this error. Please read the tutorial again 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.