-- |
-- 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>
module Crypto.PubKey.RSA.OAEP (
    OAEPParams (..),
    defaultOAEPParams,

    -- * OAEP encryption
    encryptWithSeed,
    encrypt,

    -- * OAEP decryption
    decrypt,
    decryptSafer,
    decryptBlinded,
) where

import Crypto.Hash
import Crypto.Number.Serialize (os2ip)
import Crypto.PubKey.Internal (and')
import Crypto.PubKey.MaskGenFunction
import Crypto.PubKey.RSA.Blinded.Internal
import Crypto.PubKey.RSA.Prim
import Crypto.PubKey.RSA.Types
import Crypto.Random.Types
import Data.Bits (complement, shiftR, xor, (.&.), (.|.))
import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import qualified Data.List as L
import Data.Word (Word32)

import Crypto.Internal.ByteArray (ByteArray, ByteArrayAccess)
import qualified Crypto.Internal.ByteArray as B (constEq, convert)

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

-- | Default Params with a specified hash function
defaultOAEPParams
    :: (ByteArrayAccess seed, ByteArray output, HashAlgorithm hash)
    => hash
    -> OAEPParams hash seed output
defaultOAEPParams :: forall seed output hash.
(ByteArrayAccess seed, ByteArray output, HashAlgorithm hash) =>
hash -> OAEPParams hash seed output
defaultOAEPParams hash
hashAlg =
    OAEPParams
        { oaepHash :: hash
oaepHash = hash
hashAlg
        , oaepMaskGenAlg :: MaskGenAlgorithm seed output
oaepMaskGenAlg = hash -> MaskGenAlgorithm seed output
forall seed output hashAlg.
(ByteArrayAccess seed, ByteArray output, HashAlgorithm hashAlg) =>
hashAlg -> seed -> Int -> output
mgf1 hash
hashAlg
        , oaepLabel :: Maybe ByteString
oaepLabel = Maybe ByteString
forall a. Maybe a
Nothing
        }

-- | Encrypt a message using OAEP with a predefined seed.
encryptWithSeed
    :: HashAlgorithm hash
    => ByteString
    -- ^ Seed
    -> OAEPParams hash ByteString ByteString
    -- ^ OAEP params to use for encryption
    -> PublicKey
    -- ^ Public key.
    -> ByteString
    -- ^ Message to encrypt
    -> Either Error ByteString
encryptWithSeed :: forall hash.
HashAlgorithm hash =>
ByteString
-> OAEPParams hash ByteString ByteString
-> PublicKey
-> ByteString
-> Either Error ByteString
encryptWithSeed ByteString
seed OAEPParams hash ByteString ByteString
oaep PublicKey
pk ByteString
msg
    | Int
k Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
hashLen Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
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
- Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
hashLen Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
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 -> ByteString -> ByteString
forall ba. ByteArray ba => PublicKey -> ba -> ba
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
    mgf :: MaskGenAlgorithm ByteString ByteString
mgf = OAEPParams hash ByteString ByteString
-> MaskGenAlgorithm ByteString ByteString
forall hash seed output.
OAEPParams hash seed output -> MaskGenAlgorithm seed output
oaepMaskGenAlg OAEPParams hash ByteString ByteString
oaep
    labelHash :: Digest hash
labelHash = hash -> ByteString -> Digest hash
forall ba alg.
(ByteArrayAccess ba, HashAlgorithm alg) =>
alg -> ba -> Digest alg
hashWith (OAEPParams hash ByteString ByteString -> hash
forall hash seed output. OAEPParams hash seed output -> hash
oaepHash OAEPParams hash ByteString ByteString
oaep) (ByteString
-> (ByteString -> ByteString) -> Maybe ByteString -> ByteString
forall b a. b -> (a -> b) -> Maybe a -> b
maybe ByteString
B.empty ByteString -> ByteString
forall a. a -> a
id (Maybe ByteString -> ByteString) -> Maybe ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ OAEPParams hash ByteString ByteString -> Maybe ByteString
forall hash seed output.
OAEPParams hash seed output -> Maybe ByteString
oaepLabel OAEPParams hash ByteString ByteString
oaep)
    hashLen :: Int
hashLen = hash -> Int
forall a. HashAlgorithm a => a -> Int
hashDigestSize (OAEPParams hash ByteString ByteString -> hash
forall hash seed output. OAEPParams hash seed output -> hash
oaepHash OAEPParams hash ByteString ByteString
oaep)

    -- 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
- Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
hashLen Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
2) Word8
0
    db :: ByteString
