I decided this functionality would be helpful for a project I am working on.
Aside from the standard clojure, it also requires commons-codec.
project.clj
:
(defproject <project> "VERSION"
...
:dependencies [[org.clojure/clojure "1.5.1"]
[commons-codec "1.8"]])
<project>/src/crypt.clj
:
(ns <whatever>.crypt
(:import (javax.crypto KeyGenerator SecretKey Cipher SecretKeyFactory)
(javax.crypto.spec SecretKeySpec PBEKeySpec)
(org.apache.commons.codec.binary Base64)))
(def ^:dynamic *salt* "BIND SALT IN APP")
(defn cipher- [] (. Cipher getInstance "AES"))
(defn aes-keyspec [rawkey] (new SecretKeySpec rawkey "AES"))
(defn encrypt-
[rawkey plaintext]
(let [cipher (cipher-)
mode (. Cipher ENCRYPT_MODE)]
(. cipher init mode (aes-keyspec rawkey))
(. cipher doFinal (. plaintext getBytes))))
(defn decrypt-
[rawkey ciphertext]
(let [cipher (cipher-)
mode (. Cipher DECRYPT_MODE)]
(. cipher init mode (aes-keyspec rawkey))
(new String(. cipher doFinal ciphertext))))
(defn passkey
[password & [iterations size]]
(let [keymaker (SecretKeyFactory/getInstance "PBKDF2WithHmacSHA1")
pass (.toCharArray password)
salt (.getBytes *salt*)
iterations (or iterations 1000)
size (or size 128)
keyspec (PBEKeySpec. pass salt iterations size)]
(-> keymaker (.generateSecret keyspec) .getEncoded)))
(defn encrypt
[password plaintext]
(encrypt- (passkey password) plaintext))
(defn decrypt
[password cyphertext]
(decrypt- (passkey password) cyphertext))
usage:
(binding [crypt/*salt* "THE SALT WE ARE USING"]
(crypt/encrypt "password" "message")
(crypt/decrypt "password" *1)))
if you can use generated keys, that is going to be more secure:
(defn aes-keygen [] (. KeyGenerator getInstance "AES"))
(defn genkey
[keygen]
(. keygen init 128)
(. (. keygen generateKey ) getEncoded))
(def generated (keygen aes-keygen))
(encrypt- generated plaintext)
(decrypt- generated *1)
This is only using vanilla security features provided with the jvm (commons-codec is just used for base-64 encoding/decoding so that we can operate on arbitrary input, it is not part of the security setup).