 
 (defmethod parse-password :scrypt
   [encryptedpassword]
-  (let [[algorithm salt cc mc pll password] (str/split encryptedpassword #"\$")
-        algorithm (keyword algorithm)]
-    {:algorithm algorithm
+  (let [[alg salt cc mc pll password] (str/split encryptedpassword #"\$")
+        alg (keyword alg)]
+    {:alg alg
      :salt (hex->bytes salt)
      :password (hex->bytes password)
      :cpucost (Integer/parseInt cc)

        (first)
        (keyword))))

(defmulti derive-password
  "Derive key depending on algorithm."
  :algorithm)

(defmulti check-password
  "Password verification implementation."
  :algorithm)

(defmulti format-password
  "Format password depending on algorithm."
  :algorithm)

(defmulti must-update?
  "Check if the current password configuration
  is succeptible to be updatable."
  :algorithm)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Key Derivation
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defmethod derive-password :pbkdf2+sha1
  [{:keys [algorithm password salt iterations] :as pwdparams}]
  (let [salt (->byte-array (or salt (nonce/random-bytes 12)))
        iterations (or iterations (get *default-iterations* algorithm))
        pgen (doto (PKCS5S2ParametersGenerator. (SHA1Digest.))
               (.init password salt iterations))
        password (.getKey (.generateDerivedParameters pgen 160))]
    {:algorithm algorithm
     :password password
     :salt salt
     :iterations iterations}))

(defmethod derive-password :pbkdf2+sha256
  [{:keys [algorithm password salt iterations] :as pwdparams}]
  (let [salt (->byte-array (or salt (nonce/random-bytes 12)))
        iterations (or iterations (get *default-iterations* algorithm))
        pgen (doto (PKCS5S2ParametersGenerator. (SHA256Digest.))
               (.init password salt iterations))
        password (.getKey (.generateDerivedParameters pgen 160))]
    {:algorithm algorithm
     :password password
     :salt salt
     :iterations iterations}))

(defmethod derive-password :pbkdf2+sha3_256
  [{:keys [algorithm password salt iterations] :as pwdparams}]
  (let [salt (->byte-array (or salt (nonce/random-bytes 12)))
        iterations (or iterations (get *default-iterations* algorithm))
        pgen (doto (PKCS5S2ParametersGenerator. (SHA3Digest. 256))
               (.init password salt iterations))
        password (.getKey (.generateDerivedParameters pgen 256))]
    {:algorithm algorithm
     :password password
     :salt salt
     :iterations iterations}))

(defmethod derive-password :bcrypt+sha512
  [{:keys [algorithm password salt iterations] :as pwdparams}]
  (let [salt (->byte-array (or salt (nonce/random-bytes 12)))
        iterations (or iterations (get *default-iterations* algorithm))
        iv (BCrypt/gensalt iterations)
        pwd (-> password
                (bytes/concat salt)

    (format "scrypt$%s$%s$%s$%s$%s" salt cpucost memcost parallelism password)))

(defmethod format-password :default
  [{:keys [alg password salt iterations]}]
  (let [algname (name alg)
        salt (bytes->hex salt)
        password (bytes->hex password)]
    (if (nil? iterations)
      (format "%s$%s$%s" algname salt password)
      (format "%s$%s$%s$%s" algname salt iterations password))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Key Parsing
