    -- |
    -- Module      : Crypto.PubKey.RSA.OAEP
    -- License     : BSD-style
    -- Maintainer  : Vincent Hanquez <vincent@snarc.org>
    -- Stability   : experimental
    -- Portability : Good
    --
    -- RSA OAEP mode
    -- <http://en.wikipedia.org/wiki/Optimal_asymmetric_encryption_padding>
    --
    {-# LANGUAGE OverloadedStrings #-}
    module Crypto.PubKey.RSA.OAEP
        (
          OAEPParams(..)
        , defaultOAEPParams
        -- * OAEP encryption
        , encryptWithSeed
        , encrypt
        -- * OAEP decryption
        , decrypt
        , decryptSafer
        ) where

    import Crypto.Random
    import Crypto.Types.PubKey.RSA
    import Crypto.PubKey.HashDescr
    import Crypto.PubKey.MaskGenFunction
    import Crypto.PubKey.RSA.Prim
    import Crypto.PubKey.RSA.Types
    import Crypto.PubKey.RSA (generateBlinder)
    import Crypto.PubKey.Internal (and')
    import Data.ByteString (ByteString)
    import qualified Data.ByteString as B
    import Data.Bits (xor)

    -- | Parameters for OAEP encryption/decryption
    data OAEPParams = OAEPParams
        { OAEPParams -> HashFunction
    oaepHash       :: HashFunction     -- ^ Hash function to use.
        , OAEPParams -> MaskGenAlgorithm
    oaepMaskGenAlg :: MaskGenAlgorithm -- ^ Mask Gen algorithm to use.
        , OAEPParams -> Maybe ByteString
    oaepLabel      :: Maybe ByteString -- ^ Optional label prepended to message.
        }

    -- | Default Params with a specified hash function
    defaultOAEPParams :: HashFunction -> OAEPParams
    defaultOAEPParams :: HashFunction -> OAEPParams
    defaultOAEPParams hashF :: HashFunction
    hashF =
        OAEPParams :: HashFunction -> MaskGenAlgorithm -> Maybe ByteString -> OAEPParams
    OAEPParams { oaepHash :: HashFunction
    oaepHash         = HashFunction
    hashF
                   , oaepMaskGenAlg :: MaskGenAlgorithm
    oaepMaskGenAlg   = MaskGenAlgorithm
    mgf1
                   , oaepLabel :: Maybe ByteString
    oaepLabel        = Maybe ByteString
    forall a. Maybe a
    Nothing
                   }

    -- | Encrypt a message using OAEP with a predefined seed.
    encryptWithSeed :: ByteString -- ^ Seed
                    -> OAEPParams -- ^ OAEP params to use for encryption
                    -> PublicKey  -- ^ Public key.
                    -> ByteString -- ^ Message to encrypt
                    -> Either Error ByteString
    encryptWithSeed :: ByteString
    -> OAEPParams -> PublicKey -> ByteString -> Either Error ByteString
    encryptWithSeed seed :: ByteString
    seed oaep :: OAEPParams
    oaep pk :: PublicKey
    pk msg :: ByteString
    msg
        | Int
    k Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    < 2Int -> Int -> Int
    forall a. Num a => a -> a -> a
    *Int
    hashLenInt -> Int -> Int
    forall a. Num a => a -> a -> a
    +2          = Error -> Either Error ByteString
    forall a b. a -> Either a b
    Left Error
    InvalidParameters
        | ByteString -> Int
    B.length ByteString
    seed Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Int
    hashLen = Error -> Either Error ByteString
    forall a b. a -> Either a b
    Left Error
    InvalidParameters
        | Int
    mLen Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    k Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - 2Int -> Int -> Int
    forall a. Num a => a -> a -> a
    *Int
    hashLenInt -> Int -> Int
    forall a. Num a => a -> a -> a
    -2   = Error -> Either Error ByteString
    forall a b. a -> Either a b
    Left Error
    MessageTooLong
        | Bool
    otherwise                = ByteString -> Either Error ByteString
    forall a b. b -> Either a b
    Right (ByteString -> Either Error ByteString)
    -> ByteString -> Either Error ByteString
    forall a b. (a -> b) -> a -> b
    $ PublicKey -> HashFunction
    ep PublicKey
    pk ByteString
    em
        where -- parameters
              k :: Int
    k          = PublicKey -> Int
    public_size PublicKey
    pk
              mLen :: Int
    mLen       = ByteString -> Int
    B.length ByteString
    msg
              hashF :: HashFunction
    hashF      = OAEPParams -> HashFunction
    oaepHash OAEPParams
    oaep
              mgf :: ByteString -> Int -> ByteString
    mgf        = (OAEPParams -> MaskGenAlgorithm
    oaepMaskGenAlg OAEPParams
    oaep) HashFunction
    hashF
              labelHash :: ByteString
    labelHash  = HashFunction
    hashF HashFunction -> HashFunction
    forall a b. (a -> b) -> a -> b
    $ ByteString -> HashFunction -> Maybe ByteString -> ByteString
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe ByteString
    B.empty HashFunction
    forall a. a -> a
    id (Maybe ByteString -> ByteString) -> Maybe ByteString -> ByteString
    forall a b. (a -> b) -> a -> b
    $ OAEPParams -> Maybe ByteString
    oaepLabel OAEPParams
    oaep
              hashLen :: Int
    hashLen    = ByteString -> Int
    B.length ByteString
    labelHash

              -- put fields
              ps :: ByteString
    ps         = Int -> Word8 -> ByteString
    B.replicate (Int
    k Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    mLen Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - 2Int -> Int -> Int
    forall a. Num a => a -> a -> a
    *Int
    hashLen Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - 2) 0
              db :: ByteString
    db         = [ByteString] -> ByteString
    B.concat [ByteString
    labelHash, ByteString
    ps, Word8 -> ByteString
    B.singleton 0x1, ByteString
    msg]
              dbmask :: ByteString
    dbmask     = ByteString -> Int -> ByteString
    mgf ByteString
    seed (Int
    k Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    hashLen Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - 1)
              maskedDB :: ByteString
    maskedDB   = [Word8] -> ByteString
    B.pack ([Word8] -> ByteString) -> [Word8] -> ByteString
    forall a b. (a -> b) -> a -> b
    $ (Word8 -> Word8 -> Word8) -> ByteString -> ByteString -> [Word8]
    forall a. (Word8 -> Word8 -> a) -> ByteString -> ByteString -> [a]
    B.zipWith Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    xor ByteString
    db ByteString
    dbmask
              seedMask :: ByteString
    seedMask   = ByteString -> Int -> ByteString
    mgf ByteString
    maskedDB Int
    hashLen
              maskedSeed :: ByteString
    maskedSeed = [Word8] -> ByteString
    B.pack ([Word8] -> ByteString) -> [Word8] -> ByteString
    forall a b. (a -> b) -> a -> b
    $ (Word8 -> Word8 -> Word8) -> ByteString -> ByteString -> [Word8]
    forall a. (Word8 -> Word8 -> a) -> ByteString -> ByteString -> [a]
    B.zipWith Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    xor ByteString
    seed ByteString
    seedMask
              em :: ByteString
    em         = [ByteString] -> ByteString
    B.concat [Word8 -> ByteString
    B.singleton 0x0,ByteString
    maskedSeed,ByteString
    maskedDB]

    -- | Encrypt a message using OAEP
    encrypt :: CPRG g
            => g          -- ^ random number generator.
            -> OAEPParams -- ^ OAEP params to use for encryption.
            -> PublicKey  -- ^ Public key.
            -> ByteString -- ^ Message to encrypt
            -> (Either Error ByteString, g)
    encrypt :: g
    -> OAEPParams
    -> PublicKey
    -> ByteString
    -> (Either Error ByteString, g)
    encrypt g :: g
    g oaep :: OAEPParams
    oaep pk :: PublicKey
    pk msg :: ByteString
    msg = (ByteString
    -> OAEPParams -> PublicKey -> ByteString -> Either Error ByteString
    encryptWithSeed ByteString
    seed OAEPParams
    oaep PublicKey
    pk ByteString
    msg, g
    g')
        where hashF :: HashFunction
    hashF      = OAEPParams -> HashFunction
    oaepHash OAEPParams
    oaep
              hashLen :: Int
    hashLen    = ByteString -> Int
    B.length (HashFunction
    hashF ByteString
    B.empty)
              (seed :: ByteString
    seed, g' :: g
    g') = Int -> g -> (ByteString, g)
    forall gen. CPRG gen => Int -> gen -> (ByteString, gen)
    cprgGenerate Int
    hashLen g
    g

    -- | un-pad a OAEP encoded message.
    --
    -- It doesn't apply the RSA decryption primitive
    unpad :: OAEPParams  -- ^ OAEP params to use
          -> Int         -- ^ size of the key in bytes
          -> ByteString  -- ^ encoded message (not encrypted)
          -> Either Error ByteString
    unpad :: OAEPParams -> Int -> ByteString -> Either Error ByteString
    unpad oaep :: OAEPParams
    oaep k :: Int
    k em :: ByteString
    em
        | Bool
    paddingSuccess = ByteString -> Either Error ByteString
    forall a b. b -> Either a b
    Right ByteString
    msg
        | Bool
    otherwise      = Error -> Either Error ByteString
    forall a b. a -> Either a b
    Left Error
    MessageNotRecognized
        where -- parameters
              hashF :: HashFunction
    hashF      = OAEPParams -> HashFunction
    oaepHash OAEPParams
    oaep
              mgf :: ByteString -> Int -> ByteString
    mgf        = (OAEPParams -> MaskGenAlgorithm
    oaepMaskGenAlg OAEPParams
    oaep) HashFunction
    hashF
              labelHash :: ByteString
    labelHash  = HashFunction
    hashF HashFunction -> HashFunction
    forall a b. (a -> b) -> a -> b
    $ ByteString -> HashFunction -> Maybe ByteString -> ByteString
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe ByteString
    B.empty HashFunction
    forall a. a -> a
    id (Maybe ByteString -> ByteString) -> Maybe ByteString -> ByteString
    forall a b. (a -> b) -> a -> b
    $ OAEPParams -> Maybe ByteString
    oaepLabel OAEPParams
    oaep
              hashLen :: Int
    hashLen    = ByteString -> Int
    B.length ByteString
    labelHash
              -- getting em's fields
              (pb :: ByteString
    pb, em0 :: ByteString
    em0)  = Int -> ByteString -> (ByteString, ByteString)
    B.splitAt 1 ByteString
    em
              (maskedSeed :: ByteString
    maskedSeed,maskedDB :: ByteString
    maskedDB) = Int -> ByteString -> (ByteString, ByteString)
    B.splitAt Int
    hashLen ByteString
    em0
              seedMask :: ByteString
    seedMask   = ByteString -> Int -> ByteString
    mgf ByteString
    maskedDB Int
    hashLen
              seed :: ByteString
    seed       = [Word8] -> ByteString
    B.pack ([Word8] -> ByteString) -> [Word8] -> ByteString
    forall a b. (a -> b) -> a -> b
    $ (Word8 -> Word8 -> Word8) -> ByteString -> ByteString -> [Word8]
    forall a. (Word8 -> Word8 -> a) -> ByteString -> ByteString -> [a]
    B.zipWith Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    xor ByteString
    maskedSeed ByteString
    seedMask
              dbmask :: ByteString
    dbmask     = ByteString -> Int -> ByteString
    mgf ByteString
    seed (Int
    k Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    hashLen Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - 1)
              db :: ByteString
    db         = [Word8] -> ByteString
    B.pack ([Word8] -> ByteString) -> [Word8] -> ByteString
    forall a b. (a -> b) -> a -> b
    $ (Word8 -> Word8 -> Word8) -> ByteString -> ByteString -> [Word8]
    forall a. (Word8 -> Word8 -> a) -> ByteString -> ByteString -> [a]
    B.zipWith Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    xor ByteString
    maskedDB ByteString
    dbmask
              -- getting db's fields
              (labelHash' :: ByteString
    labelHash',db1 :: ByteString
    db1) = Int -> ByteString -> (ByteString, ByteString)
    B.splitAt Int
    hashLen ByteString
    db
              (_,db2 :: ByteString
    db2)    = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
    B.break (Word8 -> Word8 -> Bool
    forall a. Eq a => a -> a -> Bool
    /= 0) ByteString
    db1
              (ps1 :: ByteString
    ps1,msg :: ByteString
    msg)  = Int -> ByteString -> (ByteString, ByteString)
    B.splitAt 1 ByteString
    db2

              paddingSuccess :: Bool
    paddingSuccess = [Bool] -> Bool
    and' [ ByteString
    labelHash' ByteString -> ByteString -> Bool
    forall a. Eq a => a -> a -> Bool
    == ByteString
    labelHash -- no need for constant eq
                                    , ByteString
    ps1        ByteString -> ByteString -> Bool
    forall a. Eq a => a -> a -> Bool
    == "\x01"
                                    , ByteString
    pb         ByteString -> ByteString -> Bool
    forall a. Eq a => a -> a -> Bool
    == "\x00"
                                    ]

    -- | Decrypt a ciphertext using OAEP
    --
    -- When the signature is not in a context where an attacker could gain
    -- information from the timing of the operation, the blinder can be set to None.
    --
    -- If unsure always set a blinder or use decryptSafer
    decrypt :: Maybe Blinder -- ^ Optional blinder
            -> OAEPParams    -- ^ OAEP params to use for decryption
            -> PrivateKey    -- ^ Private key
            -> ByteString    -- ^ Cipher text
            -> Either Error ByteString
    decrypt :: Maybe Blinder
    -> OAEPParams
    -> PrivateKey
    -> ByteString
    -> Either Error ByteString
    decrypt blinder :: Maybe Blinder
    blinder oaep :: OAEPParams
    oaep pk :: PrivateKey
    pk cipher :: ByteString
    cipher
        | ByteString -> Int
    B.length ByteString
    cipher Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Int
    k = Error -> Either Error ByteString
    forall a b. a -> Either a b
    Left Error
    MessageSizeIncorrect
        | Int
    k Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    < 2Int -> Int -> Int
    forall a. Num a => a -> a -> a
    *Int
    hashLenInt -> Int -> Int
    forall a. Num a => a -> a -> a
    +2      = Error -> Either Error ByteString
    forall a b. a -> Either a b
    Left Error
    InvalidParameters
        | Bool
    otherwise            = OAEPParams -> Int -> ByteString -> Either Error ByteString
    unpad OAEPParams
    oaep (PrivateKey -> Int
    private_size PrivateKey
    pk) (ByteString -> Either Error ByteString)
    -> ByteString -> Either Error ByteString
    forall a b. (a -> b) -> a -> b
    $ Maybe Blinder -> PrivateKey -> HashFunction
    dp Maybe Blinder
    blinder PrivateKey
    pk ByteString
    cipher
        where -- parameters
              k :: Int
    k          = PrivateKey -> Int
    private_size PrivateKey
    pk
              hashF :: HashFunction
    hashF      = OAEPParams -> HashFunction
    oaepHash OAEPParams
    oaep
              hashLen :: Int
    hashLen    = ByteString -> Int
    B.length (HashFunction
    hashF ByteString
    B.empty)

    -- | Decrypt a ciphertext using OAEP and by automatically generating a blinder.
    decryptSafer :: CPRG g
                 => g          -- ^ random number generator
                 -> OAEPParams -- ^ OAEP params to use for decryption
                 -> PrivateKey -- ^ Private key
                 -> ByteString -- ^ Cipher text
                 -> (Either Error ByteString, g)
    decryptSafer :: g
    -> OAEPParams
    -> PrivateKey
    -> ByteString
    -> (Either Error ByteString, g)
    decryptSafer rng :: g
    rng oaep :: OAEPParams
    oaep pk :: PrivateKey
    pk cipher :: ByteString
    cipher = (Maybe Blinder
    -> OAEPParams
    -> PrivateKey
    -> ByteString
    -> Either Error ByteString
    decrypt (Blinder -> Maybe Blinder
    forall a. a -> Maybe a
    Just Blinder
    blinder) OAEPParams
    oaep PrivateKey
    pk ByteString
    cipher, g
    rng')
        where (blinder :: Blinder
    blinder, rng' :: g
    rng') = g -> Integer -> (Blinder, g)
    forall g. CPRG g => g -> Integer -> (Blinder, g)
    generateBlinder g
    rng (PrivateKey -> Integer
    private_n PrivateKey
    pk)