(in-package :cl-password) (defparameter *prng* (make-prng :fortuna :seed :urandom)) (defun make-random-salt (&optional (size 16)) (random-data size *prng*)) (defun generate-password-hash-scrypt (password salt hash-length n r p) (byte-array-to-hex-string (derive-key (make-kdf 'scrypt-kdf :n n :r r :p p) (ascii-string-to-byte-array password) salt 0 ; ignored for scrypt hash-length))) (define-condition unsupported-hash-error (error) ((name :initarg :name :reader name))) (defun hash-password (password type &key (hash-length 40) (n 2048) (r 1) (p 1) (salt (make-random-salt))) (when (typep salt 'string) (setf salt (hex-string-to-byte-array salt))) (cond ((eq type :scrypt) (list :type type :salt (byte-array-to-hex-string salt) :n n :r r :p p :hash-length hash-length :hash (generate-password-hash-scrypt password salt hash-length n r p))) (t (error 'unsupported-hash-error :name type)))) (defun check-password (password hashed-password-plist) (equalp (getf (hash-password password (getf hashed-password-plist :type) :hash-length (getf hashed-password-plist :hash-length) :n (getf hashed-password-plist :n) :r (getf hashed-password-plist :r) :p (getf hashed-password-plist :p) :salt (getf hashed-password-plist :salt)) :hash) (getf hashed-password-plist :hash)))