Encrypting Properties With Jasypt

Properties are used in many Java applications as a simple way of separating parts that are likely to change, from the parts that are not that likely to change. Consider for example this typical bean definition in a Spring configuration file:


   
   
   
   

In order to simplify deployment and maintenance, it’s quite common to extract properties related to server names, ports, and user credentials from the Spring configuration file into a separate property file, like in this ldap.properties:

url=ldap://localhost:3901
userDn=uid=admin,ou=system
password=secret

In the configuration file, the previously hard-coded values are replaced with “property placeholders”, ie variables enclosed with ${}:


   
   
   
   

In order to perform the property value substitution in a transparent way, a PropertyPlaceholderConfigurer is configured:


   

Spring will pick up that one has been configured and run it before any beans are instantiated. It will read the property file and replace the placeholders with the actual values. Quite handy and very simple.

But what if your organization dislikes having sensitive information like passwords lying around in property files, in clear text? Let’s say that your boss demands that all such passwords must be encrypted. Wouldn’t it be great if the password then somehow could be automatically decrypted before being used? This can quite easily be achieved using the Jasypt library.

It’s a two-step process. First we need to encrypt the password. Then we configure a different PropertyPlaceholderConfigurer that is capable of decrypting the property after it has been read.

Encrypting the password

The available encryption algorithms are currently limited to Password Based Encryptors (PBE). There are scripts for encrypting and decrypting in the Jasypt distribution. This is the procedure for encrypting a text (assuming the Jasypt library has been unpacked in JASYPT_HOME):

% cd $JASYPT_HOME/bin
% chmod +x *.sh
% ./encrypt.sh input="This is my message to be encrypted" password=MYPAS_WORD verbose=false
p3ZVFhK+aqQCyvSk9uWk7p/eisyPbXp3zt3sqnEZsn1Z5plr4CHNC/HHqlgRQ7I3

Let’s verify that it can actually be decrypted:

% ./decrypt.sh input="p3ZVFhK+aqQCyvSk9uWk7p/eisyPbXp3zt3sqnEZsn1Z5plr4CHNC/HHqlgRQ7I3"
    password=MYPAS_WORD verbose=false
This is my message to be encrypted

Good. Note that the encryption is “salted”, so you’ll never get the same result twice. You’ll always be able to decrypt it, though. Want to see? OK, one more time then:

% ./encrypt.sh input="This is my message to be encrypted" password=MYPAS_WORD verbose=false
Zi68CfrcLndtKg0npE9OScr+7qNJmWrcO8XI7ZGyucjFiqT9h1FnAIxyezbqNjQq

% ./decrypt.sh input="Zi68CfrcLndtKg0npE9OScr+7qNJmWrcO8XI7ZGyucjFiqT9h1FnAIxyezbqNjQq"
    password=MYPAS_WORD verbose=false
This is my message to be encrypted

Now, let’s encrypt our password:

% ./encrypt.sh input="secret" password=MYPAS_WORD verbose=false
6mbJVZ6jozGYF1pjjqDQOQ==

We’ll replace the password value in the properties file with the string above, surrounded by ENC():

url=ldap://localhost:3901
userDn=uid=admin,ou=system
password=ENC(6mbJVZ6jozGYF1pjjqDQOQ==)

Configure A Decrypting PropertyPlaceholderConfigurer

We’ll simply replace our existing PropertyPlaceholderConfigurer with the Jasypt EncryptablePropertyPlaceholderConfigurer:


   
   

It delegates the actual decryption to a StringEncryptor implementation:


   

The encryptor in turn needs a configuration that provides information such as the algorithm to use and the encryption password. It delegates that responsibility to a PBEConfig implementation that expects the password to be available in an environment variable or a system property:


   
   

Providing the encryption password as a system property is actually a good thing. A system property can be cleared just when the application has started, thereby minimizing considerably the time that the password is exposed.

Running The Application

It won’t work with a Maven property:

% mvn test -DAPP_ENCRYPTION_PASSWORD=MYPAS_WORD
...
Tests run: 8, Failures: 0, Errors: 8, Skipped: 0
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] There are test failures.

Please refer to target/surefire-reports for the individual test results

We check the Surefire reports and find the cause of the error:

org.jasypt.exceptions.EncryptionInitializationException:
  Password not set for Password Based Encryptor

It does however work with an environment variable:

% export APP_ENCRYPTION_PASSWORD=MYPAS_WORD
% mvn test
...
Tests run: 8, Failures: 0, Errors: 0, Skipped: 0
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
...
% unset APP_ENCRYPTION_PASSWORD

Issues With Java5

If we’re on Java5 (or lower), we’ll need ICU4J. Otherwise, we’ll run into this:

org.jasypt.exceptions.EncryptionInitializationException:
  java.lang.NoClassDefFoundError: com/ibm/icu/text/Normalizer

There are two places where we’ll need ICU4J: the command line tools and our Maven project.

ICU4J With The Command Line Tools

