    -- |
    -- Module      : Crypto.PubKey.RSA.PKCS15
    -- License     : BSD-style
    -- Maintainer  : Vincent Hanquez <vincent@snarc.org>
    -- Stability   : experimental
    -- Portability : Good
    --
    {-# LANGUAGE OverloadedStrings #-}
    module Crypto.PubKey.RSA.PKCS15
        (
        -- * padding and unpadding
          pad
        , padSignature
        , unpad
        -- * private key operations
        , decrypt
        , decryptSafer
        , sign
        , signSafer
        -- * public key operations
        , encrypt
        , verify
        ) where

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

    -- | This produce a standard PKCS1.5 padding for encryption
    pad :: CPRG g => g -> Int -> ByteString -> Either Error (ByteString, g)
    pad :: g -> Int -> ByteString -> Either Error (ByteString, g)
    pad rng :: g
    rng len :: Int
    len m :: ByteString
    m
        | ByteString -> Int
    B.length ByteString
    m Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    len Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - 11 = Error -> Either Error (ByteString, g)
    forall a b. a -> Either a b
    Left Error
    MessageTooLong
        | Bool
    otherwise             =
            let (padding :: ByteString
    padding, rng' :: g
    rng') = g -> Int -> (ByteString, g)
    forall g. CPRG g => g -> Int -> (ByteString, g)
    getNonNullRandom g
    rng (Int
    len Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - ByteString -> Int
    B.length ByteString
    m Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - 3)
             in (ByteString, g) -> Either Error (ByteString, g)
    forall a b. b -> Either a b
    Right ([ByteString] -> ByteString
    B.concat [ Word8 -> ByteString
    B.singleton 0, Word8 -> ByteString
    B.singleton 2, ByteString
    padding, Word8 -> ByteString
    B.singleton 0, ByteString
    m ], g
    rng')

            where {- get random non-null bytes -}
                  getNonNullRandom :: CPRG g => g -> Int -> (ByteString, g)
                  getNonNullRandom :: g -> Int -> (ByteString, g)
    getNonNullRandom g :: g
    g n :: Int
    n =
                        let (bs0 :: ByteString
    bs0,g' :: g
    g') = Int -> g -> (ByteString, g)
    forall gen. CPRG gen => Int -> gen -> (ByteString, gen)
    cprgGenerate Int
    n g
    g
                            bytes :: ByteString
    bytes    = [Word8] -> ByteString
    B.pack ([Word8] -> ByteString) -> [Word8] -> ByteString
    forall a b. (a -> b) -> a -> b
    $ (Word8 -> Bool) -> [Word8] -> [Word8]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (Word8 -> Word8 -> Bool
    forall a. Eq a => a -> a -> Bool
    /= 0) ([Word8] -> [Word8]) -> [Word8] -> [Word8]
    forall a b. (a -> b) -> a -> b
    $ ByteString -> [Word8]
    B.unpack (ByteString -> [Word8]) -> ByteString -> [Word8]
    forall a b. (a -> b) -> a -> b
    $ ByteString
    bs0
                            left :: Int
    left     = (Int
    n Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - ByteString -> Int
    B.length ByteString
    bytes)
                         in if Int
    left Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == 0
                            then (ByteString
    bytes, g
    g')
                            else let (bend :: ByteString
    bend, g'' :: g
    g'') = g -> Int -> (ByteString, g)
    forall g. CPRG g => g -> Int -> (ByteString, g)
    getNonNullRandom g
    g' Int
    left
                                  in (ByteString
    bytes ByteString -> ByteString -> ByteString
    `B.append` ByteString
    bend, g
    g'')

    -- | Produce a standard PKCS1.5 padding for signature
    padSignature :: Int -> ByteString -> Either Error ByteString
    padSignature :: Int -> ByteString -> Either Error ByteString
    padSignature klen :: Int
    klen signature :: ByteString
    signature
        | Int
    klen Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    < Int
    siglenInt -> Int -> Int
    forall a. Num a => a -> a -> a
    +1 = Error -> Either Error ByteString
    forall a b. a -> Either a b
    Left Error
    SignatureTooLong
        | 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
    $ [ByteString] -> ByteString
    B.concat [Word8 -> ByteString
    B.singleton 0,Word8 -> ByteString
    B.singleton 1,ByteString
    padding,Word8 -> ByteString
    B.singleton 0,ByteString
    signature]
        where
            siglen :: Int
    siglen    = ByteString -> Int
    B.length ByteString
    signature
            padding :: ByteString
    padding   = Int -> Word8 -> ByteString
    B.replicate (Int
    klen Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    siglen Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - 3) 0xff

    -- | Try to remove a standard PKCS1.5 encryption padding.
    unpad :: ByteString -> Either Error ByteString
    unpad :: ByteString -> Either Error ByteString
    unpad packed :: ByteString
    packed
        | Bool
    paddingSuccess = ByteString -> Either Error ByteString
    forall a b. b -> Either a b
    Right ByteString
    m
        | Bool
    otherwise      = Error -> Either Error ByteString
    forall a b. a -> Either a b
    Left Error
    MessageNotRecognized
        where
            (zt :: ByteString
    zt, ps0m :: ByteString
    ps0m)   = Int -> ByteString -> (ByteString, ByteString)
    B.splitAt 2 ByteString
    packed
            (ps :: ByteString
    ps, zm :: ByteString
    zm)     = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
    B.span (Word8 -> Word8 -> Bool
    forall a. Eq a => a -> a -> Bool
    /= 0) ByteString
    ps0m
            (z :: ByteString
    z, m :: ByteString
    m)       = Int -> ByteString -> (ByteString, ByteString)
    B.splitAt 1 ByteString
    zm
            paddingSuccess :: Bool
    paddingSuccess = [Bool] -> Bool
    and' [ ByteString
    zt ByteString -> ByteString -> Bool
    forall a. Eq a => a -> a -> Bool
    == "\x00\x02"
                                  , ByteString
    z  ByteString -> ByteString -> Bool
    forall a. Eq a => a -> a -> Bool
    == "\x00"
                                  , ByteString -> Int
    B.length ByteString
    ps Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    >= 8
                                  ]

    -- | decrypt message using the private key.
    --
    -- When the decryption 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
            -> PrivateKey    -- ^ RSA private key
            -> ByteString    -- ^ cipher text
            -> Either Error ByteString
    decrypt :: Maybe Blinder
    -> PrivateKey -> ByteString -> Either Error ByteString
    decrypt blinder :: Maybe Blinder
    blinder pk :: PrivateKey
    pk c :: ByteString
    c
        | ByteString -> Int
    B.length ByteString
    c Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    /= (PrivateKey -> Int
    private_size PrivateKey
    pk) = Error -> Either Error ByteString
    forall a b. a -> Either a b
    Left Error
    MessageSizeIncorrect
        | Bool
    otherwise                       = ByteString -> Either Error ByteString
    unpad (ByteString -> Either Error ByteString)
    -> ByteString -> Either Error ByteString
    forall a b. (a -> b) -> a -> b
    $ Maybe Blinder -> PrivateKey -> ByteString -> ByteString
    dp Maybe Blinder
    blinder PrivateKey
    pk ByteString
    c

    -- | decrypt message using the private key and by automatically generating a blinder.
    decryptSafer :: CPRG g
                 => g          -- ^ random generator
                 -> PrivateKey -- ^ RSA private key
                 -> ByteString -- ^ cipher text
                 -> (Either Error ByteString, g)
    decryptSafer :: g -> PrivateKey -> ByteString -> (Either Error ByteString, g)
    decryptSafer rng :: g
    rng pk :: PrivateKey
    pk b :: ByteString
    b =
        let (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)
         in (Maybe Blinder
    -> PrivateKey -> ByteString -> Either Error ByteString
    decrypt (Blinder -> Maybe Blinder
    forall a. a -> Maybe a
    Just Blinder
    blinder) PrivateKey
    pk ByteString
    b, g
    rng')

    -- | encrypt a bytestring using the public key and a CPRG random generator.
    --
    -- the message need to be smaller than the key size - 11
    encrypt :: CPRG g => g -> PublicKey -> ByteString -> (Either Error ByteString, g)
    encrypt :: g -> PublicKey -> ByteString -> (Either Error ByteString, g)
    encrypt rng :: g
    rng pk :: PublicKey
    pk m :: ByteString
    m = do
        case g -> Int -> ByteString -> Either Error (ByteString, g)
    forall g.
    CPRG g =>
    g -> Int -> ByteString -> Either Error (ByteString, g)
    pad g
    rng (PublicKey -> Int
    public_size PublicKey
    pk) ByteString
    m of
            Left err :: Error
    err         -> (Error -> Either Error ByteString
    forall a b. a -> Either a b
    Left Error
    err, g
    rng)
            Right (em :: ByteString
    em, rng' :: g
    rng') -> (ByteString -> Either Error ByteString
    forall a b. b -> Either a b
    Right (PublicKey -> ByteString -> ByteString
    ep PublicKey
    pk ByteString
    em), g
    rng')

    -- | sign message using private key, a hash and its ASN1 description
    --
    -- 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 signSafer
    sign :: Maybe Blinder -- ^ optional blinder
         -> HashDescr     -- ^ hash descriptor
         -> PrivateKey    -- ^ private key
         -> ByteString    -- ^ message to sign
         -> Either Error ByteString
    sign :: Maybe Blinder
    -> HashDescr -> PrivateKey -> ByteString -> Either Error ByteString
    sign blinder :: Maybe Blinder
    blinder hashDescr :: HashDescr
    hashDescr pk :: PrivateKey
    pk m :: ByteString
    m = Maybe Blinder -> PrivateKey -> ByteString -> ByteString
    dp Maybe Blinder
    blinder PrivateKey
    pk (ByteString -> ByteString)
    -> Either Error ByteString -> Either Error ByteString
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    `fmap` HashDescr -> Int -> ByteString -> Either Error ByteString
    makeSignature HashDescr
    hashDescr (PrivateKey -> Int
    private_size PrivateKey
    pk) ByteString
    m

    -- | sign message using the private key and by automatically generating a blinder.
    signSafer :: CPRG g
              => g          -- ^ random generator
              -> HashDescr  -- ^ Hash descriptor
              -> PrivateKey -- ^ private key
              -> ByteString -- ^ message to sign
              -> (Either Error ByteString, g)
    signSafer :: g
    -> HashDescr
    -> PrivateKey
    -> ByteString
    -> (Either Error ByteString, g)
    signSafer rng :: g
    rng hashDescr :: HashDescr
    hashDescr pk :: PrivateKey
    pk m :: ByteString
    m =
        let (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)
         in (Maybe Blinder
    -> HashDescr -> PrivateKey -> ByteString -> Either Error ByteString
    sign (Blinder -> Maybe Blinder
    forall a. a -> Maybe a
    Just Blinder
    blinder) HashDescr
    hashDescr PrivateKey
    pk ByteString
    m, g
    rng')

    -- | verify message with the signed message
    verify :: HashDescr -> PublicKey -> ByteString -> ByteString -> Bool
    verify :: HashDescr -> PublicKey -> ByteString -> ByteString -> Bool
    verify hashDescr :: HashDescr
    hashDescr pk :: PublicKey
    pk m :: ByteString
    m sm :: ByteString
    sm =
        case HashDescr -> Int -> ByteString -> Either Error ByteString
    makeSignature HashDescr
    hashDescr (PublicKey -> Int
    public_size PublicKey
    pk) ByteString
    m of
            Left _  -> Bool
    False
            Right s :: ByteString
    s -> ByteString
    s ByteString -> ByteString -> Bool
    forall a. Eq a => a -> a -> Bool
    == (PublicKey -> ByteString -> ByteString
    ep PublicKey
    pk ByteString
    sm)

    {- makeSignature for sign and verify -}
    makeSignature :: HashDescr -> Int -> ByteString -> Either Error ByteString
    makeSignature :: HashDescr -> Int -> ByteString -> Either Error ByteString
    makeSignature hashDescr :: HashDescr
    hashDescr klen :: Int
    klen m :: ByteString
    m = Int -> ByteString -> Either Error ByteString
    padSignature Int
    klen ByteString
    signature
        where signature :: ByteString
    signature = (HashDescr -> ByteString -> ByteString
    digestToASN1 HashDescr
    hashDescr) (ByteString -> ByteString) -> ByteString -> ByteString
    forall a b. (a -> b) -> a -> b
    $ (HashDescr -> ByteString -> ByteString
    hashFunction HashDescr
    hashDescr) ByteString
    m