haste-lib-0.6.0.0: src/Haste/Crypto/Types.hs
{-# LANGUAGE GeneralizedNewtypeDeriving, OverloadedStrings #-}
module Haste.Crypto.Types where
import Haste (JSString, JSType (..))
import Haste.Binary as B
import Haste.Foreign as F
import Data.Array.Unboxed
import Data.Word
-- | Denotes a block cipher mode. As only CBC and GCM are universally supported
-- by browsers, these are presently the only modes exported by Haste.
-- If unsure, always use @GCM@.
data CipherMode = CBC | GCM
deriving (Show, Read, Eq, Ord)
data KeyLength = Bits128 | Bits256
deriving (Show, Read, Eq, Ord)
data Cipher = AES CipherMode KeyLength
deriving (Show, Read, Eq, Ord)
-- | A key for a symmetric cipher.
data SymmetricKey = SymmetricKey JSAny Cipher
keyCipher :: SymmetricKey -> Cipher
keyCipher (SymmetricKey _ c) = c
instance ToAny SymmetricKey where
toAny (SymmetricKey k c) = toObject [("key", k), ("cipher", toAny c)]
instance FromAny SymmetricKey where
fromAny x = SymmetricKey <$> F.get x "key" <*> F.get x "cipher"
newtype IV = IV {ivBytes :: UArray Word32 Word8}
deriving (ToAny, FromAny, Binary)
newtype Salt = Salt {saltBytes :: UArray Word32 Word8}
deriving (ToAny, FromAny, Binary)
type Password = JSString
instance Binary CipherMode where
put CBC = putWord8 0
put GCM = putWord8 1
get = do
n <- getWord8
case n of
0 -> pure CBC
1 -> pure GCM
_ -> fail "Cipher mode was neither CBC nor GCM"
instance Binary KeyLength where
put Bits128 = putWord8 0
put Bits256 = putWord8 1
get = do
n <- getWord8
case n of
0 -> pure Bits128
1 -> pure Bits256
_ -> fail "Key length was neither 128 nor 256 bits"
instance Binary Cipher where
put (AES mode len) = putWord8 0 >> put mode >> put len
get = do
n <- getWord8
case n of
0 -> AES <$> B.get <*> B.get
_ -> fail "Invalid cipher"
instance ToAny CipherMode where
toAny = toAny . toJSString
instance ToAny KeyLength where
toAny = toAny . toJSString
instance FromAny CipherMode where
fromAny x = do
s <- fromAny x
maybe (fail "Unable to read CipherMode") return (fromJSString s)
instance FromAny KeyLength where
fromAny x = do
s <- fromAny x
maybe (fail "Unable to read KeyLength") return (fromJSString s)
instance JSType KeyLength where
toJSString Bits128 = "128"
toJSString Bits256 = "256"
fromJSString "128" = Just Bits128
fromJSString "256" = Just Bits256
fromJSString _ = Nothing
instance ToAny Cipher where
toAny (AES mode len) = toObject
[ ("name", toAny mode)
, ("length", toAny len)
]
instance FromAny Cipher where
fromAny x = AES <$> F.get x "name" <*> F.get x "length"
instance JSType CipherMode where
toJSString CBC = "AES-CBC"
toJSString GCM = "AES-GCM"
fromJSString "AES-CBC" = Just CBC
fromJSString "AES-GCM" = Just GCM
fromJSString _ = Nothing