pg-wire-0.1.0.0: src/PgWire/Auth/MD5.hs
-- | MD5 password authentication (legacy PostgreSQL auth method).
--
-- __Audience:__ exposed for downstream library authors. The standard
-- authentication flow is driven from "PgWire.Connection"; this module
-- is only useful if you are reimplementing handshake.
module PgWire.Auth.MD5
( md5Auth
, md5Password
) where
import Crypto.Hash.MD5 qualified as MD5
import Data.ByteString (ByteString)
import Data.ByteString qualified as BS
import Data.Word (Word8)
import PgWire.Protocol.Frontend (FrontendMsg (..))
import PgWire.Wire (WireConn, sendFrontendMsg)
import Numeric (showHex)
-- | Handle MD5 password authentication.
-- PG expects: @"md5" ++ md5(md5(password ++ user) ++ salt)@
md5Auth :: WireConn -> ByteString -> ByteString -> ByteString -> IO ()
md5Auth wc user password salt =
sendFrontendMsg wc (PasswordMessage (md5Password user password salt))
-- | Compute the MD5 password hash.
md5Password :: ByteString -> ByteString -> ByteString -> ByteString
md5Password user password salt =
let inner = hexMd5 (password <> user)
outer = hexMd5 (inner <> salt)
in "md5" <> outer
hexMd5 :: ByteString -> ByteString
hexMd5 = BS.pack . concatMap toHexBytes . BS.unpack . MD5.hash
toHexBytes :: Word8 -> [Word8]
toHexBytes w =
let s = showHex w ""
padded = if length s == 1 then '0' : s else s
in map (fromIntegral . fromEnum) padded