From 59f073a41f701a2f4842f526d03bbcd60b4e5296 Mon Sep 17 00:00:00 2001 From: Paul Rouse Date: Tue, 29 Aug 2017 13:34:20 +0100 Subject: [PATCH 1/3] Pure move of Yesod.PasswordStore to Yesod.Auth.Util.PasswordStore --- yesod-auth/Yesod/{ => Auth/Util}/PasswordStore.hs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename yesod-auth/Yesod/{ => Auth/Util}/PasswordStore.hs (100%) diff --git a/yesod-auth/Yesod/PasswordStore.hs b/yesod-auth/Yesod/Auth/Util/PasswordStore.hs similarity index 100% rename from yesod-auth/Yesod/PasswordStore.hs rename to yesod-auth/Yesod/Auth/Util/PasswordStore.hs From 464b05556822e904951851f715387f77a295490d Mon Sep 17 00:00:00 2001 From: Paul Rouse Date: Tue, 29 Aug 2017 13:40:32 +0100 Subject: [PATCH 2/3] Expose Yesod.Auth.Util.PasswordStore --- yesod-auth/ChangeLog.md | 4 ++++ yesod-auth/Yesod/Auth/Email.hs | 2 +- yesod-auth/Yesod/Auth/Util/PasswordStore.hs | 11 +++-------- yesod-auth/yesod-auth.cabal | 4 ++-- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/yesod-auth/ChangeLog.md b/yesod-auth/ChangeLog.md index dc96c5dd..2a529171 100644 --- a/yesod-auth/ChangeLog.md +++ b/yesod-auth/ChangeLog.md @@ -1,3 +1,7 @@ +## 1.4.18 + +* Expose Yesod.Auth.Util.PasswordStore + ## 1.4.17.3 * Some translation fixes diff --git a/yesod-auth/Yesod/Auth/Email.hs b/yesod-auth/Yesod/Auth/Email.hs index 0c6aa34d..44990a8e 100644 --- a/yesod-auth/Yesod/Auth/Email.hs +++ b/yesod-auth/Yesod/Auth/Email.hs @@ -116,7 +116,7 @@ import Yesod.Auth import qualified Yesod.Auth.Message as Msg import Yesod.Core import Yesod.Form -import qualified Yesod.PasswordStore as PS +import qualified Yesod.Auth.Util.PasswordStore as PS import Control.Applicative ((<$>), (<*>)) import qualified Crypto.Hash as H import qualified Crypto.Nonce as Nonce diff --git a/yesod-auth/Yesod/Auth/Util/PasswordStore.hs b/yesod-auth/Yesod/Auth/Util/PasswordStore.hs index 9e32a48e..7e093db1 100755 --- a/yesod-auth/Yesod/Auth/Util/PasswordStore.hs +++ b/yesod-auth/Yesod/Auth/Util/PasswordStore.hs @@ -1,13 +1,8 @@ {-# LANGUAGE OverloadedStrings, BangPatterns #-} {-# LANGUAGE CPP #-} -- | --- Module : Crypto.PasswordStore --- Copyright : (c) Peter Scott, 2011 --- License : BSD-style --- --- Maintainer : pjscott@iastate.edu --- Stability : experimental --- Portability : portable +-- This is a fork of pwstore-fast, originally copyright (c) Peter Scott, 2011, +-- and released under a BSD-style licence. -- -- Securely store hashed, salted passwords. If you need to store and verify -- passwords, there are many wrong ways to do it, most of them all too @@ -71,7 +66,7 @@ -- iteration count. This does not have a significant effect on security, but can -- be handy for compatibility with other code. -module Yesod.PasswordStore ( +module Yesod.Auth.Util.PasswordStore ( -- * Algorithms pbkdf1, -- :: ByteString -> Salt -> Int -> ByteString diff --git a/yesod-auth/yesod-auth.cabal b/yesod-auth/yesod-auth.cabal index 75339439..839a41d3 100644 --- a/yesod-auth/yesod-auth.cabal +++ b/yesod-auth/yesod-auth.cabal @@ -1,5 +1,5 @@ name: yesod-auth -version: 1.4.17.3 +version: 1.4.18 license: MIT license-file: LICENSE author: Michael Snoyman, Patrick Brisbin @@ -77,8 +77,8 @@ library Yesod.Auth.GoogleEmail Yesod.Auth.GoogleEmail2 Yesod.Auth.Hardcoded + Yesod.Auth.Util.PasswordStore other-modules: Yesod.Auth.Routes - Yesod.PasswordStore ghc-options: -Wall source-repository head From 3c53acdad817539d836e4f3a0a7df9d073841965 Mon Sep 17 00:00:00 2001 From: Paul Rouse Date: Tue, 29 Aug 2017 18:49:21 +0100 Subject: [PATCH 3/3] Add "@since" comments for newly exposed Yesod.Auth.Util.PasswordStore --- yesod-auth/Yesod/Auth/Util/PasswordStore.hs | 51 +++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/yesod-auth/Yesod/Auth/Util/PasswordStore.hs b/yesod-auth/Yesod/Auth/Util/PasswordStore.hs index 7e093db1..1c754732 100755 --- a/yesod-auth/Yesod/Auth/Util/PasswordStore.hs +++ b/yesod-auth/Yesod/Auth/Util/PasswordStore.hs @@ -65,6 +65,8 @@ -- Note that, as of version 2.4, you can also use PBKDF2, and specify the exact -- iteration count. This does not have a significant effect on security, but can -- be handy for compatibility with other code. +-- +-- @since 1.4.18 module Yesod.Auth.Util.PasswordStore ( @@ -126,6 +128,9 @@ import Data.ByteArray (convert) -- key should be stored in the password file. When a user wishes to authenticate -- a password, just pass it and the salt to this function, and see if the output -- matches. +-- +-- @since 1.4.18 +-- pbkdf1 :: ByteString -> Salt -> Int -> ByteString pbkdf1 password (SaltBS salt) iter = hashRounds first_hash (iter + 1) where @@ -156,6 +161,9 @@ hmacSHA256 secret msg = -- @32@ is the most common digest size for @SHA256@, and is -- what the algorithm internally uses. -- @HMAC+SHA256@ is used as @PRF@, because @HMAC+SHA1@ is considered too weak. +-- +-- @since 1.4.18 +-- pbkdf2 :: ByteString -> Salt -> Int -> ByteString pbkdf2 password (SaltBS salt) c = let hLen = 32 @@ -194,6 +202,9 @@ pbkdf2 password (SaltBS salt) c = -- | Generate a 'Salt' from 128 bits of data from @\/dev\/urandom@, with the -- system RNG as a fallback. This is the function used to generate salts by -- 'makePassword'. +-- +-- @since 1.4.18 +-- genSaltIO :: IO Salt genSaltIO = Control.Exception.catch genSaltDevURandom def @@ -247,6 +258,9 @@ writePwHash (strength, SaltBS salt, hash) = -- database. Generates a salt using high-quality randomness from -- @\/dev\/urandom@ or (if that is not available, for example on Windows) -- 'System.Random', which is included in the hashed output. +-- +-- @since 1.4.18 +-- makePassword :: ByteString -> Int -> IO ByteString makePassword = makePasswordWith pbkdf1 @@ -255,6 +269,8 @@ makePassword = makePasswordWith pbkdf1 -- -- >>> makePasswordWith pbkdf1 "password" 14 -- +-- @since 1.4.18 +-- makePasswordWith :: (ByteString -> Salt -> Int -> ByteString) -- ^ The algorithm to use (e.g. pbkdf1) -> ByteString @@ -271,6 +287,9 @@ makePasswordWith algorithm password strength = do -- Note that, unlike 'makePasswordWith', this function takes the @raw@ -- number of iterations. This means the user will need to specify a -- sensible value, typically @10000@ or @20000@. +-- +-- @since 1.4.18 +-- makePasswordSaltWith :: (ByteString -> Salt -> Int -> ByteString) -- ^ A function modeling an algorithm (e.g. 'pbkdf1') -> (Int -> Int) @@ -291,6 +310,9 @@ makePasswordSaltWith algorithm strengthModifier pwd salt strength = writePwHash -- -- > >>> makePasswordSalt "hunter2" (makeSalt "72cd18b5ebfe6e96") 14 -- > "sha256|14|NzJjZDE4YjVlYmZlNmU5Ng==|yuiNrZW3KHX+pd0sWy9NTTsy5Yopmtx4UYscItSsoxc=" +-- +-- @since 1.4.18 +-- makePasswordSalt :: ByteString -> Salt -> Int -> ByteString makePasswordSalt = makePasswordSaltWith pbkdf1 (2^) @@ -307,6 +329,8 @@ makePasswordSalt = makePasswordSaltWith pbkdf1 (2^) -- > >>> verifyPasswordWith pbkdf2 id "hunter2" "sha256..." -- > True -- +-- @since 1.4.18 +-- verifyPasswordWith :: (ByteString -> Salt -> Int -> ByteString) -- ^ A function modeling an algorithm (e.g. pbkdf1) -> (Int -> Int) @@ -323,6 +347,9 @@ verifyPasswordWith algorithm strengthModifier userInput pwHash = encode (algorithm userInput salt (strengthModifier strength)) == goodHash -- | Like 'verifyPasswordWith', but uses 'pbkdf1' as algorithm. +-- +-- @since 1.4.18 +-- verifyPassword :: ByteString -> ByteString -> Bool verifyPassword = verifyPasswordWith pbkdf1 (2^) @@ -336,6 +363,9 @@ verifyPassword = verifyPasswordWith pbkdf1 (2^) -- This function can be used to periodically update your password database when -- computers get faster, in order to keep up with Moore's law. This isn't hugely -- important, but it's a good idea. +-- +-- @since 1.4.18 +-- strengthenPassword :: ByteString -> Int -> ByteString strengthenPassword pwHash newstr = case readPwHash pwHash of @@ -350,6 +380,9 @@ strengthenPassword pwHash newstr = hash = decodeLenient hashB64 -- | Return the strength of a password hash. +-- +-- @since 1.4.18 +-- passwordStrength :: ByteString -> Int passwordStrength pwHash = case readPwHash pwHash of Nothing -> 0 @@ -363,12 +396,18 @@ passwordStrength pwHash = case readPwHash pwHash of -- hash. You can generate a salt with 'genSaltIO' or 'genSaltRandom', or if you -- really know what you're doing, you can create them from your own ByteString -- values with 'makeSalt'. +-- +-- @since 1.4.18 +-- newtype Salt = SaltBS ByteString deriving (Show, Eq, Ord) -- | Create a 'Salt' from a 'ByteString'. The input must be at least 8 -- characters, and can contain arbitrary bytes. Most users will not need to use -- this function. +-- +-- @since 1.4.18 +-- makeSalt :: ByteString -> Salt makeSalt = SaltBS . encode . check_length where check_length salt | B.length salt < 8 = @@ -377,17 +416,26 @@ makeSalt = SaltBS . encode . check_length -- | Convert a 'Salt' into a 'ByteString'. The resulting 'ByteString' will be -- base64-encoded. Most users will not need to use this function. +-- +-- @since 1.4.18 +-- exportSalt :: Salt -> ByteString exportSalt (SaltBS bs) = bs -- | Convert a raw 'ByteString' into a 'Salt'. -- Use this function with caution, since using a weak salt will result in a -- weak password. +-- +-- @since 1.4.18 +-- importSalt :: ByteString -> Salt importSalt = SaltBS -- | Is the format of a password hash valid? Attempts to parse a given password -- hash. Returns 'True' if it parses correctly, and 'False' otherwise. +-- +-- @since 1.4.18 +-- isPasswordFormatValid :: ByteString -> Bool isPasswordFormatValid = isJust . readPwHash @@ -395,6 +443,9 @@ isPasswordFormatValid = isJust . readPwHash -- generator. Returns the salt and the updated random number generator. This is -- meant to be used with 'makePasswordSalt' by people who would prefer to either -- use their own random number generator or avoid the 'IO' monad. +-- +-- @since 1.4.18 +-- genSaltRandom :: (RandomGen b) => b -> (Salt, b) genSaltRandom gen = (salt, newgen) where rands _ 0 = []