This guide contains low-level technical information. Maybe you should start first with the Easy Usage or General Usage guides?

Encrypting passwords

If you want to read about how passwords should be encrypted, how you would defend from attacks on your user password database, and why you should use jasypt for encrypting your passwords, have a look at this article: How to Encrypt User Passwords.

Digest creation process with jasypt's Standard[Byte|String]Digester

The steps taken in jasypt's standard digesters for creating digests are:

  1. A salt of the specified size is generated (see org.jasypt.salt.SaltGenerator). If salt size is zero, no salt will be used. It is advisable that you use a random salt generator like org.jasypt.salt.RandomSaltGenerator (which is the default) for higher security.
  2. The salt bytes are appended at the beginning of the message.
  3. The hash function is applied to the salt and message altogether, and then to the results of the function itself, as many times as specified (iterations).
  4. If using a random salt generator, the undigested salt is appended at the beginning of the hash result.

Put schematically in bytes:

  • DIGEST = |S|..(ssb)..|S|X|X|X|...|X|
    • S: salt bytes (plain, not digested). (Only if using a random salt generator).
    • ssb: salt size in bytes.
    • X: bytes resulting from hashing (see below).
  • |X|X|X|...|X| = H(H(H(..(it)..H(Z|Z|Z|...|Z|))))
    • H: Hash function (algorithm).
    • it: Number of iterations.
    • Z: Input for hashing (see below).
  • |Z|Z|Z|...|Z| = |S|..(ssb)..|S|M|M|M...|M|
    • S: salt bytes (plain, not digested).
    • ssb: salt size in bytes.
    • M: message bytes.

When using a random salt generator, two digests created for the same message will always be different (except in the case of random salt coincidence or no usage of salt). Because of this, in this case the result of the digest method will contains both the undigested salt and the digest of salt+message, so that another digest operation can be performed with the same salt on a different message to check if both messages match (all of which will be managed automatically by the matches method).

Also, when using StandardStringDigester, the resulting digest Strings are BASE64 encoded (or hexadecimal, if you prefer) to avoid charset issues. This output encoding can be chosen with the setStringOutputType method.

RFC2307 password encryption for LDAP systems

Many LDAP systems (e.g. OpenLDAP) use password encryption schemes different to jasypt's default one. These are mainly derived from the schemes defined in RFC2307, like for example SSHA (Salted SHA).

Salted RFC2307-oriented algorithms require an inversion in the positioning of the salt during the digest operation. Jasypt supports this since version 1.7, and provides a set of util classes in the org.jasypt.util.password.rfc2307 package for the easy creation and matching of SSHA, SMD5 and other password encryption schemes of common use in LDAP systems.

Refer to these classes' JavaDoc for more details.

Code examples

Easiest use: the BasicPasswordEncryptor util class:

...
BasicPasswordEncryptor passwordEncryptor = new BasicPasswordEncryptor();
String encryptedPassword = passwordEncryptor.encryptPassword(userPassword);
...
if (passwordEncryptor.checkPassword(inputPassword, encryptedPassword)) {
  // correct!
} else {
  // bad login!
}
...

More security: the StrongPasswordEncryptor util class with a much more secure (but slower!) algorithm:

...
StrongPasswordEncryptor passwordEncryptor = new StrongPasswordEncryptor();
String encryptedPassword = passwordEncryptor.encryptPassword(userPassword);
...
if (passwordEncryptor.checkPassword(inputPassword, encryptedPassword)) {
  // correct!
} else {
  // bad login!
}
...

A little bit more control on encryptor configuration: the ConfigurablePasswordEncryptor class:

...
ConfigurablePasswordEncryptor passwordEncryptor = new ConfigurablePasswordEncryptor();
passwordEncryptor.setAlgorithm("SHA-1");
passwordEncryptor.setPlainDigest(true);
String encryptedPassword = passwordEncryptor.encryptPassword(userPassword);
...
if (passwordEncryptor.checkPassword(inputPassword, encryptedPassword)) {
  // correct!
} else {
  // bad login!
}
...

All these util classes are in fact pre-configured, easy-to-use versions of StandardStringDigester, so let's use the original class for total control:

...
StandardStringDigester digester = new StandardStringDigester();
digester.setAlgorithm("SHA-1");   // optionally set the algorithm
digester.setIterations("50000");  // increase security by performing 50000 hashing iterations
...
String digest = digester.digest(userPassword);
...
if (digester.matches(inputPassword, digest)) {
  // correct!
} else {
  // bad login!
}
...

And we can even use a pooled version for higher performance in multi-processor/multi-core systems:

...
PooledStringDigester digester = new PooledStringDigester();
digester.setPoolSize(4);          // This would be a good value for a 4-core system 
digester.setAlgorithm("SHA-1");
digester.setIterations("50000");
...
String digest = digester.digest(userPassword);
...
if (digester.matches(inputPassword, digest)) {
  // correct!
} else {
  // bad login!
}
...