2018.12.21 追記:PBKDF2とbcryptのサンプルも追加しました。パスワードハッシュ化目的ならとりあえずBcryptを使っておくのが良さそう。
haskellのcryptoniteパッケージの、Crypto.Hashを試しました。
cryptonite全般については、ここに説明があります。
使えるアルゴリズムはCrypto.Hash.Algorithmsに定義されています。
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeSynonymInstances #-}
module Main where
import Data.ByteArray (ByteArrayAccess)
import Data.ByteString (ByteString)
import Crypto.Hash
import Crypto.KDF.BCrypt (hashPassword, validatePassword, validatePasswordEither)
import Crypto.KDF.PBKDF2 (Parameters(..), fastPBKDF2_SHA256)
main :: IO ()
main = do
let password = "password" :: ByteString
putStrLn "SHA-1"
print $ sha1 password
putStrLn "SHA-2-256"
print $ sha2 password
putStrLn "SHA-3-256"
print $ sha3 password
putStrLn "SHA-3-256, 1000 times"
print $ hashnWith SHA3_256 1000 password
putStrLn "PBKDF2"
let
params = Parameters 4000 256
pass = "pass" :: ByteString
salt = "salt" :: ByteString
print (fastPBKDF2_SHA256 params pass salt :: ByteString)
putStrLn "Bcrypt"
passHash <- hashPassword 12 password :: IO ByteString
print passHash
print $ validatePassword password passHash
print $ validatePasswordEither password passHash
print $ validatePassword ("wrong password" :: ByteString) passHash
print $ validatePasswordEither ("wrong password" :: ByteString) passHash
sha1 :: ByteString -> Digest SHA1
sha1 = hash
sha2 :: ByteString -> Digest SHA256
sha2 = hash
sha3 :: ByteString -> Digest SHA3_256
sha3 = hash
hashnWith :: (ByteArrayAccess bs, HashAlgorithm alg) => alg -> Int -> bs -> Digest alg
hashnWith alg n s
| n < 1 = error "n must be equal to 1 or greater"
| n == 1 = hashWith alg s
| otherwise = hashnWith alg (n-1) (hashWith alg s)
実行結果
$ stack runghc sample.hs
SHA-1
5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8
SHA-2-256
5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8
SHA-3-256
c0067d4af4e87f00dbac63b6156828237059172d1bbeac67427345d6a9fda484
SHA-3-256, 1000 times
bd4a6cec6ec9bd37ed32bdd179ebe2c419ea4ca19d472f78bcc29ce8da63c62f
PBKDF2
"8\209\167\171y\246\245e\219\166\183\SO-\STXd\US\ENQ\248\203\aV|\216\239\226\153\220\135JD3SK\148\197\fv\189\155WX\232um\131\218p\FSc\SO\207\138\196\190\&6\175t\145\222\234\184\131\196Y\229\150 \229\EOTw\133\ETX\233\150\142\160\\I\236k\207\SUB\232\193\NAK\225\236\145) \207!\253\163\197\250\RSB\211\213\&5\145\224u\175\133\254V\DEL\FS\149s\185\226W\229\a-\188 \160\191l\150\&6\241\243\230%\210OZ\199\231g\233Q\220]n\180.\187#\NAK]\t,\169\SUB\192\255\191a\128v\219\202\159EV\144\166\EM\v\169N\208\210\202\213Y\189n\173\138\&4H\140=\205\135\"\236\FSp\f\165\216IT\224\142\235.\155\&0\160\199U#\242\131X\150\195\bMc\129#?\156\&1\EOT3\149S{\196\SUB\239\148\NUL\180AF\182y^\243\210\b~\245\ACK\151\227^\194]5\134\137#6\148\137\157_\136\154\142:\189\163"
Bcrypt
"$2b$12$FiZ6pSEDvgH4bT1V2yFxvuLTw4l8PRI4Il49AHEunr5T6bNLZgAvq"
True
Right True
False
Right False