-- |
-- Module      : Crypto.PubKey.RSA.PKCS15
-- License     : BSD-style
-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
-- Stability   : experimental
-- Portability : Good
module Crypto.PubKey.RSA.PKCS15 (
    -- * Padding and unpadding
    pad,
    padSignature,
    unpad,

    -- * Private key operations
    decrypt,
    decryptSafer,
    sign,
    signSafer,
    signDigest,
    signSaferDigest,
    signDigestInfo,
    signSaferDigestInfo,

    -- * Private key operations with a kept blinding
    decryptBlinded,
    signDigestBlinded,
    signDigestInfoBlinded,

    -- * Public key operations
    encrypt,
    verify,
    verifyDigest,
    verifyDigestInfo,

    -- * Hash ASN1 description
    HashAlgorithmASN1,
) where

import Crypto.Hash
import Crypto.Number.Serialize (os2ip)
import Crypto.PubKey.Internal (and')
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, (.&.), (.|.))
import Data.ByteString (ByteString)
import Data.Word

import Crypto.Internal.ByteArray (ByteArray, Bytes)
import qualified Crypto.Internal.ByteArray as B
import qualified Data.List as L

-- | A specialized class for hash algorithm that can product
-- a ASN1 wrapped description the algorithm plus the content
-- of the digest.
class HashAlgorithm hashAlg => HashAlgorithmASN1 hashAlg where
    -- | Convert a Digest into an ASN1 wrapped descriptive ByteArray
    hashDigestASN1 :: ByteArray out => Digest hashAlg -> out

-- http://uk.emc.com/emc-plus/rsa-labs/pkcs/files/h11300-wp-pkcs-1v2-2-rsa-cryptography-standard.pdf
-- EMSA-PKCS1-v1_5
instance HashAlgorithmASN1 MD2 where
    hashDigestASN1 :: forall out. ByteArray out => Digest MD2 -> out
hashDigestASN1 =
        [Word8] -> Digest MD2 -> out
forall out hashAlg.
ByteArray out =>
[Word8] -> Digest hashAlg -> out
addDigestPrefix
            [ Word8
0x30
            , Word8
0x20
            , Word8
0x30
            , Word8
0x0c
            , Word8
0x06
            , Word8
0x08
            , Word8
0x2a
            , Word8
0x86
            , Word8
0x48
            , Word8
0x86
            , Word8
0xf7
            , Word8
0x0d
            , Word8
0x02
            , Word8
0x02
            , Word8
0x05
            , Word8
0x00
            , Word8
0x04
            , Word8
0x10
            ]
instance HashAlgorithmASN1 MD5 where
    hashDigestASN1 :: forall out. ByteArray out => Digest MD5 -> out
hashDigestASN1 =
        [Word8] -> Digest MD5 -> out
forall out hashAlg.
ByteArray out =>
[Word8] -> Digest hashAlg -> out
addDigestPrefix
            [ Word8
0x30
            , Word8
0x20
            , Word8
0x30
            , Word8
0x0c
            , Word8
0x06
            , Word8
0x08
            , Word8
0x2a
            , Word8
0x86
            , Word8
0x48
            , Word8
0x86
            , Word8
0xf7
            , Word8
0x0d
            , Word8
0x02
            , Word8
0x05
            , Word8
0x05
            , Word8
0x00
            , Word8
0x04
            , Word8
0x10
            ]
instance HashAlgorithmASN1 SHA1 where
    hashDigestASN1 :: forall out. ByteArray out => Digest SHA1 -> out
hashDigestASN1 =
        [Word8] -> Digest SHA1 -> out
forall out hashAlg.
ByteArray out =>
[Word8] -> Digest hashAlg -> out
addDigestPrefix
            [ Word8
0x30
            , Word8
0x21
            , Word8
0x30
            , Word8
0x09
            , Word8
0x06
            , Word8
0x05
            , Word8
0x2b
            , Word8
0x0e
            , Word8
0x03
            , Word8
0x02
            , Word8
0x1a
            , Word8
0x05
            , Word8
0x00
            , Word8
0x04
            , Word8
0x14
            ]
instance HashAlgorithmASN1 SHA224 where
    hashDigestASN1 :: forall out. ByteArray out => Digest SHA224 -> out
hashDigestASN1 =
        [Word8] -> Digest SHA224 -> out
forall out hashAlg.
ByteArray out =>
[Word8] -> Digest hashAlg -> out
addDigestPrefix
            [ Word8
0x30
            , Word8
0x2d
            , Word8
0x30
            , Word8
0x0d
            , Word8
0x06
            , Word8
0x09
            , Word8
0x60
            , Word8
0x86
            , Word8
0x48
            , Word8
0x01
            , Word8
0x65
            , Word8
0x03
            , Word8
0x04
            , Word8
0x02
            , Word8
0x04
            , Word8
0x05
            , Word8
0x00
            , Word8
0x04
            , Word8
0x1c
            ]
instance HashAlgorithmASN1 SHA256 where
    hashDigestASN1 :: forall out. ByteArray out => Digest SHA256 -> out
hashDigestASN1 =
        [Word8] -> Digest SHA256 -> out
forall out hashAlg.
ByteArray out =>
[Word8] -> Digest hashAlg -> out
addDigestPrefix
            [ Word8
0x30
            , Word8
0x31
            , Word8
0x30
            , Word8
0x0d
            , Word8
0x06
            , Word8
0x09
            , Word8
0x60
            , Word8
0x86
            , Word8
0x48
            , Word8
0x01
            , Word8
0x65
            , Word8
0x03
            , Word8
0x04
            , Word8
0x02
            , Word8
0x01
            , Word8
0x05
            , Word8
0x00
            , Word8
0x04
            , Word8
0x20
            ]
instance HashAlgorithmASN1 SHA384 where
    hashDigestASN1 :: forall out. ByteArray out => Digest SHA384 -> out
hashDigestASN1 =
        [Word8] -> Digest SHA384 -> out
