Skip to content
mcantrell edited this page Jan 19, 2013 · 18 revisions

Zuul utilizes PBE (Password Based Encryption) algorithms from the JCE (Java Cryptography Extension) and Bouncy Castle via the Jasypt API.

The Zuul server and spring client are both bundled with everything except for the JCE Policy files. You'll need to download and install them into your JAVA_HOME/jre/lib/security directory.

If you're using Jasypt directly or using another language such as Node.js, Ruby, etc., The following details will help you get started. I'm working on a Node.js client which should be available soon.

Algorithms

By default, every JVM is able to do simple encryption. Without any modifications, any java client can use DES encryption but it's no longer considered secure due to its small key size. Zuul has the ability to use stronger algorithms but the server and clients will have extra dependencies.

AES (Bouncy Castle)

Triple DES (Bouncy Castle)

Triple DES (JCE)

DES (JCE)

  • Name: PBEWithMD5AndDES
  • Requirements: none (but not secure)
  • Hashing Algorithm: MD5
  • Hashing Iterations: 1000

Java PBE Details

Essentially, algorithms must have a key of x bits and should be relatively random. Using passwords as keys posses two problems:

  • They probably aren't going to match the number of bits you'll need to create a key
  • They're based on a limited number of characters which restricts the amount of randomness available even if you have a super, duper, really great password.

To overcome this limitation, RSA Labs created a few specs such as PKCS#5 which outlines how to create cryptography keys from passwords with increased security.

Essentially, the password is combined with a salt (usually random bits). This is then fed through a hashing algorithm many (1000+) times to create the secret key via a Key Derivation Function (KDF). The salt, hashing algorithm and iteration counts are not considered to be secret and may be freely exchanged.

The encrypted values produced by Jasypt (and thus Zuul) are are prefixed with the salt (usually 8 or 16 bytes depending on the algorithm requirements). They are then Base64 encoded. Decrypting the results goes something like this:

  • Convert the Base64 string to bytes
  • Strip off the first 8 or 16 bytes as the salt
  • Keep the remaining bytes for the encrypted payload
  • Invoke the KDF function with the salt, iteration count and the password to create the secret key.
  • Use the secret key to decrypt the encrypted payload

PKDF1 vs PKDF2

The main issue that you're likely to run into is the version of the KDF function used. Although Java supports PKDF2 (which is more secure), Jasypt still uses PKDF1. There have been requests to enhance it but they've been declined:

http://brianrepko.wordpress.com/2010/07/21/extending-jasypt-aes-and-blowfish-support/ http://sourceforge.net/tracker/?func=detail&aid=3032821&group_id=183612&atid=905947

PKDF2 is predominant in most other platforms. Replicating the PDKF1 behavior is relatively easy. The following is a Node.js (javascript) example using its crypto lib:

Mocha Test

var should = require('should'),
    crypto = require('crypto');

describe('Crypto Spike Tests', function () {
    var password = new Buffer('test', 'utf8');

    var KDF = function(password, salt, iterations) {
        var key = Buffer.concat([password, salt]);
        for (var i = 0; i < iterations; i++) {
            key = crypto.createHash("md5").update(key).digest();
        }
        return key;
    };

    it('should decrypt PBEWithMD5AndDES with 1000 hash iterations', function () {
        var encryptedBuffer = new Buffer('/w5a6LHjfwbjhTLUAKiPKg==', 'base64');
        var salt = encryptedBuffer.slice(0, 8);
        var payload = encryptedBuffer.slice(8);

        var key = KDF(password, salt, 1000);
        var keyBuffer =  new Buffer(key, 'binary').slice(0,8);
        var ivBuffer = new Buffer(key, 'binary').slice(8,16);

        var decipher = crypto.createDecipheriv('des', keyBuffer, ivBuffer);
        var msg = [];
        msg.push(decipher.update(payload));
        msg.push(decipher.final());
        var decrypted = msg.join("");
        decrypted.should.eql('abc');
    });
});

PGP

Zuul 1.4 adds increased encryption security and portability with the introduction of PGP public key encryption. You may now upload your ASCII armored public key:

PGP Key Screenshot

With PGP support adds increased security but comes a few limitations:

  • Decryption features are disabled because no secret key exists on the server. Clients are responsible for maintaining the secret key and decryption operations.
  • Once a settings group has been updated to use a PGP key, it may not be changed to another key until all values are deleted or manually unencrypted
  • Updating a PGP public key has the same limitations. Any assigned groups must have no encrypted values.

Zuul has error handling and warnings around these rules but keep all of this in mind before you choose to use PGP encryption.

If you need help generating keys, etc. Please see the PGP Help page.

Clone this wiki locally