2 | import public Data.DPair
10 | %foreign "C:idris_gensalt,libcrypt-idris"
11 | prim__gensalt : String -> Bits32 -> PrimIO String
13 | %foreign "C:idris_crypt,libcrypt-idris"
14 | prim__crypt : String -> String -> String
16 | %foreign "C:idris_checksalt,libcrypt-idris"
17 | prim__checksalt : String -> Int
19 | %foreign "C:idris_checkphrase,libcrypt-idris"
20 | prim__checkphrase : String -> Int
22 | %foreign "C:idris_crypt_check,libcrypt-idris"
23 | prim__cryptcheck : String -> String -> Int
35 | data SaltQuality = OK | Invalid | Legacy
38 | Eq SaltQuality where
40 | Invalid == Invalid = True
41 | Legacy == Legacy = True
45 | Show SaltQuality where
47 | show Invalid = "Invalid"
48 | show Legacy = "Legacy"
60 | Eq CryptMethod where
61 | YesCrypt == YesCrypt = True
62 | GhostYesCrypt == GhostYesCrypt = True
63 | SCrypt == SCrypt = True
64 | BCrypt == BCrypt = True
65 | SHA512Crypt == SHA512Crypt = True
66 | SHA256Crypt == SHA256Crypt = True
70 | Show CryptMethod where
71 | show YesCrypt = "YesCrypt"
72 | show GhostYesCrypt = "GhostYesCrypt"
73 | show SCrypt = "SCrypt"
74 | show BCrypt = "BCrypt"
75 | show SHA512Crypt = "SHA512Crypt"
76 | show SHA256Crypt = "SHA256Crypt"
79 | cryptPrefix : CryptMethod -> String
80 | cryptPrefix YesCrypt = "$y$"
81 | cryptPrefix GhostYesCrypt = "$gy$"
82 | cryptPrefix SCrypt = "$7$"
83 | cryptPrefix BCrypt = "$2b$"
84 | cryptPrefix SHA512Crypt = "$6$"
85 | cryptPrefix SHA256Crypt = "$5$"
93 | MinCost : CryptMethod -> Bits32
94 | MinCost YesCrypt = 1
95 | MinCost GhostYesCrypt = 1
98 | MinCost SHA512Crypt = 1000
99 | MinCost SHA256Crypt = 1000
107 | MaxCost : CryptMethod -> Bits32
108 | MaxCost YesCrypt = 11
109 | MaxCost GhostYesCrypt = 11
110 | MaxCost SCrypt = 11
111 | MaxCost BCrypt = 31
112 | MaxCost SHA512Crypt = 999999999
113 | MaxCost SHA256Crypt = 999999999
118 | 0 InRange : CryptMethod -> (cost : Bits32) -> Type
119 | InRange cm c = (MinCost cm <= c && c <= MaxCost cm) === True
125 | checkphrase : (phrase : String) -> Bool
126 | checkphrase phrase = prim__checkphrase phrase /= 0
131 | 0 Passphrase : Type
132 | Passphrase = Subset String (\x => checkphrase x === True)
137 | refinePassphrase : String -> Maybe Passphrase
138 | refinePassphrase str with (checkphrase str) proof eq
139 | _ | True = Just (Element str eq)
140 | _ | False = Nothing
149 | checksalt : (salt : String) -> SaltQuality
150 | checksalt salt = case prim__checksalt salt of
159 | Salt = Subset String (\x => checksalt x === OK)
164 | Hash = Subset String (\x => checksalt x === OK)
169 | refineSalt : String -> Maybe Salt
170 | refineSalt str with (checksalt str) proof eq
171 | _ | OK = Just (Element str eq)
176 | refineHash : String -> Maybe Hash
177 | refineHash = refineSalt
193 | -> {auto 0 prf : InRange cm cost}
195 | gensalt cm cost = fromPrim (go 100)
198 | go : Nat -> PrimIO String
199 | go Z w = prim__gensalt (cryptPrefix cm) cost w
201 | let MkIORes str w2 := prim__gensalt (cryptPrefix cm) cost w
202 | in case checksalt str of
204 | _ => MkIORes str w2
211 | cryptWithSalt : Salt -> Passphrase -> String
212 | cryptWithSalt (Element s _) (Element p _) = prim__crypt s p
221 | -> (phrase : Passphrase)
222 | -> {auto 0 p1 : InRange cm cost}
224 | crypt cm cost (Element p _) = do
225 | salt <- gensalt cm cost
226 | pure $
prim__crypt salt p
237 | -> (phrase : String)
238 | -> {auto 0 p1 : InRange cm cost}
240 | cryptMaybe cm cost phrase = do
241 | Just pp <- pure (refinePassphrase phrase) | Nothing => pure Nothing
242 | hash <- crypt cm cost pp
243 | pure (refineHash hash)
250 | cryptcheck : Hash -> String -> Bool
251 | cryptcheck (Element h _) str =
252 | let Just (Element p _) := refinePassphrase str | Nothing => False
253 | in prim__cryptcheck h p == 0