{-# LANGUAGE OverloadedStrings #-}
module Crypto.PubKey.RSA.OAEP
(
OAEPParams(..)
, defaultOAEPParams
, encryptWithSeed
, encrypt
, decrypt
, decryptSafer
) where
import Crypto.Random
import Crypto.Types.PubKey.RSA
import Crypto.PubKey.HashDescr
import Crypto.PubKey.MaskGenFunction
import Crypto.PubKey.RSA.Prim
import Crypto.PubKey.RSA.Types
import Crypto.PubKey.RSA (generateBlinder)
import Crypto.PubKey.Internal (and')
import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import Data.Bits (xor)
data OAEPParams = OAEPParams
{ OAEPParams -> HashFunction
oaepHash :: HashFunction
, OAEPParams -> MaskGenAlgorithm
oaepMaskGenAlg :: MaskGenAlgorithm
, OAEPParams -> Maybe ByteString
oaepLabel :: Maybe ByteString
}
defaultOAEPParams :: HashFunction -> OAEPParams
defaultOAEPParams :: HashFunction -> OAEPParams
defaultOAEPParams hashF :: HashFunction
hashF =
OAEPParams :: HashFunction -> MaskGenAlgorithm -> Maybe ByteString -> OAEPParams
OAEPParams { oaepHash :: HashFunction
oaepHash = HashFunction
hashF
, oaepMaskGenAlg :: MaskGenAlgorithm
oaepMaskGenAlg = MaskGenAlgorithm
mgf1
, oaepLabel :: Maybe ByteString
oaepLabel = Maybe ByteString
forall a. Maybe a
Nothing
}
encryptWithSeed :: ByteString
-> OAEPParams
-> PublicKey
-> ByteString
-> Either Error ByteString
encryptWithSeed :: ByteString
-> OAEPParams -> PublicKey -> ByteString -> Either Error ByteString
encryptWithSeed seed :: ByteString
seed oaep :: OAEPParams
oaep pk :: PublicKey
pk msg :: ByteString
msg
| Int
k Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< 2Int -> Int -> Int
forall a. Num a => a -> a -> a
*Int
hashLenInt -> Int -> Int
forall a. Num a => a -> a -> a
+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
- 2Int -> Int -> Int
forall a. Num a => a -> a -> a
*Int
hashLenInt -> Int -> Int
forall a. Num a => a -> a -> a
-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 -> HashFunction
ep PublicKey
pk ByteString
em
where
k :: Int
k = PublicKey -> Int
public_size PublicKey
pk
mLen :: Int
mLen = ByteString -> Int
B.length ByteString
msg
hashF :: HashFunction
hashF = OAEPParams -> HashFunction
oaepHash OAEPParams
oaep
mgf :: ByteString -> Int -> ByteString
mgf = (OAEPParams -> MaskGenAlgorithm
oaepMaskGenAlg OAEPParams
oaep) HashFunction
hashF
labelHash :: ByteString
labelHash = HashFunction
hashF HashFunction -> HashFunction
forall a b. (a -> b) -> a -> b
$ ByteString -> HashFunction -> Maybe ByteString -> ByteString
forall b a. b -> (a -> b) -> Maybe a -> b
maybe ByteString
B.empty HashFunction
forall a. a -> a
id (Maybe ByteString -> ByteString) -> Maybe ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ OAEPParams -> Maybe ByteString
oaepLabel OAEPParams
oaep
hashLen :: Int
hashLen = ByteString -> Int
B.length ByteString
labelHash
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
- 2Int -> Int -> Int
forall a. Num a => a -> a -> a
*Int
hashLen Int -> Int -> Int
forall a. Num a => a -> a -> a
- 2) 0
db :: ByteString
db = [ByteString] -> ByteString
B.concat [ByteString
labelHash, ByteString
ps, Word8 -> ByteString
B.singleton 0x1, ByteString
msg]
dbmask :: ByteString
dbmask = ByteString -> Int -> 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
- 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 = ByteString -> Int -> 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 0x0,ByteString
maskedSeed,ByteString
maskedDB]
encrypt :: CPRG g
=> g
-> OAEPParams
-> PublicKey
-> ByteString
-> (Either Error ByteString, g)
encrypt :: g
-> OAEPParams
-> PublicKey
-> ByteString
-> (Either Error ByteString, g)
encrypt g :: g
g oaep :: OAEPParams
oaep pk :: PublicKey
pk msg :: ByteString
msg = (ByteString
-> OAEPParams -> PublicKey -> ByteString -> Either Error ByteString
encryptWithSeed ByteString
seed OAEPParams
oaep PublicKey
pk ByteString
msg, g
g')
where hashF :: HashFunction
hashF = OAEPParams -> HashFunction
oaepHash OAEPParams
oaep
hashLen :: Int
hashLen = ByteString -> Int
B.length (HashFunction
hashF ByteString
B.empty)
(seed :: ByteString
seed, g' :: g
g') = Int -> g -> (ByteString, g)
forall gen. CPRG gen => Int -> gen -> (ByteString, gen)
cprgGenerate Int
hashLen g
g
unpad :: OAEPParams
-> Int
-> ByteString
-> Either Error ByteString
unpad :: OAEPParams -> Int -> ByteString -> Either Error ByteString
unpad oaep :: OAEPParams
oaep k :: Int
k em :: 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
hashF :: HashFunction
hashF = OAEPParams -> HashFunction
oaepHash OAEPParams
oaep
mgf :: ByteString -> Int -> ByteString
mgf = (OAEPParams -> MaskGenAlgorithm
oaepMaskGenAlg OAEPParams
oaep) HashFunction
hashF
labelHash :: ByteString
labelHash = HashFunction
hashF HashFunction -> HashFunction
forall a b. (a -> b) -> a -> b
$ ByteString -> HashFunction -> Maybe ByteString -> ByteString
forall b a. b -> (a -> b) -> Maybe a -> b
maybe ByteString
B.empty HashFunction
forall a. a -> a
id (Maybe ByteString -> ByteString) -> Maybe ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ OAEPParams -> Maybe ByteString
oaepLabel OAEPParams
oaep
hashLen :: Int
hashLen = ByteString -> Int
B.length ByteString
labelHash
(pb :: ByteString
pb, em0 :: ByteString
em0) = Int -> ByteString -> (ByteString, ByteString)
B.splitAt 1 ByteString
em
(maskedSeed :: ByteString
maskedSeed,maskedDB :: ByteString
maskedDB) = Int -> ByteString -> (ByteString, ByteString)
B.splitAt Int
hashLen ByteString
em0
seedMask :: ByteString
seedMask = ByteString -> Int -> 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 = ByteString -> Int -> 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
- 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
(labelHash' :: ByteString
labelHash',db1 :: ByteString
db1) = Int -> ByteString -> (ByteString, ByteString)
B.splitAt Int
hashLen ByteString
db
(_,db2 :: ByteString
db2) = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
B.break (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= 0) ByteString
db1
(ps1 :: ByteString
ps1,msg :: ByteString
msg) = Int -> ByteString -> (ByteString, ByteString)
B.splitAt 1 ByteString
db2
paddingSuccess :: Bool
paddingSuccess = [Bool] -> Bool
and' [ ByteString
labelHash' ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ByteString
labelHash
, ByteString
ps1 ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== "\x01"
, ByteString
pb ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== "\x00"
]
decrypt :: Maybe Blinder
-> OAEPParams
-> PrivateKey
-> ByteString
-> Either Error ByteString
decrypt :: Maybe Blinder
-> OAEPParams
-> PrivateKey
-> ByteString
-> Either Error ByteString
decrypt blinder :: Maybe Blinder
blinder oaep :: OAEPParams
oaep pk :: PrivateKey
pk cipher :: 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
| Int
k Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< 2Int -> Int -> Int
forall a. Num a => a -> a -> a
*Int
hashLenInt -> Int -> Int
forall a. Num a => a -> a -> a
+2 = Error -> Either Error ByteString
forall a b. a -> Either a b
Left Error
InvalidParameters
| Bool
otherwise = OAEPParams -> Int -> ByteString -> Either Error ByteString
unpad OAEPParams
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 -> HashFunction
dp Maybe Blinder
blinder PrivateKey
pk ByteString
cipher
where
k :: Int
k = PrivateKey -> Int
private_size PrivateKey
pk
hashF :: HashFunction
hashF = OAEPParams -> HashFunction
oaepHash OAEPParams
oaep
hashLen :: Int
hashLen = ByteString -> Int
B.length (HashFunction
hashF ByteString
B.empty)
decryptSafer :: CPRG g
=> g
-> OAEPParams
-> PrivateKey
-> ByteString
-> (Either Error ByteString, g)
decryptSafer :: g
-> OAEPParams
-> PrivateKey
-> ByteString
-> (Either Error ByteString, g)
decryptSafer rng :: g
rng oaep :: OAEPParams
oaep pk :: PrivateKey
pk cipher :: ByteString
cipher = (Maybe Blinder
-> OAEPParams
-> PrivateKey
-> ByteString
-> Either Error ByteString
decrypt (Blinder -> Maybe Blinder
forall a. a -> Maybe a
Just Blinder
blinder) OAEPParams
oaep PrivateKey
pk ByteString
cipher, g
rng')
where (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)