pbkdf (empty) → 1.0.0.0
raw patch · 7 files changed
+328/−0 lines, 7 filesdep +basedep +binarydep +byteablesetup-changed
Dependencies added: base, binary, byteable, bytedump, bytestring, cryptohash, pbkdf, utf8-string
Files
- Crypto/PBKDF.hs +49/−0
- Crypto/PBKDF/Core.hs +137/−0
- LICENSE +27/−0
- README.md +5/−0
- Setup.hs +6/−0
- pbkdf.cabal +58/−0
- rfc6070.hs +46/−0
+ Crypto/PBKDF.hs view
@@ -0,0 +1,49 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE RecordWildCards #-}++module Crypto.PBKDF + ( sha1PBKDF1+ , sha256PBKDF1+ , sha512PBKDF1+ , sha1PBKDF2+ , sha256PBKDF2+ , sha512PBKDF2+ ) where++import Crypto.PBKDF.Core+import Text.Bytedump+++-- | Password Based Key Derivation Functions:+-- This module provides stock implementations of the PBKDF functions from+-- RFC-2898 based on the SHA-1, SHA-256 and SHA-256 hash functions. Each+-- function takes the password and salt as a string and returns a hex+-- string. To work with ByteStrings and provide your own hash and+-- psuedo-random use the Crypto.PBKDF.Core that are used to implement+-- these functions.+++-- | SHA-based PBKDF1 functions++sha1PBKDF1, sha256PBKDF1, sha512PBKDF1 + :: String -- ^ the password (will be encoded with UTF-8) + -> String -- ^ the salt (will be encoded with UTF-8)+ -> Int -- ^ the iteration count+ -> String -- ^ the result key as a hex string+sha1PBKDF1 pw_s na_s c = dumpRawBS $ pbkdf1_ $ sha1PBKDF pw_s na_s c 0+sha256PBKDF1 pw_s na_s c = dumpRawBS $ pbkdf1_ $ sha256PBKDF pw_s na_s c 0+sha512PBKDF1 pw_s na_s c = dumpRawBS $ pbkdf1_ $ sha512PBKDF pw_s na_s c 0+++-- | SHA-based PBKDF2 functions++sha1PBKDF2, sha256PBKDF2, sha512PBKDF2+ :: String -- ^ the password (will be encoded with UTF-8) + -> String -- ^ the salt (will be encoded with UTF-8)+ -> Int -- ^ the iteration count+ -> Int -- ^ the length of the key to be generated (in octets)+ -> String -- ^ the result key as a hex string++sha1PBKDF2 pw_s na_s c dkLen = dumpRawBS $ pbkdf2_ $ sha1PBKDF pw_s na_s c dkLen+sha256PBKDF2 pw_s na_s c dkLen = dumpRawBS $ pbkdf2_ $ sha256PBKDF pw_s na_s c dkLen+sha512PBKDF2 pw_s na_s c dkLen = dumpRawBS $ pbkdf2_ $ sha512PBKDF pw_s na_s c dkLen
+ Crypto/PBKDF/Core.hs view
@@ -0,0 +1,137 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE RecordWildCards #-}++module Crypto.PBKDF.Core+ ( sha1PBKDF+ , sha256PBKDF+ , sha512PBKDF+ , pbkdf+ , PBKDF(..)+ , PRF(..)+ , pbkdf1_+ , pbkdf2_+ ) where++import qualified Data.Binary as B+import Data.Bits+import qualified Data.ByteString as BS+import qualified Data.ByteString.UTF8 as BU+import qualified Data.ByteString.Lazy as BLC+import qualified Crypto.Hash as CH+import Crypto.MAC.HMAC+import Data.Byteable+++-- | SHA-1 generator++sha1PBKDF :: String -> String -> Int -> Int -> PBKDF+sha1PBKDF =+ pbkdf+ PRF+ { prf_hmac = hmac sha1 64 -- 512-bit block+ , prf_hash = sha1 -- SHA-1+ , prf_hLen = 20 -- 160-bit hash+ } + where+ sha1 = toBytes . (CH.hash :: BS.ByteString -> CH.Digest CH.SHA1)++-- | SHA-256 generator++sha256PBKDF :: String -> String -> Int -> Int -> PBKDF+sha256PBKDF =+ pbkdf+ PRF+ { prf_hmac = hmac sha256 64 -- 512-bit block+ , prf_hash = sha256 -- SHA-256+ , prf_hLen = 32 -- 256-bit hash+ } + where+ sha256 = toBytes . (CH.hash :: BS.ByteString -> CH.Digest CH.SHA256)++-- | SHA-512 generator++sha512PBKDF :: String -> String -> Int -> Int -> PBKDF+sha512PBKDF =+ pbkdf+ PRF+ { prf_hmac = hmac sha512 128 -- 1024-bit block+ , prf_hash = sha512 -- SHA-512+ , prf_hLen = 64 -- 512-bit hash+ } + where+ sha512 = toBytes . (CH.hash :: BS.ByteString -> CH.Digest CH.SHA512)++-- | construct a PBKDF generator from a HMAC function++pbkdf :: PRF -> String -> String -> Int -> Int -> PBKDF+pbkdf prf pw_s na_s c dkLen =+ PBKDF+ { pbkdf_PRF = prf+ , pbkdf_P = BU.fromString pw_s+ , pbkdf_S = BU.fromString na_s+ , pbkdf_c = c+ , pbkdf_dkLen = dkLen+ }++-- | PBKDF generator parameters++data PBKDF+ = PBKDF+ { pbkdf_PRF :: PRF -- ^ the psuedo-random (i.e., HMAC) function+ , pbkdf_P :: BS.ByteString -- ^ the password (will be UTF-8 encoded)+ , pbkdf_S :: BS.ByteString -- ^ the salt (will be UTF-8 encoded)+ , pbkdf_c :: Int -- ^ iteration count for applying the HMAC+ , pbkdf_dkLen :: Int -- ^ the length of the o/p derived key + }++-- | the HMAC function and its underlying HASH function++data PRF+ = PRF+ { prf_hmac :: BS.ByteString -> BS.ByteString -> BS.ByteString -- ^ the PR/HMAC function+ , prf_hash :: BS.ByteString -> BS.ByteString -- ^ the underlying hash function+ , prf_hLen :: Int -- ^ number of octets in o/p hash+ } +++-- | the pbkdf1_ core function++pbkdf1_ :: PBKDF -> BS.ByteString+pbkdf1_ PBKDF{..} = iterate_n pbkdf_c prf_hash $ pbkdf_P `BS.append` pbkdf_S+ where+ PRF{..} = pbkdf_PRF++-- | the pbkdf2_ core function++pbkdf2_ :: PBKDF -> BS.ByteString+pbkdf2_ PBKDF{..} = BS.take pbkdf_dkLen $ BS.concat $ map f $ zip zbs ivs+ where+ f (zb,iv) = snd $ itr zb $ pbkdf_S `BS.append` iv++ itr zb msg = iterate_n pbkdf_c g (msg,zb)++ g (!u,!p) = (u',BS.pack $ BS.zipWith xor p u')+ where+ u' = prf_hmac pbkdf_P u++ r = pbkdf_dkLen - (l - 1) * prf_hLen++ l = ceiling $ (fromIntegral pbkdf_dkLen :: Double) / fromIntegral prf_hLen+ + zbs = replicate l (mk_zb prf_hLen) ++ [mk_zb r]+ + mk_zb sz = BS.pack $ replicate sz 0++ PRF{..} = pbkdf_PRF++ ivs = [ BS.pack $ drop (length os - 4) os | bno<-bnos, let os = BLC.unpack $ B.encode bno ]+ where+ bnos = [1..] :: [Int]++-- iterate a function over an argument k times++iterate_n :: Int -> (a->a) -> a -> a+iterate_n !i f !x =+ case i of+ 0 -> x+ _ -> iterate_n (i-1) f $ f x
+ LICENSE view
@@ -0,0 +1,27 @@+Copyright 2001-2005, Chris Dornan++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++- Redistributions of source code must retain the above copyright notice,+this list of conditions and the following disclaimer.+ +- Redistributions in binary form must reproduce the above copyright notice,+this list of conditions and the following disclaimer in the documentation+and/or other materials provided with the distribution.+ +- The name of the authors may not be used to endorse or promote products+derived from this software without specific prior written permission. ++THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE+THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,+OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER+IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF+THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,5 @@+pbkdf+=====++The Password Based Key Derivation Functions described in RFC 2898 with+a test suite based on the test vectors published in RFC6070.
+ Setup.hs view
@@ -0,0 +1,6 @@+module Main (main) where++import Distribution.Simple++main :: IO ()+main = defaultMain
+ pbkdf.cabal view
@@ -0,0 +1,58 @@+Name: pbkdf+Version: 1.0.0.0+Synopsis: Haskell implementation of the PBKDF functions from RFC-2898.+Description: The Password Based Key Derivation Functions described in RFC-2898 with a test suite to verify that it works with the test vectors published in RFC6070.+Homepage: https://github.com/cdornan/pbkdf+License: BSD3+License-file: LICENSE+Author: Chris Dornan+Maintainer: chris.dornan@irisconnect.com+Copyright: (C) Chris Dornan+Category: Cryptography+Build-type: Simple++Cabal-version: >=1.14++Source-repository this+ type: git+ location: https://github.com/cdornan/pbkdf.git+ tag: 1.0.0.0++Source-repository head+ type: git+ location: https://github.com/cdornan/pbkdf.git++Library+ Exposed-modules:+ Crypto.PBKDF+ Crypto.PBKDF.Core++ Build-depends:+ base >= 4.5 && < 5.0 ,+ binary >= 0.5 ,+ byteable >= 0.1 ,+ bytedump >= 1.0 ,+ bytestring >= 0.9 ,+ cryptohash >= 0.10 ,+ utf8-string >= 0.3.7+ + GHC-Options: -Wall++ Default-Language: Haskell2010++Test-Suite rfc-6070+ type: exitcode-stdio-1.0+ main-is: rfc6070.hs+ Build-depends:+ base >= 4.5 ,+ binary >= 0.5 ,+ byteable >= 0.1 ,+ bytedump >= 1.0 ,+ bytestring >= 0.9 ,+ cryptohash >= 0.10 ,+ pbkdf ,+ utf8-string >= 0.3.7++ GHC-Options: -Wall++ Default-Language: Haskell2010
+ rfc6070.hs view
@@ -0,0 +1,46 @@++import Crypto.PBKDF+import Text.Printf+import Control.Applicative+import System.Exit+++main :: IO ()+main = + do ok <- run_tests+ case ok of+ True -> return ()+ False -> exitWith $ ExitFailure 1++run_tests :: IO Bool+run_tests = and <$> mapM test test_vectors+ where+ test (pw,na,c,out) =+ do putStr $ printf "%-30s %-40s %8d (%d) : " (show pw) (show na) c dkl+ case ok of+ True -> putStrLn "passed"+ False -> putStrLn $ printf "FAILED (%s[%d])" t_out (length t_out)+ return ok+ where+ ok = t_out == out+ t_out = sha1PBKDF2 pw na c dkl+ dkl = length out `div` 2++-- RFC6070 test vectors++test_vectors :: [(String,String,Int,String)]+test_vectors = + [ (,,,) "password" "salt" 1 "0c60c80f961f0e71f3a9b524af6012062fe037a6"+ , (,,,) "password" "salt" 2 "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957"+ , (,,,) "password" "salt" 4096 "4b007901b765489abead49d926f721d065a429c1"+ , (,,,) "password" "salt" 16777216 "eefe3d61cd4da4e4e9945b3d6ba2158c2634e984"+ , (,,,) "passwordPASSWORDpassword" "saltSALTsaltSALTsaltSALTsaltSALTsalt" 4096 "3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038"+ , (,,,) "pass\0word" "sa\0lt" 4096 "56fa6aa75548099dcc37d7f03425e0c3"+ ]++--simple_test :: IO ()+--simple_test = putStrLn $ sha1PBKDF2 "password" "salt" 4096 20++--sha256_test :: IO ()+--sha256_test = putStrLn $ sha256PBKDF2 "password" "salt" 1000000 32+