forall out hashAlg.
ByteArray out =>
[Word8] -> Digest hashAlg -> out
addDigestPrefix
            [ Word8
0x30
            , Word8
0x41
            , Word8
0x30
            , Word8
0x0d
            , Word8
0x06
            , Word8
0x09
            , Word8
0x60
            , Word8
0x86
            , Word8
0x48
            , Word8
0x01
            , Word8
0x65
            , Word8
0x03
            , Word8
0x04
            , Word8
0x02
            , Word8
0x02
            , Word8
0x05
            , Word8
0x00
            , Word8
0x04
            , Word8
0x30
            ]
instance HashAlgorithmASN1 SHA512 where
    hashDigestASN1 :: forall out. ByteArray out => Digest SHA512 -> out
hashDigestASN1 =
        [Word8] -> Digest SHA512 -> out
forall out hashAlg.
ByteArray out =>
[Word8] -> Digest hashAlg -> out
addDigestPrefix
            [ Word8
0x30
            , Word8
0x51
            , Word8
0x30
            , Word8
0x0d
            , Word8
0x06
            , Word8
0x09
            , Word8
0x60
            , Word8
0x86
            , Word8
0x48
            , Word8
0x01
            , Word8
0x65
            , Word8
0x03
            , Word8
0x04
            , Word8
0x02
            , Word8
0x03
            , Word8
0x05
            , Word8
0x00
            , Word8
0x04
            , Word8
0x40
            ]
instance HashAlgorithmASN1 SHA512t_224 where
    hashDigestASN1 :: forall out. ByteArray out => Digest SHA512t_224 -> out
hashDigestASN1 =
        [Word8] -> Digest SHA512t_224 -> out
forall out hashAlg.
ByteArray out =>
[Word8] -> Digest hashAlg -> out
addDigestPrefix
            [ Word8
0x30
            , Word8
0x2d
            , Word8
0x30
            , Word8
0x0d
            , Word8
0x06
            , Word8
0x09
            , Word8
0x60
            , Word8
0x86
            , Word8
0x48
            , Word8
0x01
            , Word8
0x65
            , Word8
0x03
            , Word8
0x04
            , Word8
0x02
            , Word8
0x05
            , Word8
0x05
            , Word8
0x00
            , Word8
0x04
            , Word8
0x1c
            ]
instance HashAlgorithmASN1 SHA512t_256 where
    hashDigestASN1 :: forall out. ByteArray out => Digest SHA512t_256 -> out
hashDigestASN1 =
        [Word8] -> Digest SHA512t_256 -> out
forall out hashAlg.
ByteArray out =>
[Word8] -> Digest hashAlg -> out
addDigestPrefix
            [ Word8
0x30
            , Word8
0x31
            , Word8
0x30
            , Word8
0x0d
            , Word8
0x06
            , Word8
0x09
            , Word8
0x60
            , Word8
0x86
            , Word8
0x48
            , Word8
0x01
            , Word8
0x65
            , Word8
0x03
            , Word8
0x04
            , Word8
0x02
            , Word8
0x06
            , Word8
0x05
            , Word8
0x00
            , Word8
0x04
            , Word8
0x20
            ]
instance HashAlgorithmASN1 SHA3_224 where
    hashDigestASN1 :: forall out. ByteArray out => Digest SHA3_224 -> out
hashDigestASN1 =
        [Word8] -> Digest SHA3_224 -> out
forall out hashAlg.
ByteArray out =>
[Word8] -> Digest hashAlg -> out
addDigestPrefix
            [ Word8
0x30
            , Word8
0x2b
            , Word8
0x30
            , Word8
0x0b
            , Word8
0x06
            , Word8
0x09
            , Word8
0x60
            , Word8
0x86
            , Word8
0x48
            , Word8
0x01
            , Word8
0x65
            , Word8
0x03
            , Word8
0x04
            , Word8
0x02
            , Word8
0x07
            , Word8
0x04
            , Word8
0x1c
            ]
instance HashAlgorithmASN1 SHA3_256 where
    hashDigestASN1 :: forall out. ByteArray out => Digest SHA3_256 -> out
hashDigestASN1 =
        [Word8] -> Digest SHA3_256 -> out
forall out hashAlg.
ByteArray out =>
[Word8] -> Digest hashAlg -> out
addDigestPrefix
            [ Word8
0x30
            , Word8
0x2f
            , Word8
0x30
            , Word8
0x0b
            , Word8
0x06
            , Word8
0x09
            , Word8
0x60
            , Word8
0x86
            , Word8
0x48
            , Word8
0x01
            , Word8
0x65
            , Word8
0x03
            , Word8
0x04
            , Word8
0x02
            , Word8
0x08
            , Word8
0x04
            , Word8
0x20
            ]
instance HashAlgorithmASN1 SHA3_384 where
    hashDigestASN1 :: forall out. ByteArray out => Digest SHA3_384 -> out
hashDigestASN1 =
        [Word8] -> Digest SHA3_384 -> out
forall out hashAlg.
ByteArray out =>
[Word8] -> Digest hashAlg -> out
addDigestPrefix
            [ Word8
0x30
            , Word8
0x3f
            , Word8
0x30
            , Word8
0x0b
            , Word8
0x06
            , Word8
0x09
            , Word8
0x60
            , Word8
0x86
            , Word8
0x48
            , Word8
0x01
            , Word8
0x65
            , Word8
0x03
            , Word8
0x04
            , Word8
0x02
            , Word8
0x09
            , Word8
0x04
            , Word8
0x30
            ]
instance HashAlgorithmASN1 SHA3_512 where
    hashDigestASN1 :: forall out. ByteArray out => Digest SHA3_512 -> out
hashDigestASN1 =
        [Word8] -> Digest SHA3_512 -> out
forall out hashAlg.
ByteArray out =>
[Word8] -> Digest hashAlg -> out
addDigestPrefix
            [ Word8
0x30
            , Word8
0x4f
            , Word8
0x30
            , Word8
0x0b
            , Word8
0x06
            , Word8
0x09
            , Word8
0x60
            , Word8
0x86
            , Word8
0x48
            , Word8
0x01
            , Word8
0x65
            , Word8
0x03
            , Word8
0x04
            , Word8
0x02
            , Word8
0x0a
            , Word8
0x04
            , Word8
0x40
            ]
instance HashAlgorithmASN1 RIPEMD160 where
    hashDigestASN1 :: forall out. ByteArray out => Digest RIPEMD160 -> out
