nano-md5-0.1: Data/Digest/OpenSSL/MD5.hs
{-# OPTIONS -#include "openssl/md5.h" #-}
--------------------------------------------------------------------
-- |
-- Module : Data.Digest.OpenSSL.MD5
-- Copyright : (c) Galois, Inc. 2007
-- License : BSD3
-- Maintainer: Don Stewart <dons@galois.com>
-- Stability : provisional
-- Portability: Requires FFI
--
--------------------------------------------------------------------
--
-- | ByteString-based, zero-copying binding to OpenSSL's md5 interface
--
module Data.Digest.OpenSSL.MD5 where
--
-- A few imports, should tidy these up one day.
--
#if __GLASGOW_HASKELL__ >= 608
import qualified Data.ByteString.Unsafe as B (unsafeUseAsCStringLen)
#else
import qualified Data.ByteString.Base as B (unsafeUseAsCStringLen)
#endif
import qualified Data.ByteString as B
import Foreign
import Foreign.C.Types
import Numeric (showHex)
--
-- | Fast md5 using OpenSSL. The md5 hash should be referentially transparent..
-- The ByteString is guaranteed not to be copied.
--
-- The result string should be identical to the output of MD5(1).
-- That is:
--
-- > $ md5 /usr/share/dict/words
-- > MD5 (/usr/share/dict/words) = e5c152147e93b81424c13772330e74b3
--
-- While this md5sum binding will return:
--
md5sum :: B.ByteString -> String
md5sum p = unsafePerformIO $ B.unsafeUseAsCStringLen p $ \(ptr,n) -> do
digest <- c_md5 ptr (fromIntegral n) nullPtr
go digest 0 []
where
-- print it in 0-padded hex format
go :: Ptr Word8 -> Int -> [String] -> IO String
go !q !n acc
| n >= 16 = return $ concat (reverse acc)
| otherwise = do w <- peekElemOff q n
go q (n+1) (draw w : acc)
draw w = case showHex w [] of
[x] -> ['0', x]
x -> x
--
-- unsigned char *MD5(const unsigned char *d, unsigned long n, unsigned char *md);
--
foreign import ccall "openssl/md5.h MD5" c_md5
:: Ptr CChar -> CULong -> Ptr CChar -> IO (Ptr Word8)