db = [ByteString] -> ByteString
B.concat [Digest hash -> ByteString
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
B.convert Digest hash
labelHash, ByteString
ps, Word8 -> ByteString
B.singleton Word8
0x1, ByteString
msg]
    dbmask :: ByteString
dbmask = MaskGenAlgorithm ByteString 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
- Int
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 = MaskGenAlgorithm ByteString 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 Word8
0x0, ByteString
maskedSeed, ByteString
maskedDB]

-- | Encrypt a message using OAEP
encrypt
    :: (HashAlgorithm hash, MonadRandom m)
    => OAEPParams hash ByteString ByteString
    -- ^ OAEP params to use for encryption.
    -> PublicKey
    -- ^ Public key.
    -> ByteString
    -- ^ Message to encrypt
    -> m (Either Error ByteString)
encrypt :: forall hash (m :: * -> *).
(HashAlgorithm hash, MonadRandom m) =>
OAEPParams hash ByteString ByteString
-> PublicKey -> ByteString -> m (Either Error ByteString)
encrypt OAEPParams hash ByteString ByteString
oaep PublicKey
pk ByteString
msg = do
    ByteString
seed <- Int -> m ByteString
forall byteArray. ByteArray byteArray => Int -> m byteArray
forall (m :: * -> *) byteArray.
(MonadRandom m, ByteArray byteArray) =>
Int -> m byteArray
getRandomBytes Int
hashLen
    Either Error ByteString -> m (Either Error ByteString)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (ByteString
-> OAEPParams hash ByteString ByteString
-> PublicKey
-> ByteString
-> Either Error ByteString
forall hash.
HashAlgorithm hash =>
ByteString
-> OAEPParams hash ByteString ByteString
-> PublicKey
-> ByteString
-> Either Error ByteString
encryptWithSeed ByteString
seed OAEPParams hash ByteString ByteString
oaep PublicKey
pk ByteString
msg)
  where
    hashLen :: Int
hashLen = hash -> Int
forall a. HashAlgorithm a => a -> Int
hashDigestSize (OAEPParams hash ByteString ByteString -> hash
forall hash seed output. OAEPParams hash seed output -> hash
oaepHash OAEPParams hash ByteString ByteString
oaep)

-- | un-pad a OAEP encoded message.
--
-- It doesn't apply the RSA decryption primitive
--
-- The data block is scanned in full rather than up to the 01 octet separating
-- the padding from the message, and the label hash and the leading octet are
-- compared without an early exit, so neither the length of the padding nor
-- where a comparison first differs shows up in how long this takes.
--
-- What remains visible is the result itself: whether the block was well formed,
-- and the length of the message when it was.  That is the signal Manger's
-- attack needs, so a caller that decrypts attacker-supplied ciphertext must not
-- pass the distinction on.
unpad
    :: HashAlgorithm hash
    => OAEPParams hash ByteString ByteString
    -- ^ OAEP params to use
    -> Int
    -- ^ size of the key in bytes
    -> ByteString
    -- ^ encoded message (not encrypted)
    -> Either Error ByteString
unpad :: forall hash.
HashAlgorithm hash =>
OAEPParams hash ByteString ByteString
-> Int -> ByteString -> Either Error ByteString
unpad OAEPParams hash ByteString ByteString
oaep Int
k 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
    mgf :: MaskGenAlgorithm ByteString ByteString
mgf = OAEPParams hash ByteString ByteString
-> MaskGenAlgorithm ByteString ByteString
forall hash seed output.
OAEPParams hash seed output -> MaskGenAlgorithm seed output
oaepMaskGenAlg OAEPParams hash ByteString ByteString
oaep
    labelHash :: ByteString
labelHash =
        Digest hash -> ByteString
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
B.convert (Digest hash -> ByteString) -> Digest hash -> ByteString
forall a b. (a -> b) -> a -> b
$ hash -> ByteString -> Digest hash
forall ba alg.
(ByteArrayAccess ba, HashAlgorithm alg) =>
alg -> ba -> Digest alg
hashWith (OAEPParams hash ByteString ByteString -> hash
forall hash seed output. OAEPParams hash seed output -> hash
oaepHash OAEPParams hash ByteString ByteString
oaep) (ByteString
-> (ByteString -> ByteString) -> Maybe ByteString -> ByteString
forall b a. b -> (a -> b) -> Maybe a -> b
maybe ByteString
B.empty ByteString -> ByteString
forall a. a -> a
id (Maybe ByteString -> ByteString) -> Maybe ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ OAEPParams hash ByteString ByteString -> Maybe ByteString
forall hash seed output.
OAEPParams hash seed output -> Maybe ByteString
oaepLabel OAEPParams hash ByteString ByteString
oaep)
            :: ByteString
    hashLen :: Int
