[Encryption] Rewrite encryption ns to build off new crypto ns
This commit is contained in:
parent
2dec26fd95
commit
868a8f65de
1 changed files with 23 additions and 82 deletions
|
|
@ -1,12 +1,8 @@
|
||||||
(ns taoensso.nippy.encryption
|
(ns taoensso.nippy.encryption
|
||||||
"Simple no-nonsense crypto with reasonable defaults"
|
"Simple no-nonsense crypto with reasonable defaults"
|
||||||
(:require [taoensso.encore :as enc]))
|
(:require
|
||||||
|
[taoensso.encore :as enc]
|
||||||
;; Note that AES128 may be preferable to AES256 due to known attack
|
[taoensso.nippy.crypto :as crypto]))
|
||||||
;; vectors specific to AES256, Ref. https://www.schneier.com/blog/archives/2009/07/another_new_aes.html
|
|
||||||
;; Or, for a counter argument, Ref. https://blog.agilebits.com/2013/03/09/guess-why-were-moving-to-256-bit-aes-keys/
|
|
||||||
|
|
||||||
;;;; Interface
|
|
||||||
|
|
||||||
(def standard-header-ids "These'll support :auto thaw" #{:aes128-sha512})
|
(def standard-header-ids "These'll support :auto thaw" #{:aes128-sha512})
|
||||||
|
|
||||||
|
|
@ -15,50 +11,6 @@
|
||||||
(encrypt ^bytes [encryptor pwd ba])
|
(encrypt ^bytes [encryptor pwd ba])
|
||||||
(decrypt ^bytes [encryptor pwd ba]))
|
(decrypt ^bytes [encryptor pwd ba]))
|
||||||
|
|
||||||
;;;; Default digests, ciphers, etc.
|
|
||||||
|
|
||||||
;; TODO Prefer GCM > CBC ("AES/GCM/NoPadding", Ref. https://goo.gl/jpZoj8
|
|
||||||
(def ^:private aes-cipher* (enc/thread-local-proxy (javax.crypto.Cipher/getInstance "AES/CBC/PKCS5Padding")))
|
|
||||||
(def ^:private sha512-md* (enc/thread-local-proxy (java.security.MessageDigest/getInstance "SHA-512")))
|
|
||||||
(def ^:private prng* (enc/thread-local-proxy (java.security.SecureRandom/getInstance "SHA1PRNG")))
|
|
||||||
|
|
||||||
(defn- aes-cipher ^javax.crypto.Cipher [] (.get ^ThreadLocal aes-cipher*))
|
|
||||||
(defn- sha512-md ^java.security.MessageDigest [] (.get ^ThreadLocal sha512-md*))
|
|
||||||
(defn- prng ^java.security.SecureRandom [] (.get ^ThreadLocal prng*))
|
|
||||||
|
|
||||||
(def ^:private ^:const aes-block-size (.getBlockSize (aes-cipher)))
|
|
||||||
(def ^:private ^:const aes-iv-size aes-block-size #_12) ; 12 for GCM, Ref. https://goo.gl/c8mhqp
|
|
||||||
(def ^:private ^:const salt-size 16)
|
|
||||||
|
|
||||||
(defn- rand-bytes [size] (let [ba (byte-array size)] (.nextBytes (prng) ba) ba))
|
|
||||||
|
|
||||||
;;;; Default key derivation (salt+password -> key)
|
|
||||||
|
|
||||||
(defn- sha512-key
|
|
||||||
"SHA512-based key generator. Good JVM availability without extra dependencies
|
|
||||||
(PBKDF2, bcrypt, scrypt, etc.). Decent security when using many rounds."
|
|
||||||
|
|
||||||
([salt-ba pwd ] (sha512-key salt-ba pwd (* Short/MAX_VALUE (if salt-ba 5 64))))
|
|
||||||
([salt-ba pwd ^long n]
|
|
||||||
(let [md (sha512-md)
|
|
||||||
init-ba (let [pwd-ba (.getBytes ^String pwd "UTF-8")]
|
|
||||||
(if salt-ba (enc/ba-concat salt-ba pwd-ba) pwd-ba))
|
|
||||||
^bytes ba (enc/reduce-n (fn [acc in] (.digest md acc)) init-ba n)]
|
|
||||||
|
|
||||||
(-> ba
|
|
||||||
(java.util.Arrays/copyOf aes-block-size)
|
|
||||||
(javax.crypto.spec.SecretKeySpec. "AES")))))
|
|
||||||
|
|
||||||
(comment
|
|
||||||
(enc/qb 10
|
|
||||||
(sha512-key nil "hi" (* Short/MAX_VALUE 1)) ; ~40ms per hash (fast)
|
|
||||||
(sha512-key nil "hi" (* Short/MAX_VALUE 5)) ; ~180ms (default)
|
|
||||||
(sha512-key nil "hi" (* Short/MAX_VALUE 32)) ; ~1200ms (conservative)
|
|
||||||
(sha512-key nil "hi" (* Short/MAX_VALUE 128)) ; ~4500ms (paranoid)
|
|
||||||
))
|
|
||||||
|
|
||||||
;;;; Default implementations
|
|
||||||
|
|
||||||
(defn- throw-destructure-ex [typed-password]
|
(defn- throw-destructure-ex [typed-password]
|
||||||
(throw (ex-info
|
(throw (ex-info
|
||||||
(str "Expected password form: "
|
(str "Expected password form: "
|
||||||
|
|
@ -76,45 +28,32 @@
|
||||||
|
|
||||||
(comment (destructure-typed-pwd [:salted "foo"]))
|
(comment (destructure-typed-pwd [:salted "foo"]))
|
||||||
|
|
||||||
(deftype AES128Encryptor [header-id keyfn cached-keyfn]
|
(deftype AES128Encryptor [header-id salted-key-fn cached-key-fn]
|
||||||
IEncryptor
|
IEncryptor
|
||||||
(header-id [_] header-id)
|
(header-id [_] header-id)
|
||||||
(encrypt [_ typed-pwd ba]
|
(encrypt [_ typed-pwd ba]
|
||||||
(let [[type pwd] (destructure-typed-pwd typed-pwd)
|
(let [[type pwd] (destructure-typed-pwd typed-pwd)
|
||||||
salt? (identical? type :salted)
|
salt? (identical? type :salted)
|
||||||
iv-ba (rand-bytes aes-iv-size)
|
?salt-ba (when salt? (crypto/rand-bytes 16))
|
||||||
salt-ba (when salt? (rand-bytes salt-size))
|
key-ba
|
||||||
prefix-ba (if salt? (enc/ba-concat iv-ba salt-ba) iv-ba)
|
(crypto/take-ba 16 ; 128 bit AES
|
||||||
key-spec (if salt?
|
(if-let [salt-ba ?salt-ba]
|
||||||
(keyfn salt-ba pwd)
|
(salted-key-fn salt-ba pwd)
|
||||||
(cached-keyfn salt-ba pwd))
|
(cached-key-fn nil pwd)))]
|
||||||
;; param-spec (javax.crypto.spec.GCMParameterSpec. 128 iv-ba)
|
|
||||||
param-spec (javax.crypto.spec.IvParameterSpec. iv-ba)
|
|
||||||
cipher (aes-cipher)]
|
|
||||||
|
|
||||||
(.init cipher javax.crypto.Cipher/ENCRYPT_MODE
|
(crypto/encrypt crypto/cipher-kit-aes-cbc
|
||||||
^javax.crypto.spec.SecretKeySpec key-spec param-spec)
|
?salt-ba key-ba ba)))
|
||||||
(enc/ba-concat prefix-ba (.doFinal cipher ba))))
|
|
||||||
|
|
||||||
(decrypt [_ typed-pwd ba]
|
(decrypt [_ typed-pwd ba]
|
||||||
(let [[type pwd] (destructure-typed-pwd typed-pwd)
|
(let [[type pwd] (destructure-typed-pwd typed-pwd)
|
||||||
salt? (identical? type :salted)
|
salt? (identical? type :salted)
|
||||||
prefix-size (+ aes-iv-size (if salt? salt-size 0))
|
salt->key-fn
|
||||||
[prefix-ba data-ba] (enc/ba-split ba prefix-size)
|
(if salt?
|
||||||
[iv-ba salt-ba] (if salt?
|
#(salted-key-fn % pwd)
|
||||||
(enc/ba-split prefix-ba aes-iv-size)
|
#(cached-key-fn % pwd))]
|
||||||
[prefix-ba nil])
|
|
||||||
key-spec (if salt?
|
|
||||||
(keyfn salt-ba pwd)
|
|
||||||
(cached-keyfn salt-ba pwd))
|
|
||||||
|
|
||||||
;; param-spec (javax.crypto.spec.GCMParameterSpec. 128 iv-ba)
|
(crypto/decrypt crypto/cipher-kit-aes-cbc
|
||||||
param-spec (javax.crypto.spec.IvParameterSpec. iv-ba)
|
(if salt? 16 0) salt->key-fn ba))))
|
||||||
cipher (aes-cipher)]
|
|
||||||
|
|
||||||
(.init cipher javax.crypto.Cipher/DECRYPT_MODE
|
|
||||||
^javax.crypto.spec.SecretKeySpec key-spec param-spec)
|
|
||||||
(.doFinal cipher data-ba))))
|
|
||||||
|
|
||||||
(def aes128-encryptor
|
(def aes128-encryptor
|
||||||
"Default 128bit AES encryptor with many-round SHA-512 key-gen.
|
"Default 128bit AES encryptor with many-round SHA-512 key-gen.
|
||||||
|
|
@ -152,7 +91,9 @@
|
||||||
Faster than `aes128-salted`, and harder to attack any particular key - but
|
Faster than `aes128-salted`, and harder to attack any particular key - but
|
||||||
increased danger if a key is somehow compromised."
|
increased danger if a key is somehow compromised."
|
||||||
|
|
||||||
(AES128Encryptor. :aes128-sha512 sha512-key (enc/memoize_ sha512-key)))
|
(AES128Encryptor. :aes128-sha512
|
||||||
|
(do (fn [ salt-ba pwd] (crypto/take-ba 16 (crypto/sha512-ba salt-ba pwd (* Short/MAX_VALUE 5)))))
|
||||||
|
(enc/memoize_ (fn [_salt-ba pwd] (crypto/take-ba 16 (crypto/sha512-ba nil pwd (* Short/MAX_VALUE 64)))))))
|
||||||
|
|
||||||
;;;; Default implementation
|
;;;; Default implementation
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue