    -- |
    -- Module      : Crypto.Store.Cipher.RC2
    -- License     : BSD-style
    -- Maintainer  : Olivier Chéron <olivier.cheron@gmail.com>
    -- Stability   : stable
    -- Portability : good
    --
    -- Implementation of RC2 block cipher, a legacy algorithm providing weak
    -- security.  Use only for compatibility with software requiring this cipher and
    -- data which is not sensitive.
    module Crypto.Store.Cipher.RC2
        ( RC2
        , rc2WithEffectiveKeyLength
        ) where

    import           Data.ByteArray (ByteArrayAccess)
    import qualified Data.ByteArray as B
    import           Data.Maybe (fromMaybe)

    import  Crypto.Error
    import  Crypto.Cipher.Types

    import  Crypto.Store.Cipher.RC2.Primitive
    import  Crypto.Store.Util

    -- | RC2 block cipher.  Key is between 8 and 1024 bits.
    newtype RC2 = RC2 Key

    instance Cipher RC2 where
        cipherName :: RC2 -> String
    cipherName    RC2
    _ = String
    "RC2"
        cipherKeySize :: RC2 -> KeySizeSpecifier
    cipherKeySize RC2
    _ = Int -> Int -> KeySizeSpecifier
    KeySizeRange Int
    1 Int
    128
        cipherInit :: forall key. ByteArray key => key -> CryptoFailable RC2
    cipherInit      = (Key -> RC2) -> CryptoFailable Key -> CryptoFailable RC2
    forall a b. (a -> b) -> CryptoFailable a -> CryptoFailable b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap Key -> RC2
    RC2 (CryptoFailable Key -> CryptoFailable RC2)
    -> (key -> CryptoFailable Key) -> key -> CryptoFailable RC2
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Maybe Int -> key -> CryptoFailable Key
    forall key.
    ByteArrayAccess key =>
    Maybe Int -> key -> CryptoFailable Key
    initRC2 Maybe Int
    forall a. Maybe a
    Nothing

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

    -- | Build a RC2 cipher with the specified effective key length (in bits).
    rc2WithEffectiveKeyLength :: ByteArrayAccess key
                              => Int -> key -> CryptoFailable RC2
    rc2WithEffectiveKeyLength :: forall key. ByteArrayAccess key => Int -> key -> CryptoFailable RC2
    rc2WithEffectiveKeyLength Int
    bits key
    key
        | Int
    bits Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    < Int
    1    = CryptoError -> CryptoFailable RC2
    forall a. CryptoError -> CryptoFailable a
    CryptoFailed CryptoError
    CryptoError_KeySizeInvalid
        | Int
    bits Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    1024 = CryptoError -> CryptoFailable RC2
    forall a. CryptoError -> CryptoFailable a
    CryptoFailed CryptoError
    CryptoError_KeySizeInvalid
        | Bool
    otherwise   = Key -> RC2
    RC2 (Key -> RC2) -> CryptoFailable Key -> CryptoFailable RC2
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Maybe Int -> key -> CryptoFailable Key
    forall key.
    ByteArrayAccess key =>
    Maybe Int -> key -> CryptoFailable Key
    initRC2 (Int -> Maybe Int
    forall a. a -> Maybe a
    Just Int
    bits) key
    key

    initRC2 :: ByteArrayAccess key => Maybe Int -> key -> CryptoFailable Key
    initRC2 :: forall key.
    ByteArrayAccess key =>
    Maybe Int -> key -> CryptoFailable Key
    initRC2 Maybe Int
    mbits key
    bs
        | Int
    len Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    <    Int
    1 = CryptoError -> CryptoFailable Key
    forall a. CryptoError -> CryptoFailable a
    CryptoFailed CryptoError
    CryptoError_KeySizeInvalid
        | Int
    len Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    <= Int
    128 = Key -> CryptoFailable Key
    forall a. a -> CryptoFailable a
    CryptoPassed (Int -> key -> Key
    forall key. ByteArrayAccess key => Int -> key -> Key
    buildKey Int
    t1 key
    bs)
        | Bool
    otherwise  = CryptoError -> CryptoFailable Key
    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
            t1 :: Int
    t1  = Int -> Maybe Int -> Int
    forall a. a -> Maybe a -> a
    fromMaybe (Int
    8 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    * Int
    len) Maybe Int
    mbits