hashLen = hash -> Int
forall a. HashAlgorithm a => a -> Int
hashDigestSize (OAEPParams hash ByteString ByteString -> hash
forall hash seed output. OAEPParams hash seed output -> hash
oaepHash OAEPParams hash ByteString ByteString
oaep)
    -- getting em's fields
    (ByteString
pb, ByteString
em0) = Int -> ByteString -> (ByteString, ByteString)
B.splitAt Int
1 ByteString
em
    (ByteString
maskedSeed, ByteString
maskedDB) = Int -> ByteString -> (ByteString, ByteString)
B.splitAt Int
hashLen ByteString
em0
    seedMask :: ByteString
seedMask = MaskGenAlgorithm ByteString 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 = MaskGenAlgorithm ByteString 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
- Int
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
    (ByteString
labelHash', ByteString
db1) = Int -> ByteString -> (ByteString, ByteString)
B.splitAt Int
hashLen ByteString
db

    -- index of the first nonzero octet in db1, or its length when every octet
    -- is zero; all of them are looked at either way
    oneIndex :: Word32
oneIndex =
        (Word32, Word32) -> Word32
forall a b. (a, b) -> a
fst ((Word32, Word32) -> Word32) -> (Word32, Word32) -> Word32
forall a b. (a -> b) -> a -> b
$
            ((Word32, Word32) -> (Word32, Word8) -> (Word32, Word32))
-> (Word32, Word32) -> [(Word32, Word8)] -> (Word32, Word32)
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
L.foldl'
                (Word32, Word32) -> (Word32, Word8) -> (Word32, Word32)
forall {b}.
Integral b =>
(Word32, Word32) -> (Word32, b) -> (Word32, Word32)
step
                (Int -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteString -> Int
B.length ByteString
db1) :: Word32, Word32
1 :: Word32)
                ([Word32] -> [Word8] -> [(Word32, Word8)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Word32
0 ..] (ByteString -> [Word8]
B.unpack ByteString
db1))
    step :: (Word32, Word32) -> (Word32, b) -> (Word32, Word32)
step (Word32
idx, Word32
unseen) (Word32
i, b
b) = (Word32 -> Word32 -> Word32 -> Word32
forall {a}. Bits a => a -> a -> a -> a
select Word32
found Word32
i Word32
idx, Word32
unseen Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. Word32 -> Word32
forall a. Bits a => a -> a
complement Word32
found)
      where
        w :: Word32
w = b -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral b
b :: Word32
        -- 0 when b is zero, 1 otherwise
        nonZero :: Word32
nonZero = (Word32
w Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word32 -> Word32
forall a. Num a => a -> a
negate Word32
w) Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`shiftR` Int
31
        -- all ones at the first nonzero octet only
        found :: Word32
found = Word32 -> Word32
forall a. Num a => a -> a
negate (Word32
unseen Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. Word32
nonZero)
    select :: a -> a -> a -> a
select a
mask a
a a
b = (a
a a -> a -> a
forall a. Bits a => a -> a -> a
.&. a
mask) a -> a -> a
forall a. Bits a => a -> a -> a
.|. (a
b a -> a -> a
forall a. Bits a => a -> a -> a
.&. a -> a
forall a. Bits a => a -> a
complement a
mask)

    ps1 :: ByteString
