Skip to content
Browse files

Added pbkdf password hash convenience functions, documentation, re-en…

…abled pkcs5 unit tests.
  • Loading branch information...
1 parent abb9b35 commit 3372482396d703e2765b6665a0aa5cbb1c0b4bda @vsedach vsedach committed with May 2, 2011
Showing with 62 additions and 5 deletions.
  1. +42 −0 doc/ironclad-doc.txt
  2. +2 −0 ironclad.asd
  3. +5 −0 src/package.lisp
  4. +6 −3 src/pkcs5.lisp
  5. +7 −2 testing/test-vectors/pkcs5.lisp
View
42 doc/ironclad-doc.txt
@@ -425,6 +425,43 @@ passed to " @make-hmac " when " 'hmac' " was constructed.")
@insufficient-buffer-space " error will be signaled if there is
insufficient space in " 'buffer' ".")
+(:h3 "PBKDF")
+
+(:p "Ironclad comes with the basic PBKDF1 and PBKDF2 algorithms, as
+well as convenience functions for using them to store passwords.")
+
+(:describe :function (ironclad:derive-key kdf passphrase salt
+iteration-count key-length))
+
+(:p "Given a key derivation function object (produced by " `make-kdf`
+"), a password and salt (both must be of type " `(SIMPLE-ARRAY
+(UNSIGNED-BYTE 8) (*))` "), and number of digest iterations, returns
+the password digest as a byte array of length " 'key-length' ".")
+
+(:describe :function (ironclad:make-kdf kind))
+
+(:p "Returns a key derivation function instance (" 'kind' " must
+either be " 'pbkdf1' " or " 'pbkdf2' ") that uses the given "
+'digest' ".")
+
+(:describe :function (ironclad:pbkdf2-hash-password password))
+
+(:p "Convenience function for hashing passwords using the PBKDF2
+algorithm. Returns the derived hash of the password, and the original
+salt, as byte vectors.")
+
+(:describe :function (ironclad:pbkdf2-hash-password-to-combined-string password))
+
+(:p "Convenience function for hashing passwords using the PBKDF2
+algorithm. Returns the derived hash of the password as a single string
+that encodes the given salt and PBKDF2 algorithm parameters.")
+
+(:describe :function (ironclad:pbkdf2-check-password password combined-salt-and-digest))
+
+(:p "Given a " 'password' " byte vector and a combined salt and digest string
+produced by " `pbkdf2-hash-password-to-combined-string` ", checks whether
+the password is valid.")
+
(:h3 "CMACs")
(:p "Instances of CMACs are constructed by specifying a secret key and a
@@ -642,6 +679,11 @@ in the resulting number.")
(:p "Raises " 'n' " to the " 'exponent' " power modulo " 'modulus' " in
a more efficient fashion than " `(MOD (EXPT N EXPONENT) MODULUS)` ".")
+(:describe :function (ironclad:make-random-salt size))
+
+(:p "Generate a byte vector of " 'size' " (default 16) random bytes, suitable
+for use as a password salt.")
+
(:h2 "Conditions")
(:describe :condition ironclad-error)
View
2 ironclad.asd
@@ -49,6 +49,7 @@
(:file "octet-stream" :depends-on ("common"))
(:file "padding" :depends-on ("common"))
(:file "pkcs5" :depends-on ("common"))
+ (:file "password-hash" :depends-on ("pkcs5"))
(:module "sbcl-opt"
:depends-on ("package" "common")
:components
@@ -210,6 +211,7 @@
(:file "ciphers")
(:file "digests")
(:file "padding")
+ (:file "pkcs5")
(:file "ironclad")
;; test vectors
(:test-vector-file "crc24")
View
5 src/package.lisp
@@ -31,6 +31,11 @@
#:pbkdf1 #:pbkdf2
#:make-kdf #:derive-key
+ ;; KDF convenience functions
+ #:make-random-salt #:pbkdf2-hash-password
+ #:pbkdf2-hash-password-to-combined-string
+ #:pbkdf2-check-password
+
;; public-key encryption operations
#:make-public-key #:make-private-key
#:sign-message #:verify-signature
View
9 src/pkcs5.lisp
@@ -55,14 +55,14 @@
(defclass pbkdf2 ()
((digest-name :initarg :digest :reader kdf-digest)))
-(defmethod derive-key ((kdf pbkdf2) passphrase salt iteration-count key-length)
+(defun pbkdf2-derive-key (digest passphrase salt iteration-count key-length)
(unless (plusp iteration-count)
(error 'invalid-argument))
(unless (plusp (length passphrase))
(error 'invalid-argument))
(loop with count = 1
- with hmac = (make-hmac passphrase (kdf-digest kdf))
- with hmac-length = (digest-length (kdf-digest kdf))
+ with hmac = (make-hmac passphrase digest)
+ with hmac-length = (digest-length digest)
with key = (make-array key-length :element-type '(unsigned-byte 8)
:initial-element 0)
with key-position = 0
@@ -88,6 +88,9 @@
(incf count)))
finally (return key)))
+(defmethod derive-key ((kdf pbkdf2) passphrase salt iteration-count key-length)
+ (pbkdf2-derive-key (kdf-digest kdf) passphrase salt iteration-count key-length))
+
(defun make-kdf (kind &key digest)
;; PBKDF1, at least, will do stricter checking; this is good enough for now.
(unless (digestp digest)
View
9 testing/test-vectors/pkcs5.lisp
@@ -23,7 +23,7 @@
'(vector (unsigned-byte 8))))
(rtest:deftest pbkdf1
- (run-kdf-test (crypto:make-kdf 'crypto:pbkdf1 :digest :sha1)
+ (run-kdf-test (crypto:make-kdf 'crypto:pbkdf1 :digest 'ironclad:sha1)
*password* *salt* 1000 16 *pbkdf1-key*)
t)
@@ -46,7 +46,12 @@
'(vector (unsigned-byte 8))))
(rtest:deftest pbkdf2
- (run-kdf-test (crypto:make-kdf 'crypto:pbkdf2 :digest :sha1)
+ (run-kdf-test (crypto:make-kdf 'crypto:pbkdf2 :digest 'ironclad:sha1)
*password* *salt* 2048 24 *pbkdf2-key*)
t)
+(rtest:deftest pbkdf2-convenience
+ (ironclad:pbkdf2-check-password
+ *password*
+ "PBKDF2$SHA256:1000$78578e5a5d63cb06$aa2ae650dc866dc4de4fc3c8f06eddac1abc3011a99402fbc46d7e131fac06d5")
+ t)

0 comments on commit 3372482

Please sign in to comment.
Something went wrong with that request. Please try again.