hashDigestASN1 =
        [Word8] -> Digest RIPEMD160 -> out
forall out hashAlg.
ByteArray out =>
[Word8] -> Digest hashAlg -> out
addDigestPrefix
            [ Word8
0x30
            , Word8
0x21
            , Word8
0x30
            , Word8
0x09
            , Word8
0x06
            , Word8
0x05
            , Word8
0x2b
            , Word8
0x24
            , Word8
0x03
            , Word8
0x02
            , Word8
0x01
            , Word8
0x05
            , Word8
0x00
            , Word8
0x04
            , Word8
0x14
            ]

--

-- ** Hack **

--
-- this happens to not need a real ASN1 encoder, because
-- thanks to the digest being a specific size AND
-- that the digest data is the last bytes in the encoding,
-- this allows to just prepend the right prefix to the
-- computed digest, to make it in the expected and valid shape.
--
-- Otherwise the expected structure is in the following form:
--
--   Start Sequence
--     ,Start Sequence
--       ,OID oid
--       ,optional parameters (Null for SHA-2, absent for SHA-3)
--     ,End Sequence
--     ,OctetString digest
--   ,End Sequence
addDigestPrefix :: ByteArray out => [Word8] -> Digest hashAlg -> out
addDigestPrefix :: forall out hashAlg.
ByteArray out =>
[Word8] -> Digest hashAlg -> out
addDigestPrefix [Word8]
prefix Digest hashAlg
digest =
    [Word8] -> out
forall a. ByteArray a => [Word8] -> a
B.pack [Word8]
prefix out -> out -> out
forall bs. ByteArray bs => bs -> bs -> bs
`B.append` Digest hashAlg -> out
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
B.convert Digest hashAlg
digest

-- | This produce a standard PKCS1.5 padding for encryption
pad
    :: (MonadRandom m, ByteArray message) => Int -> message -> m (Either Error message)
pad :: forall (m :: * -> *) message.
(MonadRandom m, ByteArray message) =>
Int -> message -> m (Either Error message)
pad Int
len message
m
    | message -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length message
m Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
len Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
11 = Either Error message -> m (Either Error message)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Error -> Either Error message
forall a b. a -> Either a b
Left Error
MessageTooLong)
    | Bool
otherwise = do
        message
padding <- Int -> m message
forall bytearray (m :: * -> *).
(ByteArray bytearray, MonadRandom m) =>
Int -> m bytearray
getNonNullRandom (Int
len Int -> Int -> Int
forall a. Num a => a -> a -> a
- message -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length message
m Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
3)
        Either Error message -> m (Either Error message)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either Error message -> m (Either Error message))
-> Either Error message -> m (Either Error message)
forall a b. (a -> b) -> a -> b
$ message -> Either Error message
forall a b. b -> Either a b
Right (message -> Either Error message)
-> message -> Either Error message
forall a b. (a -> b) -> a -> b
$ [message] -> message
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
[bin] -> bout
B.concat [[Word8] -> message
forall a. ByteArray a => [Word8] -> a
B.pack [Word8
0, Word8
2], message
padding, [Word8] -> message
forall a. ByteArray a => [Word8] -> a
B.pack [Word8
0], message
m]
  where
    -- get random non-null bytes
    getNonNullRandom :: (ByteArray bytearray, MonadRandom m) => Int -> m bytearray
    getNonNullRandom :: forall bytearray (m :: * -> *).
(ByteArray bytearray, MonadRandom m) =>
Int -> m bytearray
getNonNullRandom Int
n = do
        Bytes
bs0 <- Int -> m Bytes
forall byteArray. ByteArray byteArray => Int -> m byteArray
forall (m :: * -> *) byteArray.
(MonadRandom m, ByteArray byteArray) =>
Int -> m byteArray
getRandomBytes Int
n
        let bytes :: bytearray
bytes = [Word8] -> bytearray
forall a. ByteArray a => [Word8] -> a
B.pack ([Word8] -> bytearray) -> [Word8] -> bytearray
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
/= Word8
0) ([Word8] -> [Word8]) -> [Word8] -> [Word8]
forall a b. (a -> b) -> a -> b
$ Bytes -> [Word8]
forall a. ByteArrayAccess a => a -> [Word8]
B.unpack (Bytes
bs0 :: Bytes)
            left :: Int
left = Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- bytearray -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length bytearray
bytes
        if Int
left Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0
            then bytearray -> m bytearray
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return bytearray
bytes
            else do
                bytearray
bend <- Int -> m bytearray
forall bytearray (m :: * -> *).
(ByteArray bytearray, MonadRandom m) =>
Int -> m bytearray
getNonNullRandom Int
left
                bytearray -> m bytearray
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (bytearray
bytes bytearray -> bytearray -> bytearray
forall bs. ByteArray bs => bs -> bs -> bs
`B.append` bytearray
bend)

-- | Produce a standard PKCS1.5 padding for signature
padSignature
    :: ByteArray signature => Int -> signature -> Either Error signature
padSignature :: forall signature.
ByteArray signature =>
Int -> signature -> Either Error signature
padSignature Int
klen signature
signature
    | Int
klen Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
siglen Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
11 = Error -> Either Error signature
forall a b. a -> Either a b
Left Error
SignatureTooLong
    | Bool
otherwise =
        signature -> Either Error signature
forall a b. b -> Either a b
Right ([signature] -> signature
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
[bin] -> bout
B.concat [[Word8] -> signature
forall a. ByteArray a => [Word8] -> a
B.pack [Word8
0, Word8
1], Int -> Word8 -> signature
forall ba. ByteArray ba => Int -> Word8 -> ba
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
- Int
3) Word8
0xff, [Word8] -> signature
forall a. ByteArray a => [Word8] -> a
B.pack [Word8
0], signature
signature])
  where
    siglen :: Int
siglen = signature -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length signature
signature

