Web.ClientSession

clientsession-0.9.1.2: Securely store session data in a client-side cookie.

Copyright | Michael Snoyman
License | BSD3
Maintainer | Michael Snoyman <michael@snoyman.com>
Stability | Stable
Portability | portable
Safe Haskell | None
Language | Haskell98

Web.ClientSession

Contents

- Automatic key generation
- Actual encryption/decryption

Description

Stores session data in a client cookie. In order to do so, we:

- Encrypt the cookie data using AES in CTR mode. This allows you to store sensitive information on the client side without worrying about eavesdropping.
- Authenticate the encrypted cookie data using Skein-MAC-512-256. Besides detecting potential errors in storage or transmission of the cookies (integrity), the MAC also avoids malicious modifications of the cookie data by assuring you that the cookie data really was generated by this server (authenticity).
- Encode everything using Base64. Thus we avoid problems with non-printable characters by giving the browser a simple string.

Simple usage of the library involves just calling `getDefaultKey` on the startup of your server, `encryptIO` when serializing cookies and `decrypt` when parsing then back.

Synopsis

- data Key
- data IV
- randomIV :: IO IV
- mkIV :: ByteString -> Maybe IV
- getKey :: FilePath -> IO Key
- getKeyEnv :: String -> IO Key
- defaultKeyFile :: FilePath
- getDefaultKey :: IO Key
- initKey :: ByteString -> Either String Key
- randomKey :: IO (ByteString, Key)
- randomKeyEnv :: String -> IO Key
- encrypt :: Key -> IV -> ByteString -> ByteString
- encryptIO :: Key -> ByteString -> IO ByteString
- decrypt :: Key -> ByteString -> Maybe ByteString

# Automatic key generation

data Key #

The keys used to store the cookies. We have an AES key used to encrypt the cookie and a Skein-MAC-512-256 key used verify the authencity and integrity of the cookie. The AES key must have exactly 32 bytes (256 bits) while Skein-MAC-512-256 must have 64 bytes (512 bits).

See also `getDefaultKey` and `initKey`.

Instances

Eq Key # |
Methods (==) :: Key -> Key -> Bool # (/=) :: Key -> Key -> Bool #
Show Key # | Dummy `Show` instance.
Methods showsPrec :: Int -> Key -> ShowS # show :: Key -> String # showList :: [Key] -> ShowS #
Serialize Key # |
Methods put :: Putter Key # get :: Get Key #

data IV #

The initialization vector used by AES. Must be exactly 16 bytes long.

Instances

Eq IV # |
Methods (==) :: IV -> IV -> Bool # (/=) :: IV -> IV -> Bool #
Ord IV # |
Methods compare :: IV -> IV -> Ordering # (<) :: IV -> IV -> Bool # (<=) :: IV -> IV -> Bool # (>) :: IV -> IV -> Bool # (>=) :: IV -> IV -> Bool # max :: IV -> IV -> IV # min :: IV -> IV -> IV #
Show IV # |
Methods showsPrec :: Int -> IV -> ShowS # show :: IV -> String # showList :: [IV] -> ShowS #
Serialize IV # |
Methods put :: Putter IV # get :: Get IV #

randomIV :: IO IV #

Randomly construct a fresh initialization vector. You MUST NOT reuse initialization vectors.

mkIV :: ByteString -> Maybe IV #

Construct an initialization vector from a `ByteString`. Fails if there isn't exactly 16 bytes.

getKey #

Arguments

:: FilePath | File name where key is stored.
-> IO Key | The actual key.

Get a key from the given text file.

If the file does not exist or is corrupted a random key will be generated and stored in that file.

getKeyEnv #

Arguments

:: String | Name of the environment variable
-> IO Key | The actual key.

Get the key from the named environment variable

Assumes the value is a Base64-encoded string. If the variable is not set, a random key will be generated, set in the environment, and the Base64-encoded version printed on `devstdout`.

defaultKeyFile :: FilePath #

The default key file.

getDefaultKey :: IO Key #

Simply calls `getKey` `defaultKeyFile`.

initKey :: ByteString -> Either String Key #

Initializes a `Key` from a random `ByteString`. Fails if there isn't exactly 96 bytes (256 bits for AES and 512 bits for Skein-MAC-512-512).

Note that the input string is assumed to be uniformly chosen from the set of all 96-byte strings. In other words, each byte should be chosen from the set of all byte values (0-255) with the same probability.

In particular, this function does not do any kind of key stretching. You should never feed it a password, for example.

It's highly recommended to feed `initKey` only with values generated by `randomKey`, unless you really know what you're doing.

randomKey :: IO (ByteString, Key) #

Generate a random `Key`. Besides the `Key`, the `ByteString` passed to `initKey` is returned so that it can be saved for later use.

randomKeyEnv :: String -> IO Key #

Generate a random `Key`, set a Base64-encoded version of it in the given environment variable, then return it. Also prints the generated string to `devstdout`.

# Actual encryption/decryption

encrypt #

Arguments

:: Key | Key of the server.
-> IV | New, random initialization vector (see `randomIV`).
-> ByteString | Serialized cookie data.
-> ByteString | Encoded cookie data to be given to the client browser.

Encrypt (AES-CTR), authenticate (Skein-MAC-512-256) and encode (Base64) the given cookie data. The returned byte string is ready to be used in a response header.

encryptIO :: Key -> ByteString -> IO ByteString #

Same as `encrypt`, however randomly generates the initialization vector for you.

decrypt #

Arguments

:: Key | Key of the server.
-> ByteString | Encoded cookie data given by the browser.
-> Maybe ByteString | Serialized cookie data.

Decode (Base64), verify the integrity and authenticity (Skein-MAC-512-256) and decrypt (AES-CTR) the given encoded cookie data. Returns the original serialized cookie data. Fails if the data is corrupted.