-- |
-- 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