1 {-# LANGUAGE OverloadedStrings #-}
3 Module : Crypto.Macaroon
4 Copyright : (c) 2015 Julien Tanguy
7 Maintainer : julien.tanguy@jhome.fr
8 Stability : experimental
11 Pure haskell implementations of macaroons.
13 Warning: this implementation has not been audited by security experts.
14 Do not use in production
19 - Macaroons: Cookies with Contextual Caveats for Decentralized Authorization in the Cloud <http://research.google.com/pubs/pub41892.html>
20 - Time for better security in NoSQL <http://hackingdistributed.com/2014/11/23/macaroons-in-hyperdex>
22 module Crypto.Macaroon (
28 -- * Accessing functions
45 -- * Prepare Macaroons for transfer
49 import Crypto.Cipher.AES
53 import qualified Data.ByteString as BS
54 import qualified Data.ByteString.Base64.URL as B64
55 import qualified Data.ByteString.Char8 as B8
60 import Crypto.Macaroon.Internal
62 -- | Create a Macaroon from its key, identifier and location
63 create :: Key -> Key -> Location -> Macaroon
64 create secret ident loc = MkMacaroon loc ident [] (toBytes (hmac derivedKey ident :: HMAC SHA256))
66 derivedKey = toBytes (hmac "macaroons-key-generator" secret :: HMAC SHA256)
68 caveatLoc :: Caveat -> Location
71 caveatId :: Caveat -> Key
74 caveatVId :: Caveat -> Key
77 inspect :: Macaroon -> String
80 serialize :: Macaroon -> BS.ByteString
81 serialize m = B8.filter (/= '=') . B64.encode $ packets
83 packets = BS.concat [ putPacket "location" (location m)
84 , putPacket "identifier" (identifier m)
86 , putPacket "signature" (signature m)
88 caveatPackets = BS.concat $ map (cavPacket (location m)) (caveats m)
89 cavPacket loc c | cl c == loc && vid c == BS.empty = putPacket "cid" (cid c)
90 | otherwise = BS.concat [ putPacket "cid" (cid c)
91 , putPacket "vid" (vid c)
92 , putPacket "cl" (cl c)
94 putPacket key dat = BS.concat [
95 B8.map toLower . hex . encode $ (fromIntegral size :: Word16)
102 size = 4 + 2 + BS.length key + BS.length dat
107 -- | Add a first party Caveat to a Macaroon, with its identifier
108 addFirstPartyCaveat :: Key -> Macaroon -> Macaroon
109 addFirstPartyCaveat ident m = addCaveat (location m) ident BS.empty m
111 -- |Add a third party Caveat to a Macaroon, using its location, identifier and
113 addThirdPartyCaveat :: Key
118 addThirdPartyCaveat key cid loc m = addCaveat loc cid vid m
120 vid = encryptECB (initAES (signature m)) key