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

    -- * Public key operations
    encrypt,
    verify,

    -- * Hash ASN1 description
    HashAlgorithmASN1,
) where

import Crypto.Hash
import Crypto.PubKey.Internal (and')
import Crypto.PubKey.RSA (generateBlinder)
import Crypto.PubKey.RSA.Prim
import Crypto.PubKey.RSA.Types
import Crypto.Random.Types

import Data.ByteString (ByteString)
import Data.Word

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

-- | 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 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
--       ,Null
--     ,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 ([Word8] -> signature
forall a. ByteArray a => [Word8] -> a
B.pack [Word8]
padding signature -> signature -> signature
forall bs. ByteArray bs => bs -> bs -> bs
`B.append` signature
signature)
  where
    siglen :: Int
siglen = signature -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length signature
signature
    padding :: [Word8]
padding = Word8
0 Word8 -> [Word8] -> [Word8]
forall a. a -> [a] -> [a]
: Word8
1 Word8 -> [Word8] -> [Word8]
forall a. a -> [a] -> [a]
: (Int -> Word8 -> [Word8]
forall a. Int -> a -> [a]
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] -> [Word8] -> [Word8]
forall a. [a] -> [a] -> [a]
++ [Word8
0])

-- | Try to remove a standard PKCS1.5 encryption padding.
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
    (bytearray
zt, bytearray
ps0m) = Int -> bytearray -> (bytearray, bytearray)
forall bs. ByteArray bs => Int -> bs -> (bs, bs)
B.splitAt Int
2 bytearray
packed
    (bytearray
ps, bytearray
zm) = (Word8 -> Bool) -> bytearray -> (bytearray, bytearray)
forall bs. ByteArray bs => (Word8 -> Bool) -> bs -> (bs, bs)
B.span (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8
0) bytearray
ps0m
    (bytearray
z, bytearray
m) = Int -> bytearray -> (bytearray, bytearray)
forall bs. ByteArray bs => Int -> bs -> (bs, bs)
B.splitAt Int
1 bytearray
zm
    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)
            , bytearray
z bytearray -> bytearray -> Bool
forall a. Eq a => a -> a -> Bool
== Int -> bytearray
forall ba. ByteArray ba => Int -> ba
B.zero Int
1
            , bytearray -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length bytearray
ps Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
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
--
-- The message is returned un-padded.
decrypt
    :: Maybe Blinder
    -- ^ optional blinder
    -> PrivateKey
    -- ^ RSA private key
    -> ByteString
    -- ^ cipher text
    -> Either Error ByteString
decrypt :: Maybe Blinder
-> PrivateKey -> ByteString -> Either Error ByteString
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 ByteString
forall a b. a -> Either a b
Left Error
MessageSizeIncorrect
    | Bool
otherwise = ByteString -> Either Error ByteString
forall bytearray.
ByteArray bytearray =>
bytearray -> Either Error bytearray
unpad (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
c

-- | decrypt message using the private key and by automatically generating a blinder.
decryptSafer
    :: MonadRandom m
    => PrivateKey
    -- ^ RSA private key
    -> ByteString
    -- ^ cipher text
    -> m (Either Error ByteString)
decryptSafer :: forall (m :: * -> *).
MonadRandom m =>
PrivateKey -> ByteString -> m (Either Error ByteString)
decryptSafer PrivateKey
pk ByteString
b = do
    Blinder
blinder <- Integer -> m Blinder
forall (m :: * -> *). MonadRandom m => Integer -> m Blinder
generateBlinder (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 (Maybe Blinder
-> PrivateKey -> ByteString -> Either Error ByteString
decrypt (Blinder -> Maybe Blinder
forall a. a -> Maybe a
Just Blinder
blinder) PrivateKey
pk ByteString
b)

-- | 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 => PublicKey -> ByteString -> m (Either Error ByteString)
encrypt :: forall (m :: * -> *).
MonadRandom m =>
PublicKey -> ByteString -> m (Either Error ByteString)
encrypt PublicKey
pk ByteString
m = do
    Either Error ByteString
r <- Int -> ByteString -> m (Either Error ByteString)
forall (m :: * -> *) message.
(MonadRandom m, ByteArray message) =>
Int -> message -> m (Either Error message)
pad (PublicKey -> Int
public_size PublicKey
pk) ByteString
m
    case Either Error ByteString
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 ByteString
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 (PublicKey -> ByteString -> ByteString
forall ba. ByteArray ba => PublicKey -> ba -> ba
ep PublicKey
pk ByteString
em)

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

-- | sign message using the private key and by automatically generating a blinder.
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
    Blinder
blinder <- Integer -> m Blinder
forall (m :: * -> *). MonadRandom m => Integer -> m Blinder
generateBlinder (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 (Maybe Blinder
-> Maybe hashAlg
-> PrivateKey
-> ByteString
-> Either Error ByteString
forall hashAlg.
HashAlgorithmASN1 hashAlg =>
Maybe Blinder
-> Maybe hashAlg
-> PrivateKey
-> ByteString
-> Either Error ByteString
sign (Blinder -> Maybe Blinder
forall a. a -> Maybe a
Just Blinder
blinder) Maybe hashAlg
hashAlg PrivateKey
pk ByteString
m)

-- | verify message with the signed message
verify
    :: HashAlgorithmASN1 hashAlg
    => Maybe hashAlg
    -> PublicKey
    -> ByteString
    -> ByteString
    -> Bool
verify :: forall hashAlg.
HashAlgorithmASN1 hashAlg =>
Maybe hashAlg -> PublicKey -> ByteString -> ByteString -> Bool
verify Maybe hashAlg
hashAlg PublicKey
pk ByteString
m ByteString
sm =
    case 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 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)

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