File: Poly1305.hs

package info (click to toggle)
haskell-cryptonite 0.30-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 3,372 kB
  • sloc: ansic: 22,009; haskell: 18,423; makefile: 8
file content (116 lines) | stat: -rw-r--r-- 4,249 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116

-- |
-- Module      : Crypto.MAC.Poly1305
-- License     : BSD-style
-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
-- Stability   : experimental
-- Portability : unknown
--
-- Poly1305 implementation
--
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Crypto.MAC.Poly1305
    ( Ctx
    , State
    , Auth(..)
    , authTag
    -- * Incremental MAC Functions
    , initialize -- :: State
    , update     -- :: State -> ByteString -> State
    , updates    -- :: State -> [ByteString] -> State
    , finalize   -- :: State -> Auth
    -- * One-pass MAC function
    , auth
    ) where

import           Foreign.Ptr
import           Foreign.C.Types
import           Data.Word
import           Crypto.Internal.ByteArray (ByteArrayAccess, ScrubbedBytes, Bytes)
import qualified Crypto.Internal.ByteArray as B
import           Crypto.Internal.DeepSeq
import           Crypto.Error

-- | Poly1305 State
--
-- This type is an instance of 'ByteArrayAccess' for debugging purpose. Internal
-- layout is architecture dependent, may contain uninitialized data fragments,
-- and change in future versions.  The bytearray should not be used as input to
-- cryptographic algorithms.
newtype State = State ScrubbedBytes
    deriving (ByteArrayAccess)

-- | Poly1305 State. use State instead of Ctx
type Ctx = State
{-# DEPRECATED Ctx "use Poly1305 State instead" #-}

-- | Poly1305 Auth
newtype Auth = Auth Bytes
    deriving (ByteArrayAccess,NFData)

authTag :: ByteArrayAccess b => b -> CryptoFailable Auth
authTag b
    | B.length b /= 16 = CryptoFailed $ CryptoError_AuthenticationTagSizeInvalid
    | otherwise        = CryptoPassed $ Auth $ B.convert b

instance Eq Auth where
    (Auth a1) == (Auth a2) = B.constEq a1 a2

foreign import ccall unsafe "cryptonite_poly1305.h cryptonite_poly1305_init"
    c_poly1305_init :: Ptr State -> Ptr Word8 -> IO ()

foreign import ccall "cryptonite_poly1305.h cryptonite_poly1305_update"
    c_poly1305_update :: Ptr State -> Ptr Word8 -> CUInt -> IO ()

foreign import ccall unsafe "cryptonite_poly1305.h cryptonite_poly1305_finalize"
    c_poly1305_finalize :: Ptr Word8 -> Ptr State -> IO ()

-- | initialize a Poly1305 context
initialize :: ByteArrayAccess key
           => key
           -> CryptoFailable State
initialize key
    | B.length key /= 32 = CryptoFailed $ CryptoError_MacKeyInvalid
    | otherwise          = CryptoPassed $ State $ B.allocAndFreeze 84 $ \ctxPtr ->
        B.withByteArray key $ \keyPtr ->
            c_poly1305_init (castPtr ctxPtr) keyPtr
{-# NOINLINE initialize #-}

-- | update a context with a bytestring
update :: ByteArrayAccess ba => State -> ba -> State
update (State prevCtx) d = State $ B.copyAndFreeze prevCtx $ \ctxPtr ->
    B.withByteArray d $ \dataPtr ->
        c_poly1305_update (castPtr ctxPtr) dataPtr (fromIntegral $ B.length d)
{-# NOINLINE update #-}

-- | updates a context with multiples bytestring
updates :: ByteArrayAccess ba => State -> [ba] -> State
updates (State prevCtx) d = State $ B.copyAndFreeze prevCtx (loop d)
  where loop []     _      = return ()
        loop (x:xs) ctxPtr = do
            B.withByteArray x $ \dataPtr -> c_poly1305_update ctxPtr dataPtr (fromIntegral $ B.length x)
            loop xs ctxPtr
{-# NOINLINE updates #-}

-- | finalize the context into a digest bytestring
finalize :: State -> Auth
finalize (State prevCtx) = Auth $ B.allocAndFreeze 16 $ \dst -> do
    _ <- B.copy prevCtx (\ctxPtr -> c_poly1305_finalize dst (castPtr ctxPtr)) :: IO ScrubbedBytes
    return ()
{-# NOINLINE finalize #-}

-- | One-pass authorization creation
auth :: (ByteArrayAccess key, ByteArrayAccess ba) => key -> ba -> Auth
auth key d
    | B.length key /= 32 = error "Poly1305: key length expected 32 bytes"
    | otherwise          = Auth $ B.allocAndFreeze 16 $ \dst -> do
        _ <- B.alloc 84 (onCtx dst) :: IO ScrubbedBytes
        return ()
  where
        onCtx dst ctxPtr =
            B.withByteArray key $ \keyPtr -> do
                c_poly1305_init (castPtr ctxPtr) keyPtr
                B.withByteArray d $ \dataPtr ->
                    c_poly1305_update (castPtr ctxPtr) dataPtr (fromIntegral $ B.length d)
                c_poly1305_finalize dst (castPtr ctxPtr)