module Crypto.PubKey.RSA.OAEP
(
OAEPParams(..)
, defaultOAEPParams
, encryptWithSeed
, encrypt
, decrypt
, decryptSafer
) where
import Crypto.Hash
import Crypto.Random.Types
import Crypto.PubKey.RSA.Types
import Crypto.PubKey.MaskGenFunction
import Crypto.PubKey.RSA.Prim
import Crypto.PubKey.RSA (generateBlinder)
import Crypto.PubKey.Internal (and')
import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import Data.Bits (xor)
import Crypto.Internal.ByteArray (ByteArrayAccess, ByteArray)
import qualified Crypto.Internal.ByteArray as B (convert)
data OAEPParams hash seed output = OAEPParams
{ forall hash seed output. OAEPParams hash seed output -> hash
oaepHash :: hash
, forall hash seed output.
OAEPParams hash seed output -> MaskGenAlgorithm seed output
oaepMaskGenAlg :: MaskGenAlgorithm seed output
, forall hash seed output.
OAEPParams hash seed output -> Maybe ByteString
oaepLabel :: Maybe ByteString
}
defaultOAEPParams :: (ByteArrayAccess seed, ByteArray output, HashAlgorithm hash)
=> hash
-> OAEPParams hash seed output
defaultOAEPParams :: forall seed output hash.
(ByteArrayAccess seed, ByteArray output, HashAlgorithm hash) =>
hash -> OAEPParams hash seed output
defaultOAEPParams hash
hashAlg =
OAEPParams { oaepHash :: hash
oaepHash = hash
hashAlg
, oaepMaskGenAlg :: MaskGenAlgorithm seed output
oaepMaskGenAlg = forall seed output hashAlg.
(ByteArrayAccess seed, ByteArray output, HashAlgorithm hashAlg) =>
hashAlg -> seed -> Int -> output
mgf1 hash
hashAlg
, oaepLabel :: Maybe ByteString
oaepLabel = forall a. Maybe a
Nothing
}
encryptWithSeed :: HashAlgorithm hash
=> ByteString
-> OAEPParams hash ByteString ByteString
-> PublicKey
-> ByteString
-> Either Error ByteString
encryptWithSeed :: forall hash.
HashAlgorithm hash =>
ByteString
-> OAEPParams hash ByteString ByteString
-> PublicKey
-> ByteString
-> Either Error ByteString
encryptWithSeed ByteString
seed OAEPParams hash ByteString ByteString
oaep PublicKey
pk ByteString
msg
| Int
k forall a. Ord a => a -> a -> Bool
< Int
2forall a. Num a => a -> a -> a
*Int
hashLenforall a. Num a => a -> a -> a
+Int
2 = forall a b. a -> Either a b
Left Error
InvalidParameters
| ByteString -> Int
B.length ByteString
seed forall a. Eq a => a -> a -> Bool
/= Int
hashLen = forall a b. a -> Either a b
Left Error
InvalidParameters
| Int
mLen forall a. Ord a => a -> a -> Bool
> Int
k forall a. Num a => a -> a -> a
- Int
2forall a. Num a => a -> a -> a
*Int
hashLenforall a. Num a => a -> a -> a
-Int
2 = forall a b. a -> Either a b
Left Error
MessageTooLong
| Bool
otherwise = forall a b. b -> Either a b
Right forall a b. (a -> b) -> a -> b
$ forall ba. ByteArray ba => PublicKey -> ba -> ba
ep PublicKey
pk ByteString
em
where
k :: Int
k = PublicKey -> Int
public_size PublicKey
pk
mLen :: Int
mLen = ByteString -> Int
B.length ByteString
msg
mgf :: MaskGenAlgorithm ByteString ByteString
mgf = forall hash seed output.
OAEPParams hash seed output -> MaskGenAlgorithm seed output
oaepMaskGenAlg OAEPParams hash ByteString ByteString
oaep
labelHash :: Digest hash
labelHash = forall ba alg.
(ByteArrayAccess ba, HashAlgorithm alg) =>
alg -> ba -> Digest alg
hashWith (forall hash seed output. OAEPParams hash seed output -> hash
oaepHash OAEPParams hash ByteString ByteString
oaep) (forall b a. b -> (a -> b) -> Maybe a -> b
maybe ByteString
B.empty forall a. a -> a
id forall a b. (a -> b) -> a -> b
$ forall hash seed output.
OAEPParams hash seed output -> Maybe ByteString
oaepLabel OAEPParams hash ByteString ByteString
oaep)
hashLen :: Int
hashLen = forall a. HashAlgorithm a => a -> Int
hashDigestSize (forall hash seed output. OAEPParams hash seed output -> hash
oaepHash OAEPParams hash ByteString ByteString
oaep)
ps :: ByteString
ps = Int -> Word8 -> ByteString
B.replicate (Int
k forall a. Num a => a -> a -> a
- Int
mLen forall a. Num a => a -> a -> a
- Int
2forall a. Num a => a -> a -> a
*Int
hashLen forall a. Num a => a -> a -> a
- Int
2) Word8
0
db :: ByteString
db = [ByteString] -> ByteString
B.concat [forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
B.convert Digest hash
labelHash, ByteString
ps, Word8 -> ByteString
B.singleton Word8
0x1, ByteString
msg]
dbmask :: ByteString
dbmask = MaskGenAlgorithm ByteString ByteString
mgf ByteString
seed (Int
k forall a. Num a => a -> a -> a
- Int
hashLen forall a. Num a => a -> a -> a
- Int
1)
maskedDB :: ByteString
maskedDB = [Word8] -> ByteString
B.pack forall a b. (a -> b) -> a -> b
$ forall a. (Word8 -> Word8 -> a) -> ByteString -> ByteString -> [a]
B.zipWith forall a. Bits a => a -> a -> a
xor ByteString
db ByteString
dbmask
seedMask :: ByteString
seedMask = MaskGenAlgorithm ByteString ByteString
mgf ByteString
maskedDB Int
hashLen
maskedSeed :: ByteString
maskedSeed = [Word8] -> ByteString
B.pack forall a b. (a -> b) -> a -> b
$ forall a. (Word8 -> Word8 -> a) -> ByteString -> ByteString -> [a]
B.zipWith forall a. Bits a => a -> a -> a
xor ByteString
seed ByteString
seedMask
em :: ByteString
em = [ByteString] -> ByteString
B.concat [Word8 -> ByteString
B.singleton Word8
0x0,ByteString
maskedSeed,ByteString
maskedDB]
encrypt :: (HashAlgorithm hash, MonadRandom m)
=> OAEPParams hash ByteString ByteString
-> PublicKey
-> ByteString
-> m (Either Error ByteString)
encrypt :: forall hash (m :: * -> *).
(HashAlgorithm hash, MonadRandom m) =>
OAEPParams hash ByteString ByteString
-> PublicKey -> ByteString -> m (Either Error ByteString)
encrypt OAEPParams hash ByteString ByteString
oaep PublicKey
pk ByteString
msg = do
ByteString
seed <- forall (m :: * -> *) byteArray.
(MonadRandom m, ByteArray byteArray) =>
Int -> m byteArray
getRandomBytes Int
hashLen
forall (m :: * -> *) a. Monad m => a -> m a
return (forall hash.
HashAlgorithm hash =>
ByteString
-> OAEPParams hash ByteString ByteString
-> PublicKey
-> ByteString
-> Either Error ByteString
encryptWithSeed ByteString
seed OAEPParams hash ByteString ByteString
oaep PublicKey
pk ByteString
msg)
where
hashLen :: Int
hashLen = forall a. HashAlgorithm a => a -> Int
hashDigestSize (forall hash seed output. OAEPParams hash seed output -> hash
oaepHash OAEPParams hash ByteString ByteString
oaep)
unpad :: HashAlgorithm hash
=> OAEPParams hash ByteString ByteString
-> Int
-> ByteString
-> Either Error ByteString
unpad :: forall hash.
HashAlgorithm hash =>
OAEPParams hash ByteString ByteString
-> Int -> ByteString -> Either Error ByteString
unpad OAEPParams hash ByteString ByteString
oaep Int
k ByteString
em
| Bool
paddingSuccess = forall a b. b -> Either a b
Right ByteString
msg
| Bool
otherwise = forall a b. a -> Either a b
Left Error
MessageNotRecognized
where
mgf :: MaskGenAlgorithm ByteString ByteString
mgf = forall hash seed output.
OAEPParams hash seed output -> MaskGenAlgorithm seed output
oaepMaskGenAlg OAEPParams hash ByteString ByteString
oaep
labelHash :: ByteString
labelHash = forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
B.convert forall a b. (a -> b) -> a -> b
$ forall ba alg.
(ByteArrayAccess ba, HashAlgorithm alg) =>
alg -> ba -> Digest alg
hashWith (forall hash seed output. OAEPParams hash seed output -> hash
oaepHash OAEPParams hash ByteString ByteString
oaep) (forall b a. b -> (a -> b) -> Maybe a -> b
maybe ByteString
B.empty forall a. a -> a
id forall a b. (a -> b) -> a -> b
$ forall hash seed output.
OAEPParams hash seed output -> Maybe ByteString
oaepLabel OAEPParams hash ByteString ByteString
oaep)
hashLen :: Int
hashLen = forall a. HashAlgorithm a => a -> Int
hashDigestSize (forall hash seed output. OAEPParams hash seed output -> hash
oaepHash OAEPParams hash ByteString ByteString
oaep)
(ByteString
pb, ByteString
em0) = Int -> ByteString -> (ByteString, ByteString)
B.splitAt Int
1 ByteString
em
(ByteString
maskedSeed,ByteString
maskedDB) = Int -> ByteString -> (ByteString, ByteString)
B.splitAt Int
hashLen ByteString
em0
seedMask :: ByteString
seedMask = MaskGenAlgorithm ByteString ByteString
mgf ByteString
maskedDB Int
hashLen
seed :: ByteString
seed = [Word8] -> ByteString
B.pack forall a b. (a -> b) -> a -> b
$ forall a. (Word8 -> Word8 -> a) -> ByteString -> ByteString -> [a]
B.zipWith forall a. Bits a => a -> a -> a
xor ByteString
maskedSeed ByteString
seedMask
dbmask :: ByteString
dbmask = MaskGenAlgorithm ByteString ByteString
mgf ByteString
seed (Int
k forall a. Num a => a -> a -> a
- Int
hashLen forall a. Num a => a -> a -> a
- Int
1)
db :: ByteString
db = [Word8] -> ByteString
B.pack forall a b. (a -> b) -> a -> b
$ forall a. (Word8 -> Word8 -> a) -> ByteString -> ByteString -> [a]
B.zipWith forall a. Bits a => a -> a -> a
xor ByteString
maskedDB ByteString
dbmask
(ByteString
labelHash',ByteString
db1) = Int -> ByteString -> (ByteString, ByteString)
B.splitAt Int
hashLen ByteString
db
(ByteString
_,ByteString
db2) = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
B.break (forall a. Eq a => a -> a -> Bool
/= Word8
0) ByteString
db1
(ByteString
ps1,ByteString
msg) = Int -> ByteString -> (ByteString, ByteString)
B.splitAt Int
1 ByteString
db2
paddingSuccess :: Bool
paddingSuccess = [Bool] -> Bool
and' [ ByteString
labelHash' forall a. Eq a => a -> a -> Bool
== ByteString
labelHash
, ByteString
ps1 forall a. Eq a => a -> a -> Bool
== Int -> Word8 -> ByteString
B.replicate Int
1 Word8
0x1
, ByteString
pb forall a. Eq a => a -> a -> Bool
== Int -> Word8 -> ByteString
B.replicate Int
1 Word8
0x0
]
decrypt :: HashAlgorithm hash
=> Maybe Blinder
-> OAEPParams hash ByteString ByteString
-> PrivateKey
-> ByteString
-> Either Error ByteString
decrypt :: forall hash.
HashAlgorithm hash =>
Maybe Blinder
-> OAEPParams hash ByteString ByteString
-> PrivateKey
-> ByteString
-> Either Error ByteString
decrypt Maybe Blinder
blinder OAEPParams hash ByteString ByteString
oaep PrivateKey
pk ByteString
cipher
| ByteString -> Int
B.length ByteString
cipher forall a. Eq a => a -> a -> Bool
/= Int
k = forall a b. a -> Either a b
Left Error
MessageSizeIncorrect
| Int
k forall a. Ord a => a -> a -> Bool
< Int
2forall a. Num a => a -> a -> a
*Int
hashLenforall a. Num a => a -> a -> a
+Int
2 = forall a b. a -> Either a b
Left Error
InvalidParameters
| Bool
otherwise = forall hash.
HashAlgorithm hash =>
OAEPParams hash ByteString ByteString
-> Int -> ByteString -> Either Error ByteString
unpad OAEPParams hash ByteString ByteString
oaep (PrivateKey -> Int
private_size PrivateKey
pk) forall a b. (a -> b) -> a -> b
$ forall ba. ByteArray ba => Maybe Blinder -> PrivateKey -> ba -> ba
dp Maybe Blinder
blinder PrivateKey
pk ByteString
cipher
where
k :: Int
k = PrivateKey -> Int
private_size PrivateKey
pk
hashLen :: Int
hashLen = forall a. HashAlgorithm a => a -> Int
hashDigestSize (forall hash seed output. OAEPParams hash seed output -> hash
oaepHash OAEPParams hash ByteString ByteString
oaep)
decryptSafer :: (HashAlgorithm hash, MonadRandom m)
=> OAEPParams hash ByteString ByteString
-> PrivateKey
-> ByteString
-> m (Either Error ByteString)
decryptSafer :: forall hash (m :: * -> *).
(HashAlgorithm hash, MonadRandom m) =>
OAEPParams hash ByteString ByteString
-> PrivateKey -> ByteString -> m (Either Error ByteString)
decryptSafer OAEPParams hash ByteString ByteString
oaep PrivateKey
pk ByteString
cipher = do
Blinder
blinder <- forall (m :: * -> *). MonadRandom m => Integer -> m Blinder
generateBlinder (PrivateKey -> Integer
private_n PrivateKey
pk)
forall (m :: * -> *) a. Monad m => a -> m a
return (forall hash.
HashAlgorithm hash =>
Maybe Blinder
-> OAEPParams hash ByteString ByteString
-> PrivateKey
-> ByteString
-> Either Error ByteString
decrypt (forall a. a -> Maybe a
Just Blinder
blinder) OAEPParams hash ByteString ByteString
oaep PrivateKey
pk ByteString
cipher)