How to encrypt properties with Jasypt
Today we are going to see an interesting tool that will allow us to encrypt our properties. It is common bad practice to upload passwords to be used in our java application to the code repositories. To avoid this, we can use Jasypt, which as we will see is easy to use and, gives us multiple ways of configuration and encryption.
Throughout the post, we will focus on how to use it based on its possible use as a property encryption utility. Mainly because the property file is the place where we usually store sensitive information. But before we see an example of how to implement, we will also see what are the possible options that Jasypt provides us.
To begin with and whenever we talk about String encryption, we will have four possible options:
- BasicPasswordEncryptor: It allows us to make simple and basic code encryption.
- StrongPasswordEncryptor: It allows us to make more complex encryption but also more expensive in terms of CPU consumption.
- StandardPBEStringEncryptor: This allows us to make bidirectional encryption, in which we can indicate different values: the algorithm to use, the IvGenerator, and most importantly the master key to encrypt and decrypt.
- PooledPBEStringEncryptor: Very similar to the previous one, only that it also creates a pool of StandardPBEStringEncryptor and therefore improves the performance when using it. Very useful if we are going to use it a lot.
Its use is really basic, as we can see it later. But maybe we need to clarify a couple of concepts first. Especially regarding the StandardPBEStringEncryptor that allows further configuration than the others.
- Master key
On the one hand, we have to indicate which is the key on which we will start to perform this encryption/decryption. This can be any, as long as it complies with minimum security requirements in terms of the type of characters and length. But here, the most important thing can be how we must store this password. Because we are facing the same problem of having to put a key in a property file. For this, the best solution, following the 12 factor methodology, is to store that key in an environment variable. If we use Linux we can create such a variable in the /etc/environment file (but be careful, we need to reboot the system to take it into account). And then easily obtain it in our Java code.
private String PBES_PWD = System.getenv("JASYPT_PWD");
- Encryption algorithm
This is an optional value, but it will allow us to select the encryption algorithm with which we feel more comfortable. This algorithm will depend on our JVM. And if we are not sure which one to use or which ones we have available to use. We can run the following Java code that will indicate those possible values.
- IvGenerator
The algorithms of type PBEWithDigestAndAES that are supported by Java Cryptography Extension aka JCE, need an initialization vector aka IV. This must also be random and used only once. For this purpose, Jasypt provides the RandomIvGenerator class.
Next, we will see a small piece of code that includes the different configurations, so that you can see how simple they are to use. Note that the StandardPBEStringEncryptor and PooledPBEStringEncryptor classes have a default configuration, so it is not necessary to include all the parameters, but at least it is necessary to include the master key.
And if we compare the times, we will have the following output:
BasicPasswordEncryptor: 3 ms
StrongPasswordEncryptor: 99 ms
StandardPBEStringEncryptor: 7ms
PooledPBEStringEncryptor without configuration: 3ms
PooledPBEStringEncryptor with configuration: 8ms
Now that we know the basic use, we are going to apply it to a properties file that we have in our application. To be able to make use of it, we will only have to carry out these steps:
- Create an object of StringEncryptor type as we have seen previously.
- Create an object of type Properties with the help of the EncryptableProperties class. To this class, we must pass the StringEncryptor object created in the previous point.
- Store the encapsulated encrypted properties between ENC( ).
Example of utility class:
Example of a property file where the user is not encrypted and the password is encrypted:
datasource.usr=root
datasource.pwd=ENC(xwg7loJbeovRKn4R710cjEKyTBfwQV/PNKgPHZdQoOQ1AQ9W/UwfjnhRyHUyuKdD)
Up to here, we have been able to see how it would work with a normal application. But we will also see how to make use of it in a Spring Boot application.
We already have the basic knowledge of Jasypt and as always making any application run with Spring will be easier. Although in this case, we will have to make use of a library not developed by Spring itself but by a developer, Ulises Bocchio. But in four simple steps, we can have our Spring application with encrypted properties.
First, we must include the corresponding dependencies for Spring. This can be provided if our project has spring-boot-starter-parent as a parent. But apart we must include the dependency that couples Jasypt with Spring, and it has been made by the external developer:
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot</artifactId>
<version>3.0.3</version>
</dependency>
The second part will be to add the @EnableEncryptableProperties annotation to our main configuration class:
The third part will be to add the Jasypt configuration in the Spring configuration file, application.properties. In it, we will be able to indicate the encryption algorithm or the IV generation class. Apart of course from our encrypted variables, but those can be also stored in others files.
jasypt.encryptor.algorithm=PBEWithHmacSHA512AndAES_256
jasypt.encryptor.iv-generator-classname=org.jasypt.iv.RandomIvGenerator
spring.datasource.username=root
spring.datasource.password=ENC(xwg7loJbeovRKn4R710cjEKyTBfwQV/PNKgPHZdQoOQ1AQ9W/UwfjnhRyHUyuKdD)
Finally, we could obtain them, with the usual Spring annotations, in the following way:
Or if we store them in another file like configuration.properties, as in the previous example, we could obtain them as follows:
To make it work, we can pass the master key in two different ways:
- Through an environment variable named JASYPT_ENCRYPTOR_PASSWORD.
- Through a JVM or Maven argument named jasypt_encryptor_password.
We can adopt this same solution for an Apache Camel application that is managed by Spring Boot.
As we can see, it is a quick and easy solution to avoid having our code with sensitive passwords. The only drawback may be that our properties are not synchronized and we need to restart our application if we want to change them. But for that, we will see that there are solutions like Hashicorp Vault or Apache Zookeeper.
Finally, if you want to try it, here you have the code.