ps1 = Int -> ByteString -> ByteString
B.take Int
1 (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ Int -> ByteString -> ByteString
B.drop (Word32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
oneIndex) ByteString
db1
    msg :: ByteString
msg = Int -> ByteString -> ByteString
B.drop (Word32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
oneIndex Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) ByteString
db1

    paddingSuccess :: Bool
paddingSuccess =
        [Bool] -> Bool
and'
            [ ByteString
labelHash' ByteString -> ByteString -> Bool
forall bs1 bs2.
(ByteArrayAccess bs1, ByteArrayAccess bs2) =>
bs1 -> bs2 -> Bool
`B.constEq` ByteString
labelHash
            , ByteString
ps1 ByteString -> ByteString -> Bool
forall bs1 bs2.
(ByteArrayAccess bs1, ByteArrayAccess bs2) =>
bs1 -> bs2 -> Bool
`B.constEq` Int -> Word8 -> ByteString
B.replicate Int
1 Word8
0x1
            , ByteString
pb ByteString -> ByteString -> Bool
forall bs1 bs2.
(ByteArrayAccess bs1, ByteArrayAccess bs2) =>
bs1 -> bs2 -> Bool
`B.constEq` Int -> Word8 -> ByteString
B.replicate Int
1 Word8
0x0
            ]

-- | Decrypt a ciphertext using OAEP
--
-- The blinder is optional and 'Nothing' is accepted, but see t'Blinder' for
-- what it covers and when leaving it out is a decision rather than a default.
-- 'decryptSafer' generates one for you.
--
-- Following RFC 8017, the ciphertext is rejected unless it is exactly as long
-- as the modulus (section 7.1.2, step 1) and its integer representative is
-- below the modulus (RSADP, section 5.1.2, step 1).  The decryption primitive
-- normalises any multiple of the modulus away, so without the second check
-- @c + n@ would decrypt to the same message as @c@, and a ciphertext would not
-- be unique to its plaintext.  Both checks are made on the ciphertext alone,
-- which is public, and report 'MessageSizeIncorrect'.
decrypt
    :: HashAlgorithm hash
    => Maybe Blinder
    -- ^ Optional blinder
    -> OAEPParams hash ByteString ByteString
    -- ^ OAEP params to use for decryption
    -> PrivateKey
    -- ^ Private key
    -> ByteString
    -- ^ Cipher text
    -> Either Error ByteString
decrypt :: forall hash.
HashAlgorithm hash =>
Maybe Blinder
-> OAEPParams hash ByteString ByteString
-> PrivateKey
-> ByteString
-> Either Error ByteString
decrypt Maybe Blinder
blinder OAEPParams hash ByteString ByteString
oaep PrivateKey
pk 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
    | ByteString -> Integer
forall ba. ByteArrayAccess ba => ba -> Integer
os2ip ByteString
cipher Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
>= PrivateKey -> Integer
private_n PrivateKey
pk = 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
< Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
hashLen Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2 = Error -> Either Error ByteString
forall a b. a -> Either a b
Left Error
InvalidParameters
    | Bool
otherwise = OAEPParams hash ByteString ByteString
-> Int -> ByteString -> Either Error ByteString
forall hash.
HashAlgorithm hash =>
OAEPParams hash ByteString ByteString
-> Int -> ByteString -> Either Error ByteString
unpad OAEPParams hash ByteString ByteString
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 -> ByteString -> ByteString
forall ba. ByteArray ba => Maybe Blinder -> PrivateKey -> ba -> ba
dp Maybe Blinder
blinder PrivateKey
pk ByteString
cipher
  where
    -- parameters
    k :: Int
k = PrivateKey -> Int
private_size PrivateKey
pk
    hashLen :: Int
hashLen = hash -> Int
forall a. HashAlgorithm a => a -> Int
hashDigestSize (OAEPParams hash ByteString ByteString -> hash
forall hash seed output. OAEPParams hash seed output -> hash
oaepHash OAEPParams hash ByteString ByteString
oaep)

-- | Decrypt a ciphertext using OAEP, blinded with the pair kept for this key;
-- see "Crypto.PubKey.RSA.Blinded".
decryptSafer
    :: (HashAlgorithm hash, MonadRandom m)
    => OAEPParams hash ByteString ByteString
    -- ^ OAEP params to use for decryption
    -> PrivateKey
    -- ^ Private key
    -> ByteString
    -- ^ Cipher text
    -> m (Either Error ByteString)
decryptSafer :: forall hash (m :: * -> *).
(HashAlgorithm hash, MonadRandom m) =>
OAEPParams hash ByteString ByteString
-> PrivateKey -> ByteString -> m (Either Error ByteString)
decryptSafer OAEPParams hash ByteString ByteString
oaep PrivateKey
pk ByteString
cipher
    | ByteString -> Int
B.length ByteString
cipher Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
k = Either Error ByteString -> m (Either Error ByteString)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Error -> Either Error ByteString
forall a b. a -> Either a b
Left Error
MessageSizeIncorrect)
    | ByteString -> Integer
forall ba. ByteArrayAccess ba => ba -> Integer
os2ip ByteString
cipher Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
>= PrivateKey -> Integer
private_n PrivateKey
pk = Either Error ByteString -> m (Either Error ByteString)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (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
< Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
hashLen Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2 = Either Error ByteString -> m (Either Error ByteString)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Error -> Either Error ByteString
forall a b. a -> Either a b
Left Error
InvalidParameters)
    | Bool
otherwise = do
        Draw
d <- PrivateKey -> m Draw
forall (m :: * -> *). MonadRandom m => PrivateKey -> m Draw
drawFor PrivateKey
pk
        Either Error ByteString -> m (Either Error ByteString)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either Error ByteString -> m (Either Error ByteString))
