-- |
-- Module      : Crypto.Cipher.CAST5
-- License     : BSD-style
-- Maintainer  : Olivier Chéron <olivier.cheron@gmail.com>
-- Stability   : stable
-- Portability : good
--
module Crypto.Cipher.CAST5
    ( CAST5
    ) where

import           Crypto.Error
import           Crypto.Cipher.Types
import           Crypto.Cipher.CAST5.Primitive
import           Crypto.Internal.ByteArray (ByteArrayAccess)
import qualified Crypto.Internal.ByteArray as B

-- | CAST5 block cipher (also known as CAST-128).  Key is between
-- 40 and 128 bits.
newtype CAST5 = CAST5 Key

instance Cipher CAST5 where
    cipherName :: CAST5 -> String
cipherName    CAST5
_ = String
"CAST5"
    cipherKeySize :: CAST5 -> KeySizeSpecifier
cipherKeySize CAST5
_ = Int -> Int -> KeySizeSpecifier
KeySizeRange Int
5 Int
16
    cipherInit :: forall key. ByteArray key => key -> CryptoFailable CAST5
cipherInit      = key -> CryptoFailable CAST5
forall key. ByteArrayAccess key => key -> CryptoFailable CAST5
initCAST5

instance BlockCipher CAST5 where
    blockSize :: CAST5 -> Int
blockSize CAST5
_ = Int
8
    ecbEncrypt :: forall ba. ByteArray ba => CAST5 -> ba -> ba
ecbEncrypt (CAST5 Key
k) = (Word64 -> Word64) -> ba -> ba
forall bs. ByteArray bs => (Word64 -> Word64) -> bs -> bs
B.mapAsWord64 (Key -> Word64 -> Word64
encrypt Key
k)
    ecbDecrypt :: forall ba. ByteArray ba => CAST5 -> ba -> ba
ecbDecrypt (CAST5 Key
k) = (Word64 -> Word64) -> ba -> ba
forall bs. ByteArray bs => (Word64 -> Word64) -> bs -> bs
B.mapAsWord64 (Key -> Word64 -> Word64
decrypt Key
k)

initCAST5 :: ByteArrayAccess key => key -> CryptoFailable CAST5
initCAST5 :: forall key. ByteArrayAccess key => key -> CryptoFailable CAST5
initCAST5 key
bs
    | Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<   Int
5 = CryptoError -> CryptoFailable CAST5
forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_KeySizeInvalid
    | Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<  Int
16 = CAST5 -> CryptoFailable CAST5
forall a. a -> CryptoFailable a
CryptoPassed (Key -> CAST5
CAST5 (Key -> CAST5) -> Key -> CAST5
forall a b. (a -> b) -> a -> b
$ Bool -> Bytes -> Key
forall key. ByteArrayAccess key => Bool -> key -> Key
buildKey Bool
short Bytes
padded)
    | Int
len Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
16 = CAST5 -> CryptoFailable CAST5
forall a. a -> CryptoFailable a
CryptoPassed (Key -> CAST5
CAST5 (Key -> CAST5) -> Key -> CAST5
forall a b. (a -> b) -> a -> b
$ Bool -> key -> Key
forall key. ByteArrayAccess key => Bool -> key -> Key
buildKey Bool
False key
bs)
    | Bool
otherwise = CryptoError -> CryptoFailable CAST5
forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_KeySizeInvalid
  where
    len :: Int
len   = key -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length key
bs
    short :: Bool
short = Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
10

    padded :: B.Bytes
    padded :: Bytes
padded = key -> Bytes
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
B.convert key
bs Bytes -> Bytes -> Bytes
forall bs. ByteArray bs => bs -> bs -> bs
`B.append` Int -> Word8 -> Bytes
forall ba. ByteArray ba => Int -> Word8 -> ba
B.replicate (Int
16 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
len) Word8
0