Monday, December 22, 2008

A Groovy Cryptology Library

Rain City's open-source groovy library has recently been enhanced to include a crypto package. Implementation includes symmetric and asymmetric algorithms, hmac, digest, guid, key pool and key store utilities. This post will explain the main classes and show a few examples.

Guid: The Guid class is a simple wrapper around java's UUID class. It makes it easy to create a new guid or read an existing guid string to create a guid object.

println new Guid().toString() -> e79a8462-32ad-48db-9905-3d53e1471de3

SaltedSecureRandom: SaltedSecureRandom provides a salt-seeded SecureRandom object using hardware dependent /dev/urandom. This works for all non-Microsoft-windows platforms. On windows, a simple secure random object is returned. (If you are serious about security, don't use windows).

Digest: This class is a thin wrapper around the JCE digest algorithms, including SHA-512. The class defaults to SHA-256 to maintain compatibility with other languages and platforms. MD5 is also available. The default provider is Sun. The class also provides a 'main' to enable checking digests from the command line.

ByteContainer: The ByteContainer class has utilities for converting strings to by streams, base64 bytes and hex strings. Invaluable for exchanging encrypted data.

Hmac: The Hmac class supports SHA-256 and MD5 and provides methods to set text and key to compute and render keyed digests. It also includes a key generator that defaults to SHA-256 algorithm.

def bc = new ByteContainer()
def k = Hmac.generateKey()

bc.bytes = k.encoded
println bc -> 85a749fd3818fccf0dc6997b6c9f25129babbf6b98606f8b51a14e68b5551fa6

Crypto: This is the primary class to use when you need asymmetric encryption using well known algorithms from various providers. The default algorithm is AES using the Bouncy Castle provider with PKCS7 padding. Other supported algorithms are Blowfish, DES, Tripple DES, and all the others supported by the Sun provider.

def crypto = new Crypto() // requires bouncy castle

assert Security.getProvider("BC")

def pw = "my password".bytes
def key = crypto.createKeySpec( pw )
assert 'AES' == key.algorithm

def text = 'this is a test of plain text'

crypto.generateIV()
println crypto.ivSpec.getIV()

def enc = crypto.encrypt( text, pw )
def s64 = enc.encodeBase64().toString()
println s64 -> q7teBCCBK+n3qTSr518QIj04qa/cS/P2bhsUw/eg8a8=

def dec = crypto.decrypt( enc, pw )
def s = new String( dec )
println s -> this is a test of plain text

crypto.clearBytes pw
println "${pw}" -> [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

RsaKeyPool/RsaKeyStore: 2048 bit public/private keys use very large random prime numbers. So generating secure key pairs takes lots of CPU cycles and a fair amount of time. To alleviate any performance bottlenecks, the best approach is to create a key pool to serve up single use key pairs. The pool actually gets keys from a key store that can be built off-line to any desired size. This approach means that a server won't be bogged down initializing the pool when it first comes up (or is bounced).

The actual generation of the key pairs is through a JCE KeyPairGenerator using the Bouncy Castle provider. It's initialized to the key size (defaulting to 2048 bits) and uses the salted secure random class mentioned earlier.

Rsa: The Rsa class provides encryption and decryption of data using public/private keys. For the uninitiated, the main thing to remember is that the public key is used to encrypt and the private key to decrypt. The Rsa class makes this a bit easier by providing encrypt() and decrypt() methods. A simple use case example goes like this:
  • Alice wants to send an encrypted document to Bob. She begins the process by requesting a public key from Bob. This is what will be used to encrypt the document.
  • Bob creates a key pair (or gets a pair from the pool) and sends the public key back to Alice.
  • Alice creates a Rsa object and sets the public key to Bob's key. The document is encrypted then sent to Bob.
  • Bob receives the encrypted document and decrypts with Rsa using his private key.
Now lets take this simple use case and implement some of the parts. For our purposes, we will use two classes Alice, the sender and Bob the receiver.

import org.raincity.glib.crypto.*

class Alice {
def encrypted
def send = { bob, text ->
def key = bob.getKey()
def rsa = Rsa.instance
rsa.pubKey = key
encrypted = rsa.encrypt( text.bytes )
bob.receive( encrypted )
}
}

class Bob {
def text
def keyPair

def getKey() {
keyPair = RsaKeyPool.instance.keyPair
return keyPair.publicKey
}

def receive = { encrypted ->
def rsa = Rsa.instance
rsa.privKey = keyPair.privateKey
text = new String( rsa.decrypt( encrypted ) )
}
}

alice = new Alice()
bob = new Bob()
alice.send( bob, "This is a super secret message" )
println "encrypted=${new BigInteger(alice.encrypted).toString(16)}"
println bob.text
And when you run the script you see...

encrypted=496bc13c9ba194a2becc525839bab8d9c40a7c126a1ac32f0aa21...
decrypted=This is a super secret message

Future posts will discuss how these classes are used to support Adobe Flex to Grails encrypted exchange sessions. If you are interested you can download the library and examples in a single jar file here.