-> Either Error ByteString -> m (Either Error ByteString)
forall a b. (a -> b) -> a -> b
$ PrivateKey
-> Draw
-> ((Integer, Integer) -> Either Error ByteString)
-> Either Error ByteString
forall a. PrivateKey -> Draw -> ((Integer, Integer) -> a) -> a
withBlindingFor PrivateKey
pk Draw
d (((Integer, Integer) -> Either Error ByteString)
 -> Either Error ByteString)
-> ((Integer, Integer) -> Either Error ByteString)
-> Either Error ByteString
forall a b. (a -> b) -> a -> b
$ \(Integer, Integer)
pair -> OAEPParams hash ByteString ByteString
-> Int -> ByteString -> Either Error ByteString
forall hash.
HashAlgorithm hash =>
OAEPParams hash ByteString ByteString
-> Int -> ByteString -> Either Error ByteString
unpad OAEPParams hash ByteString ByteString
oaep Int
k ((Integer, Integer) -> PrivateKey -> ByteString -> ByteString
forall ba.
ByteArray ba =>
(Integer, Integer) -> PrivateKey -> ba -> ba
dpWithPair (Integer, Integer)
pair PrivateKey
pk ByteString
cipher)
  where
    k :: Int
k = PrivateKey -> Int
private_size PrivateKey
pk
    hashLen :: Int
hashLen = hash -> Int
forall a. HashAlgorithm a => a -> Int
hashDigestSize (OAEPParams hash ByteString ByteString -> hash
forall hash seed output. OAEPParams hash seed output -> hash
oaepHash OAEPParams hash ByteString ByteString
oaep)

-- | 'decrypt' with the blinding a t'BlindedKey' keeps, and the key for the
-- next operation.
decryptBlinded
    :: (HashAlgorithm hash, MonadRandom m)
    => OAEPParams hash ByteString ByteString
    -> BlindedKey
    -> ByteString
    -- ^ Cipher text
    -> m (Either Error ByteString, BlindedKey)
decryptBlinded :: forall hash (m :: * -> *).
(HashAlgorithm hash, MonadRandom m) =>
OAEPParams hash ByteString ByteString
-> BlindedKey
-> ByteString
-> m (Either Error ByteString, BlindedKey)
decryptBlinded OAEPParams hash ByteString ByteString
oaep BlindedKey
bk ByteString
cipher
    | ByteString -> Int
B.length ByteString
cipher Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
k = (Either Error ByteString, BlindedKey)
-> m (Either Error ByteString, BlindedKey)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Error -> Either Error ByteString
forall a b. a -> Either a b
Left Error
MessageSizeIncorrect, BlindedKey
bk)
    | ByteString -> Integer
forall ba. ByteArrayAccess ba => ba -> Integer
os2ip ByteString
cipher Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
>= PrivateKey -> Integer
private_n PrivateKey
pk = (Either Error ByteString, BlindedKey)
-> m (Either Error ByteString, BlindedKey)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Error -> Either Error ByteString
forall a b. a -> Either a b
Left Error
MessageSizeIncorrect, BlindedKey
bk)
    | Int
k Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
hashLen Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2 = (Either Error ByteString, BlindedKey)
-> m (Either Error ByteString, BlindedKey)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Error -> Either Error ByteString
forall a b. a -> Either a b
Left Error
InvalidParameters, BlindedKey
bk)
    | Bool
otherwise = do
        (ByteString
m, BlindedKey
bk') <- BlindedKey -> ByteString -> m (ByteString, BlindedKey)
forall (m :: * -> *) ba.
(MonadRandom m, ByteArray ba) =>
BlindedKey -> ba -> m (ba, BlindedKey)
dpBlinded BlindedKey
bk ByteString
cipher
        (Either Error ByteString, BlindedKey)
-> m (Either Error ByteString, BlindedKey)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (OAEPParams hash ByteString ByteString
-> Int -> ByteString -> Either Error ByteString
forall hash.
HashAlgorithm hash =>
OAEPParams hash ByteString ByteString
-> Int -> ByteString -> Either Error ByteString
unpad OAEPParams hash ByteString ByteString
oaep Int
k ByteString
m, BlindedKey
bk')
  where
    pk :: PrivateKey
pk = BlindedKey -> PrivateKey
blindedPrivateKey BlindedKey
bk
    k :: Int
k = PrivateKey -> Int
private_size PrivateKey
pk
    hashLen :: Int
hashLen = hash -> Int
forall a. HashAlgorithm a => a -> Int
hashDigestSize (OAEPParams hash ByteString ByteString -> hash
forall hash seed output. OAEPParams hash seed output -> hash
oaepHash OAEPParams hash ByteString ByteString
oaep)