Encryption plugin for Grails
2% of Grails users
Dependency :
compile ":crypto:2.0"
Summary
Installation
grails install-plugin crypto
Description
A Grails plugin with some Groovy wrappers for both Blowfish and PGP, as well as a tool class for generating random passwords, salting passwords when hashing them, and verifying salted passwords. Uses the Bouncy Castle encryption libraries.
The first method in each of these sets generates a String consisted of the salted and hashed password, and the second checks a submitted password (the first argument) against a salted and hashed password (the second argument).In addition, there are two utility static methods to return a random login and password:
The set of allowed password characters are the alphanumerics along with "!@,;.-=+" (not including quotes).
The set of allowed login characters are the alphanumerics along with just "." (not including quotes).
Encrypted values can also be returned base64-encoded, where there's an extra option to trim the result string.
For encryption, the following code encrypts a message in three different ways, which should all be equivalent. While the example returns the encrypted text as base64-encoded, a function that returns it as a byte array is also available (the equivalent call would be pgp.decrypt)
And this code encrypts a message and instead of returning the byte array base64-encoded, returns it encoded as armored text.
In the case of a decryption failure, the decrypt function will return null:
While the default encodedPrivateKey function returns the key encrypted with a blank passphrase, one can easily be added:
The above code would fail in JDK6 because of a String.getBytes() problem.
The solution would be to:import java.nio.charset.Charset....byte (+) xencrypted = Blowfish.encrypt(message.getBytes(Charset.forName("ISO-8859-1")), password)Similar for decrypt:String decryptedString = new String(decrypted,Charset.forName("ISO-8859-1"))BTW, Some how "UTF-8" does not work here
Password Management
Mr. Smart Developer Says: "Storing plaintext passwords is EEEEEEVIL. Simply don't do it, because you're exposing your users to all kinds of potential threat, and may be tempted for evil yourself. If you aren't going to use some kind of externalized authentication service, then store your passwords salted and hashed."While Mr. Smart Developer is totally right, that's traditionally been difficult to do in Grails, because there's no easy way to salt and hash passwords. This plugin solves that.Password management utilities are found in cr.co.arquetipos.password.PasswordTools. In there are two sets of static methods for working with salted and hashed passwords:saltPasswordBase64(String) / checkDigestBase64(String,String) saltPasswordHex(String) / checkDigestHex(String,String)
generateRandomPassword(int size=10) generateRandomLogin(int size=10)
Blowfish
The following encrypts a message with blowfish, and attempts to decrypt it with both the correct password and a bad one.String message = 'Hush hush' String password = 'DeVitto' String badPassword = 'Danny'// Encrypts the message as a byte array byte[] encrypted = Blowfish.encrypt(message.getBytes(), password) assert encrypted// Decrypts with the correct password, and compares def decrypted = Blowfish.decrypt(encrypted, password) assert decrypted String decryptedString = new String(decrypted)// Decrypted strings may contain trailing char(0)s decryptedString = decryptedString.trim()println "$decryptedString ${decryptedString.getBytes()}" println "$message ${message.getBytes()}"assertEquals decryptedString, message// Decrypting with a bad password returns null decrypted = Blowfish.decrypt(encrypted, badPassword) assert decrypted == null
String message = 'Hush hush' String password ='DeVitto' String badPassword = 'Danny'// Encrypts a message and returns it base64-encoded String encrypted = Blowfish.encryptBase64(message, password) assert encrypted String decrypted = Blowfish.decryptBase64(encrypted, password) assert decryptedassertEquals decrypted, message// There's an option to not trim the return value, even though the // default is to do so. In that case, the decrypted value may not // exactly match the original message decrypted = Blowfish.decryptBase64(encrypted, password, false) assert decrypted != message assertEquals decrypted.trim(), messageprintln "The following two rows should be different:" println "$decrypted ${decrypted.getBytes()}"// Decrypting with an invalid password returns null decrypted = Blowfish.decryptBase64(encrypted, badPassword) assertEquals decrypted, null
PGP
Key generation and encoding:// Generates a PGP key pair def pgp = PGP.generateKeyPair()// Verifies that all values are present assert pgp assert pgp.keyPair assert pgp.publicKey assert pgp.privateKeyassertEquals pgp.keyPair.publicKey, pgp.publicKey assertEquals pgp.keyPair.privateKey, pgp.privateKey// Obtains the public and private keys, encoded armored-encoded String encodedPublic = pgp.encodedPublicKey String encodedPrivate = pgp.encodedPrivateKey// Creates PGP objects which contain only the public or private keys PGP publicOnly = new PGP(encodedPublic, '') PGP privateOnly = new PGP('', encodedPrivate)// Verifies that the previously encoded public key matches the // one from the object we just created with it assertEquals encodedPublic, publicOnly.encodedPublicKeyassert publicOnly assert privateOnly // Key created from the private key must have the public key as well assert privateOnly.encodedPrivateKey assert privateOnly.encodedPublicKeyprintln "From privateOnly:" println publicOnly.encodedPublicKey println privateOnly.encodedPublicKey println privateOnly.encodedPrivateKey
def pgp = PGP.generateKeyPair()String encodedPublic = pgp.encodedPublicKey String encodedPrivate = pgp.encodedPrivateKeyPGP publicOnly = new PGP(encodedPublic, '') PGP privateOnly = new PGP('', encodedPrivate)assert publicOnly assert privateOnlyassertEquals encodedPublic, publicOnly.encodedPublicKeyString message = 'Hush hush' /* Encrypts the message in three different ways: with the original key pair, with the one that only has the public key, and with the one that was generated from the private key. They will later be decrypted in several ways to ensure that all are equivalent. */ String encrypted = pgp.encryptBase64(message) String encrypted2 = publicOnly.encryptBase64(message) String encrypted3 = privateOnly.encryptBase64(message)assert encrypted assert encrypted2 assert encrypted3println "Encrypted number one:" println encrypted println "Encrypted number two:" println encrypted2 String decryptedPrivate = privateOnly.decryptBase64(encrypted) assert decryptedPrivateString decryptedBoth = pgp.decryptBase64(encrypted2) assert decryptedBothassertEquals decryptedPrivate, decryptedBoth assertEquals decryptedPrivate, messagedecryptedPrivate = privateOnly.decryptBase64(encrypted2) assert decryptedPrivatedecryptedBoth = pgp.decryptBase64(encrypted) assert decryptedBothString decryptedPrivate3 = privateOnly.decryptBase64(encrypted3) assert decryptedPrivate3String decryptedBoth3 = pgp.decryptBase64(encrypted3) assert decryptedBoth3assertEquals decryptedPrivate, decryptedBoth assertEquals decryptedPrivate, message assertEquals decryptedBoth3, message assertEquals decryptedPrivate3, message
def pgp = PGP.generateKeyPair()String encodedPublic = pgp.encodedPublicKey String encodedPrivate = pgp.encodedPrivateKeyPGP publicOnly = new PGP(encodedPublic, '') PGP privateOnly = new PGP('', encodedPrivate)assert publicOnly assert privateOnlyassertEquals encodedPublic, publicOnly.encodedPublicKeyString message = 'Hush hush' String encrypted = pgp.encryptArmored(message) String encrypted2 = pgp.encryptArmored(message)println "Armored 1:n$encryptedn" println "Armored 2:n$encrypted2n"
def pgp = PGP.generateKeyPair() def pgp2 = PGP.generateKeyPair()String message = 'Hush hush' String encrypted = pgp.encryptBase64(message) assert encryptedString decrypted = pgp2.decryptBase64(encrypted) assertEquals decrypted, null
def pgp = PGP.generateKeyPair()String passphrase = PasswordTools.generateRandomPassword(10) assert passphrase assertEquals passphrase.size(), 10String encodedPublic = pgp.encodedPublicKey String encodedPrivate = pgp.getEncodedPrivateKey(passphrase)// ..... // The encoded key is later instantiated using the passphrasePGP privateOnly = new PGP('', encodedPrivate, passphrase) assert privateOnly