2

Is there a simple text encyptor for Clojure which just needs one password to decrypt? I just want something like to encrypt:

(encrypt "Some secret message" "Some secret key")

:and to decrypt:

(decrypt (encrypt "Some secret message" "Some secret key") "Some secret key")

:will return:

"Some secret message"
yazz.com
  • 57,320
  • 66
  • 234
  • 385
  • I think your answer is here: http://stackoverflow.com/questions/10221257/is-there-an-aes-library-for-clojure – noisesmith Aug 19 '13 at 14:37

3 Answers3

3

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).

noisesmith
  • 20,076
  • 2
  • 41
  • 49
1

Try simple-crypto:

[org.clojars.tnoda/simple-crypto "0.1.0"]

It do exactly what you want:

user=> (use 'org.clojars.tnoda.simple-crypto)
user=> (decrypt (encrypt "Some secret message" "Some secret key!") "Some secret key!")
"Some secret message"
Leonid Beschastny
  • 50,364
  • 10
  • 118
  • 122
0

I'm not aware of any Clojure library that is doing that mostly -I would say- because it is too easy to do using javax.crypto, javax.crypto.spec and java.security packages.

Could be done within 30 lines.

Chiron
  • 20,081
  • 17
  • 81
  • 133