wordpass (empty) → 0.1.0.0
raw patch · 5 files changed
+165/−0 lines, 5 filesdep +basedep +containersdep +directorysetup-changed
Dependencies added: base, containers, directory, random-fu, random-source, text, vector
Files
- LICENSE +30/−0
- README.md +7/−0
- Setup.hs +2/−0
- WordPass.hs +101/−0
- wordpass.cabal +25/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2014, Michal J. Gajda++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.++ * Neither the name of Michal J. Gajda nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"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 COPYRIGHT+OWNER OR CONTRIBUTORS 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,7 @@+WordPass+========++Dictionary-based password generator.++Uses dictionaries from /usr/share/dict by default.+You might want to look and change the code, since it is not intended as CLI yet :-).
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ WordPass.hs view
@@ -0,0 +1,101 @@+-- | Main module generating passwords.+module Main where++import System.Directory(getDirectoryContents)+import qualified Data.Text as Text+import qualified Data.Text.IO as Text+import Data.Text(Text)+import qualified Data.Set as Set+import Data.Char (isAlpha, isPunctuation, isSymbol)+import Data.Random.RVar+import Data.Random.Sample+import Data.Random.RVar.Enum+import Data.Random.Distribution+import Data.Random.Distribution.Uniform+import Data.Random.Source.IO+import qualified Data.Vector as V+import Control.Applicative+import Control.Monad (replicateM, foldM)++-- | Reads a dict format to get a list of unique words without any special+-- chars.+readDict :: FilePath -> IO (V.Vector Text)+readDict filename = do+ input <- Text.readFile filename+ return $! V.fromList . Set.toList . Set.fromList . map stripTails . Text.lines $! input+ where+ stripTails = head . Text.split (not . isAlpha)++-- | Find all plausible dictionaries in a given directory+dictFiles dir = postprocess `fmap`+ getDirectoryContents dir+ where+ postprocess = map ((dir ++ "/") ++) . filter (not . (=='.') . head)++-- | Default directory where to look for the word lists.+defaultDictDir :: FilePath+defaultDictDir = "/usr/share/dict"++-- | Read a set of dictionaries and put the together.+readDicts filenames = (V.fromList . Set.toList) `fmap` foldM action Set.empty filenames+ where+ action currentSet filename = do newSet <- readDict filename+ return $! Set.fromList (V.toList newSet) `Set.union` currentSet++-- | Read all dictionaries from a given directory.+readDictDir dirname = dictFiles dirname >>= readDicts++-- | Filename for default dictionary (should be command line argument or default glob.)+defaultDictionary :: FilePath+defaultDictionary = "/usr/share/dict/british-english"++-- | Take a random element of a vector.+randomElement :: V.Vector a -> RVar a+randomElement words = (words V.!) <$> uniform 0 (V.length words - 1)++-- | Pick a random password, given a words list, and a number of words it will contain.+randomPassword :: V.Vector Text -> Int -> RVar Text+randomPassword words numWords = do ws <- replicateM numWords $ randomElement words+ seps <- replicateM numWords randomSeparator+ return $ Text.concat $ zipWith Text.append ws seps++-- | Estimate strength of random password with given inputs.+randomPasswordStrength words numWords = fromIntegral numWords * logBase 2 wordStrength+ where+ wordStrength = fromIntegral $ V.length words * (32 + 100)++-- * Random separators+-- | Randomly pick a word separator as a two-digit number, or a symbol+-- character.+randomSeparator :: RVar Text+randomSeparator = do b <- uniform False True+ if b then symbolSeparator+ else numericSeparator++-- | Two-digit number as a separator 10^2 = 6.6 bits of entropy.+numericSeparator :: RVar Text+numericSeparator = Text.pack <$> show <$> uniform 0 (99 :: Int)++-- | Conjunction of two unary predicates+(|||) :: (t -> Bool) -> (t -> Bool) -> t -> Bool+(|||) f g x = f x || g x++-- | List of symbol and punctuation characters in ASCII+-- Should be 5 bits of entropy+symbolChars :: V.Vector Char+symbolChars = V.fromList $ filter (isSymbol ||| isPunctuation) $ map toEnum [0..127]++-- | Text with random symbol character, 5 bits of entropy+symbolSeparator :: RVar Text+symbolSeparator = Text.singleton <$> randomElement symbolChars++main = do dictWords <- readDictDir defaultDictDir+ --print $ V.length dictWords+ putStr "Estimated password strength (bits): "+ print $ randomPasswordStrength dictWords numWs+ replicateM 5 $ do + rv <- sample $ randomPassword dictWords numWs+ Text.putStrLn rv+ where+ numWs = 5+
+ wordpass.cabal view
@@ -0,0 +1,25 @@+-- Initial wordpass.cabal generated by cabal init. For further +-- documentation, see http://haskell.org/cabal/users-guide/++name: wordpass+version: 0.1.0.0+synopsis: Dictionary-based password generator+-- description: +homepage: https://github.com/mjgajda/wordpass+license: BSD3+license-file: LICENSE+author: Michal J. Gajda+maintainer: mjgajda@gmail.com+-- copyright: +category: System+build-type: Simple+extra-source-files: README.md+cabal-version: >=1.10++executable wordpass+ main-is: WordPass.hs+ -- other-modules: Data.Random.RVar.Enum + other-extensions: OverlappingInstances, MultiParamTypeClasses, FlexibleInstances+ build-depends: base >=4.6 && <4.7, text >=1.1 && <1.2, containers >=0.5 && <0.6, random-fu >=0.2 && <0.3, random-source >=0.3 && <0.4, vector >=0.10 && <0.11, directory >= 1.2 && < 1.4+ -- hs-source-dirs: + default-language: Haskell2010