-- | Try to remove a standard PKCS1.5 encryption padding.
--
-- The block is scanned in full rather than up to the octet ending the padding
-- string, so how long that string is does not show up in how long this takes.
--
-- What remains visible is the result itself: whether the padding was well
-- formed, and the length of the message when it was.  That is inherent to the
-- scheme, and it is the signal Bleichenbacher's attack needs, so a caller that
-- decrypts attacker-supplied ciphertext must not pass the distinction on --
-- TLS, for instance, continues with a random premaster secret and reports
-- nothing.
unpad :: ByteArray bytearray => bytearray -> Either Error bytearray
unpad :: forall bytearray.
ByteArray bytearray =>
bytearray -> Either Error bytearray
unpad bytearray
packed
    | Bool
paddingSuccess = bytearray -> Either Error bytearray
forall a b. b -> Either a b
Right bytearray
m
    | Bool
otherwise = Error -> Either Error bytearray
forall a b. a -> Either a b
Left Error
MessageNotRecognized
  where
    len :: Int
len = bytearray -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length bytearray
packed
    (bytearray
zt, bytearray
ps0m) = Int -> bytearray -> (bytearray, bytearray)
forall bs. ByteArray bs => Int -> bs -> (bs, bs)
B.splitAt Int
2 bytearray
packed

    -- index of the first zero octet in ps0m, counted from the start of packed,
    -- or len when there is none; every octet is looked at either way
    zeroIndex :: Word32
zeroIndex = (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 Int
len :: Word32, Word32
1 :: Word32) [(Word32, Word8)]
indexed
    indexed :: [(Word32, Word8)]
indexed = [Word32] -> [Word8] -> [(Word32, Word8)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Word32
2 ..] (bytearray -> [Word8]
forall a. ByteArrayAccess a => a -> [Word8]
B.unpack bytearray
ps0m)
    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 zero 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 -> Word32
forall a. Bits a => a -> a
complement 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)

    psLength :: Int
psLength = Word32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
zeroIndex Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
2 :: Int
    m :: bytearray
m = Int -> bytearray -> bytearray
forall bs. ByteArray bs => Int -> bs -> bs
B.drop (Word32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
zeroIndex Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) bytearray
packed
    paddingSuccess :: Bool
paddingSuccess =
        [Bool] -> Bool
and'
            [ bytearray
zt bytearray -> Bytes -> Bool
forall bs1 bs2.
(ByteArrayAccess bs1, ByteArrayAccess bs2) =>
bs1 -> bs2 -> Bool
`B.constEq` ([Word8] -> Bytes
forall a. ByteArray a => [Word8] -> a
B.pack [Word8
0, Word8
2] :: Bytes)
            , Word32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
zeroIndex Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
len
            , Int
psLength Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
8
            ]

-- | decrypt message using the private key.
--
-- 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.
--
-- The message is returned un-padded.
--
-- Following RFC 8017, the ciphertext is rejected unless it is exactly as long
-- as the modulus (section 7.2.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
    :: ByteArray ba
    => Maybe Blinder
    -- ^ optional blinder
    -> PrivateKey
    -- ^ RSA private key
    -> ByteString
    -- ^ cipher text
    -> Either Error ba
decrypt :: forall ba.
ByteArray ba =>
Maybe Blinder -> PrivateKey -> ByteString -> Either Error ba
decrypt Maybe Blinder
blinder PrivateKey
pk ByteString
c
    | ByteString -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ByteString
c Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= (PrivateKey -> Int
private_size PrivateKey
pk) = Error -> Either Error ba
forall a b. a -> Either a b
Left Error
MessageSizeIncorrect
    | ByteString -> Integer
forall ba. ByteArrayAccess ba => ba -> Integer
os2ip ByteString
c Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
>= PrivateKey -> Integer
private_n PrivateKey
pk = Error -> Either Error ba
forall a b. a -> Either a b
Left Error
MessageSizeIncorrect
    -- "convert" must be apply to "c".
    | Bool
otherwise = ba -> Either Error ba
forall bytearray.
ByteArray bytearray =>
bytearray -> Either Error bytearray
unpad (ba -> Either Error ba) -> ba -> Either Error ba
forall a b. (a -> b) -> a -> b
$ Maybe Blinder -> PrivateKey -> ba -> ba
forall ba. ByteArray ba => Maybe Blinder -> PrivateKey -> ba -> ba
dp Maybe Blinder
blinder PrivateKey
pk (ba -> ba) -> ba -> ba
forall a b. (a -> b) -> a -> b
$ ByteString -> ba
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
B.convert ByteString
c

-- | decrypt message using the private key, blinded with the pair kept for
-- this key; see "Crypto.PubKey.RSA.Blinded".
decryptSafer
    :: (MonadRandom m, ByteArray ba)
    => PrivateKey
    -- ^ RSA private key
    -> ByteString
    -- ^ cipher text
    -> m (Either Error ba)
decryptSafer :: forall (m :: * -> *) ba.
(MonadRandom m, ByteArray ba) =>
PrivateKey -> ByteString -> m (Either Error ba)
decryptSafer PrivateKey
pk ByteString
b
    | ByteString -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ByteString
b Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= PrivateKey -> Int
private_size PrivateKey
pk = Either Error ba -> m (Either Error ba)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Error -> Either Error ba
forall a b. a -> Either a b
Left Error
MessageSizeIncorrect)
    | ByteString -> Integer
forall ba. ByteArrayAccess ba => ba -> Integer
os2ip ByteString
b Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
>= PrivateKey -> Integer
private_n PrivateKey
pk = Either Error ba -> m (Either Error ba)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Error -> Either Error ba
forall a b. a -> Either a b
Left Error
MessageSizeIncorrect)
    | Bool
otherwise = do
        Draw
d <- PrivateKey -> m Draw
forall (m :: * -> *). MonadRandom m => PrivateKey -> m Draw
drawFor PrivateKey
pk
        Either Error ba -> m (Either Error ba)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either Error ba -> m (Either Error ba))