Reviewing the Jasypt scripts, we find that it’s possible to customize the classpath:

export JASYPT_CLASSPATH=~/Downloads/icu4j-4_0.jar

ICU4J With Maven

Add this profile to the Maven pom.xml to get ICU4J in the classpath:


   
      jdk15
      
         1.5
      
      
         
            com.ibm.icu
            icu4j
            3.8
         
      
   

Currently, the 4.0 version is not available in the central Maven repo, but 3.8 seems to work just fine.

Summary

Using Jasypt, it’s actually quite easy to use encrypted values in your property files. In a Spring-based application, it’s simply a question of replacing the existing PropertyPlaceholderConfigurer with the Jasypt encrypting equivalent, plus two more beans providing encryption and configuration. Choose how to provide the encryption password, and you’re set to go.

If running on Java5 or lower, you’ll also need to add ICU4J to your classpath, for the encryption scripts as well as your build and deployment environment.

References

This Post Has 31 Comments

  1. Ed K

    Great post! This is exactly what I was looking for.

  2. Ronn

    Can you please provide a little sample spring application , (Sample Code) for Jasypt, it will be very helpfull to understnd all the steps and from begining to end.
    if u can please mail or upload a sample Spring application with Jasypt.

  3. Ronn

    Hi, I am still getting this error for Jasypt1.5 , i tried to include my classpath variable and path for ICU, can you please let me know what exaclt we need to do to run Encyption.bat on windows
    i am using
    java version “1.4.2_17″
    Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2
    Java HotSpot(TM) Client VM (build 1.4.2_17-b06, mixed mode)

    Here is what i did
    C:jasypt-1.5bin>encrypt.bat input=”my test data” password=m
    —-ENVIRONMENT—————–
    Runtime: Sun Microsystems Inc. Java HotSpot(TM) Client VM 1.4
    —-ARGUMENTS——————-
    input: my test data
    password: my_pa_word
    —-ERROR———————–
    java.lang.NoClassDefFoundError: com/ibm/icu/text/Normalizer

    I added in classpath — C:icu4j-4_0icu4j-4_0.jar
    and iin path C:icu4j-4_0

    Do I need to add JSYPT in classpath ??
    please help.

  4. Charlie Simms

    What do I need to do to resolve the following error:
    PropertyAccessException 1: org.springframework.beans.MethodInvocationException: Property ‘passwordEnvName’ threw exception; nested exception is java.lang.Error: getenv no longer supported, use properties and -D instead: APP_ENCRYPTION_PASSWORD]

    1. Ulrik Sandberg

      Not sure about this one, but System.getenv was re-instated in Java5 after having been deprecated in 1.2. Could it be that you’re using an older Java?

  5. Charlie Simms

    I am using 1.4.
    I only want to be able to pick up the password from my properties file not as an environment variable

  6. Yair

    Hi. I’m creating an application with Spring and Hibernate. I follow the steps to encrypt the hibernate password and it works correctly on Windows but it doesn’t work on linux Debian. Do I have to configure the APP_ENCRYPTION_PASSWORD in somewhere or something?

    thank you in advance…

  7. Bo

    Hi:
    Mr.Sandberg .I’m a Chinese student. On this point I hame some problems. at ”
    org.jasypt.exceptions.EncryptionInitializationException:
    Password not set for Password Based Encryptor


    According to the method that is you. if between “ENC” and “()”
    have a space,then Compile OK, but when the project submitted to the user or running password is incorrect. What should I do?

    both isn’t have some space?

    you have time to return? Here or EMAIL. thanks.

  8. Tuno

    Great post! This is exactly what I was looking for too.

  9. Ben

    Will this work on Windows7? I have a system environment variable set for the password to decrypt the datasouce password. After debugging the source code, it’s still not clear to me where I messed up. With jasypt 1.8, I’m getting this…

    java.lang.NullPointerException at org.jasypt.encryption.pbe.config.SimplePBEConfig.getPasswordCharArray(SimplePBEConfig.java:434) at org.jasypt.encryption.pbe.StandardPBEByteEncryptor.resolveConfigurationPassword(StandardPBEByteEncryptor.java:740)

  10. Ulrik Sandberg

    Looking at that line, it seems the password property is null. Perhaps that gives you a hint where to look further.

  11. Ben

    SOLVED

    The problem was resolved after a reboot.

  12. Aditya

    Hi,

    Thank you for this blog.
    However I have a query. Can we use JASYPT Encryptor with PropertyFactoryBean. So before making a properties file available to bean it is decrypted.

    Thank You
    Aditya Sharma

  13. Thorsten Reimers

    Cool, very helpful description!!!

    I just followed your instructions, ran into the NullPointer from above, added the missing property for my master password and was able to use encryption within one hour!

    Thank you very much for this clear step by step instruction
    Thorsten

  14. Kerry

    Can i hide the value of “APP_ENCRYPTION_PASSWORD”?

    In my situation the encrpytion work is done by 3rd party than they won’t provide their password they use for encrypting the string.

    Thank you. The blog is very clear!!

  15. javaguy

    My batch processes kicks off automatically during nights and there is no way of manual intervention, so how can i handle the master password(APP_ENCRYPTION_PASSWORD) ?

    Just a person encrypts database password and paste it in the properties file and using shell scripts the application kicks off automatically. Then how can the application able to receive the master password ? How can I secure master password ?

  16. alu

    I’m getting org.jasypt.exceptions.EncryptionOperationNotPossibleException.

    I used encrypt.bat to encrypt my password and able to get it back with decrypt.bat. I added to environment variable and updated my property file.

    I still have the same exception. Can you point out anywhere else I should check? I wonder if OS makes any difference. I’m on Windows 7.

  17. alu

    Hi, I debugged and finally traced down to “javax.crypto.BadPaddingException Given final block not properly padded”. Does anyone know where I might be doing wrong?

  18. pzerocool

    This is the perfect solution.
    Excellent post.

  19. Shameer

    Thanks for your this Nice Post. Simple & Well explained. Keep writing…

  20. Uma

    I am getting NULL Pointer Exception….Can someone help
    I hardcoded password to make sure I am passing all values…

    16:15:50,230 INFO XmlBeanDefinitionReader:315 – Loading XML bean definitions from class path resource [applicationContext.xml]
    16:15:50,905 INFO XmlBeanDefinitionReader:315 – Loading XML bean definitions from class path resource [hibernate.cfg.xml]
    16:15:51,913 INFO EncryptablePropertyPlaceholderConfigurer:177 – Loading properties file from URL [file:config/jdbc.properties]
    16:15:51,914 INFO EncryptablePropertyPlaceholderConfigurer:177 – Loading properties file from URL [file:config/broker.properties]
    16:15:52,027 ERROR EMMSServer:85 – EMMS Server starting problem :
    org.jasypt.exceptions.EncryptionInitializationException: java.lang.NullPointerException
    at org.jasypt.encryption.pbe.StandardPBEByteEncryptor.initialize(StandardPBEByteEncryptor.java:708)
    at org.jasypt.encryption.pbe.StandardPBEStringEncryptor.initialize(StandardPBEStringEncryptor.java:553)
    at org.jasypt.encryption.pbe.StandardPBEStringEncryptor.decrypt(StandardPBEStringEncryptor.java:705)
    at org.jasypt.properties.PropertyValueEncryptionUtils.decrypt(PropertyValueEncryptionUtils.java:72)
    at org.jasypt.spring31.properties.EncryptablePropertyPlaceholderConfigurer.convertPropertyValue(EncryptablePropertyPlaceholderConfigurer.java:109)
    at org.springframework.beans.factory.config.PropertyResourceConfigurer.convertProperty(PropertyResourceConfigurer.java:121)
    at org.springframework.beans.factory.config.PropertyResourceConfigurer.convertProperties(PropertyResourceConfigurer.java:104)
    at org.springframework.beans.factory.config.PropertyResourceConfigurer.postProcessBeanFactory(PropertyResourceConfigurer.java:81)
    at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:681)
    at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:656)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:446)
    at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:139)
    at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:83)
    at com.csc.emms.server.EMMSServer.main(EMMSServer.java:90)
    at com.csc.emms.service.servicelauncher.ServiceLauncher.start(ServiceLauncher.java:65)
    at com.csc.emms.service.servicelauncher.ServiceLauncher.serviceMain(ServiceLauncher.java:33)
    Caused by: java.lang.NullPointerException
    at org.jasypt.normalization.Normalizer.normalizeToNfc(Normalizer.java:88)
    at org.jasypt.encryption.pbe.StandardPBEByteEncryptor.initialize(StandardPBEByteEncryptor.java:653)
    … 15 more

    below are the code:
    ==================

    <property name="password" value="” />

    1. PratikC

      I am also getting the same exception, NPE…
      Did you get any resolution for it then please enlighten me!

      Thanks,
      Pratik

  21. Gina Choi

    Nice and clear! Thank you.

  22. Hrishikesh

    How should put here

    if i have multiple user name and password for different databases in same properties file?

  23. Wasim

    Hi,

    I tried the above implementation but im getting this issue :

    org.xml.sax.SAXParseException; lineNumber: 6; columnNumber: 68; schema_reference.4: Failed to read schema document ‘http://www.jasypt.org/schema/encryption/’, because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not .

    Can someone please help me here ?

    Thanks,
    Wasim

  24. zack j

    Great blog post! This explanation was short but tremendously helpful. Thank you for sharing.

  25. sharon

    Thank you very much for this!!!
    I would like to know, This article is almost 10 years old, is there any differences when going with jasypt 1.9.2 and spring 4.3.11.RELEASE

  26. Vinu

    Great Post. Thank you very much.

  27. Deepak

    Very useful post !! keep up the good work.

Leave a Reply