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

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

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

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

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

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

-- | decrypt message using the private key.
--
-- When the decryption is not in a context where an attacker could gain
-- information from the timing of the operation, the blinder can be set to None.
--
-- If unsure always set a blinder or use decryptSafer
decrypt :: Maybe Blinder -- ^ optional blinder
        -> PrivateKey    -- ^ RSA private key
        -> ByteString    -- ^ cipher text
        -> Either Error ByteString
decrypt :: Maybe Blinder
-> PrivateKey -> ByteString -> Either Error ByteString
decrypt blinder :: Maybe Blinder
blinder pk :: PrivateKey
pk c :: ByteString
c
    | ByteString -> Int
B.length ByteString
c Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= (PrivateKey -> Int
private_size PrivateKey
pk) = Error -> Either Error ByteString
forall a b. a -> Either a b
Left Error
MessageSizeIncorrect
    | Bool
otherwise                       = ByteString -> Either Error ByteString
unpad (ByteString -> Either Error ByteString)
-> ByteString -> Either Error ByteString
forall a b. (a -> b) -> a -> b
$ Maybe Blinder -> PrivateKey -> ByteString -> ByteString
dp Maybe Blinder
blinder PrivateKey
pk ByteString
c

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

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

-- | sign message using private key, a hash and its ASN1 description
--
-- When the signature is not in a context where an attacker could gain
-- information from the timing of the operation, the blinder can be set to None.
--
-- If unsure always set a blinder or use signSafer
sign :: Maybe Blinder -- ^ optional blinder
     -> HashDescr     -- ^ hash descriptor
     -> PrivateKey    -- ^ private key
     -> ByteString    -- ^ message to sign
     -> Either Error ByteString
sign :: Maybe Blinder
-> HashDescr -> PrivateKey -> ByteString -> Either Error ByteString
sign blinder :: Maybe Blinder
blinder hashDescr :: HashDescr
hashDescr pk :: PrivateKey
pk m :: ByteString
m = Maybe Blinder -> PrivateKey -> ByteString -> ByteString
dp Maybe Blinder
blinder PrivateKey
pk (ByteString -> ByteString)
-> Either Error ByteString -> Either Error ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` HashDescr -> Int -> ByteString -> Either Error ByteString
makeSignature HashDescr
hashDescr (PrivateKey -> Int
private_size PrivateKey
pk) ByteString
m

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

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

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