-> Either Error ba -> m (Either Error ba)
forall a b. (a -> b) -> a -> b
$ PrivateKey
-> Draw
-> ((Integer, Integer) -> Either Error ba)
-> Either Error ba
forall a. PrivateKey -> Draw -> ((Integer, Integer) -> a) -> a
withBlindingFor PrivateKey
pk Draw
d (((Integer, Integer) -> Either Error ba) -> Either Error ba)
-> ((Integer, Integer) -> Either Error ba) -> Either Error ba
forall a b. (a -> b) -> a -> b
$ \(Integer, Integer)
pair -> ba -> Either Error ba
forall bytearray.
ByteArray bytearray =>
bytearray -> Either Error bytearray
unpad ((Integer, Integer) -> PrivateKey -> ba -> ba
forall ba.
ByteArray ba =>
(Integer, Integer) -> PrivateKey -> ba -> ba
dpWithPair (Integer, Integer)
pair PrivateKey
pk (ByteString -> ba
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
B.convert ByteString
b))

-- | 'decrypt' with the blinding a t'BlindedKey' keeps, and the key for the
-- next operation.
decryptBlinded
    :: (MonadRandom m, ByteArray ba)
    => BlindedKey
    -> ByteString
    -- ^ cipher text
    -> m (Either Error ba, BlindedKey)
decryptBlinded :: forall (m :: * -> *) ba.
(MonadRandom m, ByteArray ba) =>
BlindedKey -> ByteString -> m (Either Error ba, BlindedKey)
decryptBlinded BlindedKey
bk ByteString
c
    | ByteString -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ByteString
c Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= PrivateKey -> Int
private_size PrivateKey
pk = (Either Error ba, BlindedKey) -> m (Either Error ba, BlindedKey)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Error -> Either Error ba
forall a b. a -> Either a b
Left Error
MessageSizeIncorrect, BlindedKey
bk)
    | ByteString -> Integer
forall ba. ByteArrayAccess ba => ba -> Integer
os2ip ByteString
c Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
>= PrivateKey -> Integer
private_n PrivateKey
pk = (Either Error ba, BlindedKey) -> m (Either Error ba, BlindedKey)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Error -> Either Error ba
forall a b. a -> Either a b
Left Error
MessageSizeIncorrect, BlindedKey
bk)
    | Bool
otherwise = do
        (ba
m, BlindedKey
bk') <- BlindedKey -> ba -> m (ba, BlindedKey)
forall (m :: * -> *) ba.
(MonadRandom m, ByteArray ba) =>
BlindedKey -> ba -> m (ba, BlindedKey)
dpBlinded BlindedKey
bk (ByteString -> ba
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
B.convert ByteString
c)
        (Either Error ba, BlindedKey) -> m (Either Error ba, BlindedKey)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (ba -> Either Error ba
forall bytearray.
ByteArray bytearray =>
bytearray -> Either Error bytearray
unpad ba
m, BlindedKey
bk')
  where
    pk :: PrivateKey
pk = BlindedKey -> PrivateKey
blindedPrivateKey BlindedKey
bk

-- | encrypt a bytestring using the public key.
--
-- The message needs to be smaller than the key size - 11.
-- The message should not be padded.
encrypt
    :: (MonadRandom m, ByteArray ba) => PublicKey -> ba -> m (Either Error ByteString)
encrypt :: forall (m :: * -> *) ba.
(MonadRandom m, ByteArray ba) =>
PublicKey -> ba -> m (Either Error ByteString)
encrypt PublicKey
pk ba
m = do
    Either Error ba
r <- Int -> ba -> m (Either Error ba)
forall (m :: * -> *) message.
(MonadRandom m, ByteArray message) =>
Int -> message -> m (Either Error message)
pad (PublicKey -> Int
public_size PublicKey
pk) ba
m
    case Either Error ba
r of
        Left Error
err -> 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
$ Error -> Either Error ByteString
forall a b. a -> Either a b
Left Error
err
        Right ba
em -> 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
$ ByteString -> Either Error ByteString
forall a b. b -> Either a b
Right (ba -> ByteString
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
B.convert (ba -> ByteString) -> ba -> ByteString
forall a b. (a -> b) -> a -> b
$ PublicKey -> ba -> ba
forall ba. ByteArray ba => PublicKey -> ba -> ba
ep PublicKey
pk ba
em)

-- | sign message using private key, a hash and its ASN1 description
--
-- __Deprecated.__  Use 'signDigest', or 'signDigestInfo' where this would
-- have been given 'Nothing'.  The @Maybe hashAlg@ argument says both \"hash
-- it with this\" and \"do not hash it\", and down the first path the value
-- inside the 'Just' is never read: it is there to fix the type, which
-- leaves a caller that has only a type with nothing to pass.
--
-- 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.
-- 'signSafer' generates one for you.
sign
    :: HashAlgorithmASN1 hashAlg
    => Maybe Blinder
    -- ^ optional blinder
    -> Maybe hashAlg
    -- ^ hash algorithm
    -> PrivateKey
    -- ^ private key
    -> ByteString
    -- ^ message to sign
    -> Either Error ByteString
sign :: forall hashAlg.
HashAlgorithmASN1 hashAlg =>
Maybe Blinder
-> Maybe hashAlg
-> PrivateKey
-> ByteString
-> Either Error ByteString
sign Maybe Blinder
blinder Maybe hashAlg
hashDescr PrivateKey
pk ByteString
m = Maybe Blinder -> PrivateKey -> ByteString -> ByteString
forall ba. ByteArray ba => Maybe Blinder -> PrivateKey -> ba -> ba
dp Maybe Blinder
blinder PrivateKey
pk (ByteString -> ByteString)
-> Either Error ByteString -> Either Error ByteString
forall a b. (a -> b) -> Either Error a -> Either Error b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` Maybe hashAlg -> Int -> ByteString -> Either Error ByteString
forall hashAlg.
HashAlgorithmASN1 hashAlg =>
Maybe hashAlg -> Int -> ByteString -> Either Error ByteString
makeSignature Maybe hashAlg
hashDescr (PrivateKey -> Int
private_size PrivateKey
pk) ByteString
m
{-# DEPRECATED
    sign
    "Use signDigest, or signDigestInfo when the message is already a DigestInfo"
    #-}

-- | sign message using the private key, blinded with the pair kept for this
-- key; see "Crypto.PubKey.RSA.Blinded".
--
-- __Deprecated.__  Use 'signSaferDigest', or 'signSaferDigestInfo'.
signSafer
    :: (HashAlgorithmASN1 hashAlg, MonadRandom m)
    => Maybe hashAlg
    -- ^ Hash algorithm
    -> PrivateKey
    -- ^ private key
    -> ByteString
    -- ^ message to sign
    -> m (Either Error ByteString)
signSafer :: forall hashAlg (m :: * -> *).
(HashAlgorithmASN1 hashAlg, MonadRandom m) =>
Maybe hashAlg
-> PrivateKey -> ByteString -> m (Either Error ByteString)
signSafer Maybe hashAlg
hashAlg PrivateKey
pk ByteString
m = 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 -> Either Error ByteString -> Either Error ByteString
signWithBlindingFor PrivateKey
pk Draw
d (Maybe hashAlg -> Int -> ByteString -> Either Error ByteString
forall hashAlg.
HashAlgorithmASN1 hashAlg =>
Maybe hashAlg -> Int -> ByteString -> Either Error ByteString
makeSignature Maybe hashAlg
hashAlg (PrivateKey -> Int
private_size PrivateKey
pk) ByteString
m)
{-# DEPRECATED
    signSafer
    "Use signSaferDigest, or signSaferDigestInfo when the message is already a DigestInfo"
    #-}

-- | verify message with the signed message
--
-- __Deprecated.__  Use 'verifyDigest', or 'verifyDigestInfo' where this
-- would have been given 'Nothing'.
--
-- Following RFC 8017, the signature is rejected unless it is exactly as long
-- as the modulus (section 8.2.2, step 1) and its integer representative is
-- below the modulus (section 5.2.2, step 1).  Verification works by
-- re-encoding the expected signature and comparing it with the result of the
-- public-key operation, and that operation normalises away both the length of
-- the encoding and any multiple of the modulus; without these checks a
-- zero-padded signature, or @s + n@, would verify just as well as @s@.
verify
    :: HashAlgorithmASN1 hashAlg
    => Maybe hashAlg
    -> PublicKey
    -> ByteString
    -- ^ Message
    -> ByteString
    -- ^ Signature
    -> Bool
verify :: forall hashAlg.
HashAlgorithmASN1 hashAlg =>
Maybe hashAlg -> PublicKey -> ByteString -> ByteString -> Bool
verify Maybe hashAlg
hashAlg PublicKey
pk ByteString
m ByteString
sm =
    PublicKey -> Either Error ByteString -> ByteString -> Bool
verifyEncoded PublicKey
pk (Maybe hashAlg -> Int -> ByteString -> Either Error ByteString
forall hashAlg.
HashAlgorithmASN1 hashAlg =>
Maybe hashAlg -> Int -> ByteString -> Either Error ByteString
makeSignature Maybe hashAlg
hashAlg (PublicKey -> Int
public_size PublicKey
pk) ByteString
m) ByteString
sm
{-# DEPRECATED
    verify
    "Use verifyDigest, or verifyDigestInfo when the message is already a DigestInfo"
    #-}

-- | The two checks of RFC 8017 and the comparison, shared by the three
-- verification entry points.  The expected encoding is a thunk and is
-- forced only once the checks have passed, as it was when this was written
-- out inside 'verify'.
verifyEncoded
    :: PublicKey
    -> Either Error ByteString
    -- ^ the encoding a signature of this message would have
    -> ByteString
    -- ^ signature
    -> Bool
verifyEncoded :: PublicKey -> Either Error ByteString -> ByteString -> Bool
verifyEncoded PublicKey
pk Either Error ByteString
expected ByteString
sm
    | ByteString -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ByteString
sm Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= PublicKey -> Int
public_size PublicKey
pk = Bool
False
    | ByteString -> Integer
forall ba. ByteArrayAccess ba => ba -> Integer
os2ip ByteString
sm Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
>= PublicKey -> Integer
public_n PublicKey
pk = Bool
False
    | Bool
otherwise =
        case Either Error ByteString
expected of
            Left Error
_ -> Bool
False
            Right ByteString
s -> ByteString
s ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== PublicKey -> ByteString -> ByteString
forall ba. ByteArray ba => PublicKey -> ba -> ba
ep PublicKey
pk ByteString
sm

-- | Sign a digest.
--
-- The digest's type says which algorithm made it, so this needs nothing
-- else to name one: the ASN.1 DigestInfo prefix comes from the
-- 'HashAlgorithmASN1' instance that type selects.  'sign' takes @Maybe
-- hashAlg@ and never reads the value inside the @Just@ -- it is there only
-- to fix the type -- which is no burden when the caller has a value and
-- leaves nothing to pass when the caller is itself polymorphic in the
-- algorithm.
--
-- > signDigest blinder key (hashWith SHA256 message)
--
-- 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.  'signSaferDigest' generates one for you.
signDigest
    :: HashAlgorithmASN1 hashAlg
    => Maybe Blinder
    -- ^ optional blinder
    -> PrivateKey
    -- ^ private key
    -> Digest hashAlg
    -- ^ digest of the message to sign
    -> Either Error ByteString
signDigest :: forall hashAlg.
HashAlgorithmASN1 hashAlg =>
Maybe Blinder
-> PrivateKey -> Digest hashAlg -> Either Error ByteString
signDigest Maybe Blinder
blinder PrivateKey
pk Digest hashAlg
digest =
    Maybe Blinder -> PrivateKey -> ByteString -> ByteString
forall ba. ByteArray ba => Maybe Blinder -> PrivateKey -> ba -> ba
dp Maybe Blinder
blinder PrivateKey
pk (ByteString -> ByteString)
-> Either Error ByteString -> Either Error ByteString
forall a b. (a -> b) -> Either Error a -> Either Error b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` Int -> ByteString -> Either Error ByteString
forall signature.
ByteArray signature =>
Int -> signature -> Either Error signature
padSignature (PrivateKey -> Int
private_size PrivateKey
pk) (Digest hashAlg -> ByteString
forall out. ByteArray out => Digest hashAlg -> out
forall hashAlg out.
(HashAlgorithmASN1 hashAlg, ByteArray out) =>
Digest hashAlg -> out
hashDigestASN1 Digest hashAlg
digest)

-- | 'signDigest' blinded with the pair kept for this key, as 'signSafer' is
-- to 'sign'; see "Crypto.PubKey.RSA.Blinded".
signSaferDigest
    :: (HashAlgorithmASN1 hashAlg, MonadRandom m)
    => PrivateKey
    -- ^ private key
    -> Digest hashAlg
    -- ^ digest of the message to sign
    -> m (Either Error ByteString)
signSaferDigest :: forall hashAlg (m :: * -> *).
(HashAlgorithmASN1 hashAlg, MonadRandom m) =>
PrivateKey -> Digest hashAlg -> m (Either Error ByteString)
signSaferDigest PrivateKey
pk Digest hashAlg
digest = 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 -> Either Error ByteString -> Either Error ByteString
signWithBlindingFor PrivateKey
pk Draw
d (Int -> ByteString -> Either Error ByteString
forall signature.
ByteArray signature =>
Int -> signature -> Either Error signature
padSignature (PrivateKey -> Int
private_size PrivateKey
pk) (Digest hashAlg -> ByteString
forall out. ByteArray out => Digest hashAlg -> out
forall hashAlg out.
(HashAlgorithmASN1 hashAlg, ByteArray out) =>
Digest hashAlg -> out
hashDigestASN1 Digest hashAlg
digest))

-- | 'signDigest' with the blinding a t'BlindedKey' keeps, and the key for the
-- next operation.
signDigestBlinded
    :: (HashAlgorithmASN1 hashAlg, MonadRandom m)
    => BlindedKey
    -> Digest hashAlg
    -- ^ digest of the message to sign
    -> m (Either Error ByteString, BlindedKey)
signDigestBlinded :: forall hashAlg (m :: * -> *).
(HashAlgorithmASN1 hashAlg, MonadRandom m) =>
BlindedKey
-> Digest hashAlg -> m (Either Error ByteString, BlindedKey)
signDigestBlinded BlindedKey
bk Digest hashAlg
digest =
    BlindedKey
-> Either Error ByteString
-> m (Either Error ByteString, BlindedKey)
forall (m :: * -> *).
MonadRandom m =>
BlindedKey
-> Either Error ByteString
-> m (Either Error ByteString, BlindedKey)
signBlindedEncoded BlindedKey
bk (Either Error ByteString
 -> m (Either Error ByteString, BlindedKey))
-> Either Error ByteString
-> m (Either Error ByteString, BlindedKey)
forall a b. (a -> b) -> a -> b
$
        Int -> ByteString -> Either Error ByteString
forall signature.
ByteArray signature =>
Int -> signature -> Either Error signature
padSignature (PrivateKey -> Int
private_size (BlindedKey -> PrivateKey
blindedPrivateKey BlindedKey
bk)) (Digest hashAlg -> ByteString
forall out. ByteArray out => Digest hashAlg -> out
forall hashAlg out.
(HashAlgorithmASN1 hashAlg, ByteArray out) =>
Digest hashAlg -> out
hashDigestASN1 Digest hashAlg
digest)

-- | Sign something that is already a DigestInfo, the ASN.1 structure
-- naming a hash algorithm and carrying a digest under it.
--
-- This is what @'sign' blinder 'Nothing'@ does.  It needs no
-- 'HashAlgorithmASN1' constraint, because nothing here hashes or encodes:
-- the caller has done both.  @'sign' blinder 'Nothing'@ carries the
-- constraint anyway, and since the type variable then appears nowhere else
-- the caller has to name an algorithm that is never used --
-- @'sign' blinder ('Nothing' :: 'Maybe' 'Crypto.Hash.SHA256')@ -- to say
-- which one it is not using.
signDigestInfo
    :: Maybe Blinder
    -- ^ optional blinder
    -> PrivateKey
    -- ^ private key
    -> ByteString
    -- ^ a DigestInfo, encoded
    -> Either Error ByteString
signDigestInfo :: Maybe Blinder
-> PrivateKey -> ByteString -> Either Error ByteString
signDigestInfo Maybe Blinder
blinder PrivateKey
pk ByteString
di =
    Maybe Blinder -> PrivateKey -> ByteString -> ByteString
forall ba. ByteArray ba => Maybe Blinder -> PrivateKey -> ba -> ba
dp Maybe Blinder
blinder PrivateKey
pk (ByteString -> ByteString)
-> Either Error ByteString -> Either Error ByteString
forall a b. (a -> b) -> Either Error a -> Either Error b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` Int -> ByteString -> Either Error ByteString
forall signature.
ByteArray signature =>
Int -> signature -> Either Error signature
padSignature (PrivateKey -> Int
private_size PrivateKey
pk) ByteString
di

-- | 'signDigestInfo' blinded with the pair kept for this key.
signSaferDigestInfo
    :: MonadRandom m
    => PrivateKey
    -- ^ private key
    -> ByteString
    -- ^ a DigestInfo, encoded
    -> m (Either Error ByteString)
signSaferDigestInfo :: forall (m :: * -> *).
MonadRandom m =>
PrivateKey -> ByteString -> m (Either Error ByteString)
signSaferDigestInfo PrivateKey
pk ByteString
di = 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 -> Either Error ByteString -> Either Error ByteString
signWithBlindingFor PrivateKey
pk Draw
d (Int -> ByteString -> Either Error ByteString
forall signature.
ByteArray signature =>
Int -> signature -> Either Error signature
padSignature (PrivateKey -> Int
private_size PrivateKey
pk) ByteString
di)

-- | 'signDigestInfo' with the blinding a t'BlindedKey' keeps, and the key for
-- the next operation.
signDigestInfoBlinded
    :: MonadRandom m
    => BlindedKey
    -> ByteString
    -- ^ a DigestInfo, encoded
    -> m (Either Error ByteString, BlindedKey)
signDigestInfoBlinded :: forall (m :: * -> *).
MonadRandom m =>
BlindedKey -> ByteString -> m (Either Error ByteString, BlindedKey)
signDigestInfoBlinded BlindedKey
bk ByteString
di =
    BlindedKey
-> Either Error ByteString
-> m (Either Error ByteString, BlindedKey)
forall (m :: * -> *).
MonadRandom m =>
BlindedKey
-> Either Error ByteString
-> m (Either Error ByteString, BlindedKey)
signBlindedEncoded BlindedKey
bk (Either Error ByteString
 -> m (Either Error ByteString, BlindedKey))
-> Either Error ByteString
-> m (Either Error ByteString, BlindedKey)
forall a b. (a -> b) -> a -> b
$ Int -> ByteString -> Either Error ByteString
forall signature.
ByteArray signature =>
Int -> signature -> Either Error signature
padSignature (PrivateKey -> Int
private_size (BlindedKey -> PrivateKey
blindedPrivateKey BlindedKey
bk)) ByteString
di

-- | The private-key operation on an encoded signature, if there is one; the
-- key is used up only if there is.
signBlindedEncoded
    :: MonadRandom m
    => BlindedKey
    -> Either Error ByteString
    -> m (Either Error ByteString, BlindedKey)
signBlindedEncoded :: forall (m :: * -> *).
MonadRandom m =>
BlindedKey
-> Either Error ByteString
-> m (Either Error ByteString, BlindedKey)
signBlindedEncoded BlindedKey
bk (Left Error
err) = (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
err, BlindedKey
bk)
signBlindedEncoded BlindedKey
bk (Right ByteString
em) = do
    (ByteString
s, BlindedKey
bk') <- BlindedKey -> ByteString -> m (ByteString, BlindedKey)
forall (m :: * -> *) ba.
(MonadRandom m, ByteArray ba) =>
BlindedKey -> ba -> m (ba, BlindedKey)
dpBlinded BlindedKey
bk ByteString
em
    (Either Error ByteString, BlindedKey)
-> m (Either Error ByteString, BlindedKey)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (ByteString -> Either Error ByteString
forall a b. b -> Either a b
Right ByteString
s, BlindedKey
bk')

-- | The same, with the pair the @Safer@ functions keep for this key.
signWithBlindingFor
    :: PrivateKey -> Draw -> Either Error ByteString -> Either Error ByteString
signWithBlindingFor :: PrivateKey
-> Draw -> Either Error ByteString -> Either Error ByteString
signWithBlindingFor PrivateKey
_ Draw
_ (Left Error
err) = Error -> Either Error ByteString
forall a b. a -> Either a b
Left Error
err
signWithBlindingFor PrivateKey
pk Draw
d (Right ByteString
em) = ByteString -> Either Error ByteString
forall a b. b -> Either a b
Right (PrivateKey
-> Draw -> ((Integer, Integer) -> ByteString) -> ByteString
forall a. PrivateKey -> Draw -> ((Integer, Integer) -> a) -> a
withBlindingFor PrivateKey
pk Draw
d (\(Integer, Integer)
pair -> (Integer, Integer) -> PrivateKey -> ByteString -> ByteString
forall ba.
ByteArray ba =>
(Integer, Integer) -> PrivateKey -> ba -> ba
dpWithPair (Integer, Integer)
pair PrivateKey
pk ByteString
em))

-- | Verify a signature over a digest.  The checks are 'verify's.
verifyDigest
    :: HashAlgorithmASN1 hashAlg
    => PublicKey
    -> Digest hashAlg
    -- ^ digest of the message
    -> ByteString
    -- ^ signature
    -> Bool
verifyDigest :: forall hashAlg.
HashAlgorithmASN1 hashAlg =>
PublicKey -> Digest hashAlg -> ByteString -> Bool
verifyDigest PublicKey
pk Digest hashAlg
digest ByteString
sm =
    PublicKey -> Either Error ByteString -> ByteString -> Bool
verifyEncoded PublicKey
pk (Int -> ByteString -> Either Error ByteString
forall signature.
ByteArray signature =>
Int -> signature -> Either Error signature
padSignature (PublicKey -> Int
public_size PublicKey
pk) (Digest hashAlg -> ByteString
forall out. ByteArray out => Digest hashAlg -> out
forall hashAlg out.
(HashAlgorithmASN1 hashAlg, ByteArray out) =>
Digest hashAlg -> out
hashDigestASN1 Digest hashAlg
digest)) ByteString
sm

-- | Verify a signature over something that is already a DigestInfo, which
-- is what @'verify' 'Nothing'@ does.
verifyDigestInfo
    :: PublicKey
    -> ByteString
    -- ^ a DigestInfo, encoded
    -> ByteString
    -- ^ signature
    -> Bool
verifyDigestInfo :: PublicKey -> ByteString -> ByteString -> Bool
verifyDigestInfo PublicKey
pk ByteString
di ByteString
sm =
    PublicKey -> Either Error ByteString -> ByteString -> Bool
verifyEncoded PublicKey
pk (Int -> ByteString -> Either Error ByteString
forall signature.
ByteArray signature =>
Int -> signature -> Either Error signature
padSignature (PublicKey -> Int
public_size PublicKey
pk) ByteString
di) ByteString
sm

-- | make signature digest, used in 'sign' and 'verify'
makeSignature
    :: HashAlgorithmASN1 hashAlg
    => Maybe hashAlg
    -- ^ optional hashing algorithm
    -> Int
    -> ByteString
    -> Either Error ByteString
makeSignature :: forall hashAlg.
HashAlgorithmASN1 hashAlg =>
Maybe hashAlg -> Int -> ByteString -> Either Error ByteString
makeSignature Maybe hashAlg
Nothing Int
klen ByteString
m = Int -> ByteString -> Either Error ByteString
forall signature.
ByteArray signature =>
Int -> signature -> Either Error signature
padSignature Int
klen ByteString
m
makeSignature (Just hashAlg
hashAlg) Int
klen ByteString
m = Int -> ByteString -> Either Error ByteString
forall signature.
ByteArray signature =>
Int -> signature -> Either Error signature
padSignature Int
klen (Digest hashAlg -> ByteString
forall out. ByteArray out => Digest hashAlg -> out
forall hashAlg out.
(HashAlgorithmASN1 hashAlg, ByteArray out) =>
Digest hashAlg -> out
hashDigestASN1 (Digest hashAlg -> ByteString) -> Digest hashAlg -> ByteString
forall a b. (a -> b) -> a -> b
$ hashAlg -> ByteString -> Digest hashAlg
forall ba alg.
(ByteArrayAccess ba, HashAlgorithm alg) =>
alg -> ba -> Digest alg
hashWith hashAlg
hashAlg ByteString
m)