module Crypto.PubKey.RSA.PKCS15
(
pad
, padSignature
, unpad
, decrypt
, decryptSafer
, sign
, signSafer
, encrypt
, verify
, HashAlgorithmASN1
) where
import Crypto.Random.Types
import Crypto.PubKey.Internal (and')
import Crypto.PubKey.RSA.Types
import Crypto.PubKey.RSA.Prim
import Crypto.PubKey.RSA (generateBlinder)
import Crypto.Hash
import Data.ByteString (ByteString)
import Data.Word
import Crypto.Internal.ByteArray (ByteArray, Bytes)
import qualified Crypto.Internal.ByteArray as B
class HashAlgorithm hashAlg => HashAlgorithmASN1 hashAlg where
hashDigestASN1 :: ByteArray out => Digest hashAlg -> out
instance HashAlgorithmASN1 MD2 where
hashDigestASN1 :: Digest MD2 -> out
hashDigestASN1 = [Word8] -> Digest MD2 -> out
forall out hashAlg.
ByteArray out =>
[Word8] -> Digest hashAlg -> out
addDigestPrefix [0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x02,0x05,0x00,0x04,0x10]
instance HashAlgorithmASN1 MD5 where
hashDigestASN1 :: Digest MD5 -> out
hashDigestASN1 = [Word8] -> Digest MD5 -> out
forall out hashAlg.
ByteArray out =>
[Word8] -> Digest hashAlg -> out
addDigestPrefix [0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x04,0x10]
instance HashAlgorithmASN1 SHA1 where
hashDigestASN1 :: Digest SHA1 -> out
hashDigestASN1 = [Word8] -> Digest SHA1 -> out
forall out hashAlg.
ByteArray out =>
[Word8] -> Digest hashAlg -> out
addDigestPrefix [0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,0x04,0x14]
instance HashAlgorithmASN1 SHA224 where
hashDigestASN1 :: Digest SHA224 -> out
hashDigestASN1 = [Word8] -> Digest SHA224 -> out
forall out hashAlg.
ByteArray out =>
[Word8] -> Digest hashAlg -> out
addDigestPrefix [0x30,0x2d,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x04,0x05,0x00,0x04,0x1c]
instance HashAlgorithmASN1 SHA256 where
hashDigestASN1 :: Digest SHA256 -> out
hashDigestASN1 = [Word8] -> Digest SHA256 -> out
forall out hashAlg.
ByteArray out =>
[Word8] -> Digest hashAlg -> out
addDigestPrefix [0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,0x20]
instance HashAlgorithmASN1 SHA384 where
hashDigestASN1 :: Digest SHA384 -> out
hashDigestASN1 = [Word8] -> Digest SHA384 -> out
forall out hashAlg.
ByteArray out =>
[Word8] -> Digest hashAlg -> out
addDigestPrefix [0x30,0x41,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00,0x04,0x30]
instance HashAlgorithmASN1 SHA512 where
hashDigestASN1 :: Digest SHA512 -> out
hashDigestASN1 = [Word8] -> Digest SHA512 -> out
forall out hashAlg.
ByteArray out =>
[Word8] -> Digest hashAlg -> out
addDigestPrefix [0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04,0x40]
instance HashAlgorithmASN1 SHA512t_224 where
hashDigestASN1 :: Digest SHA512t_224 -> out
hashDigestASN1 = [Word8] -> Digest SHA512t_224 -> out
forall out hashAlg.
ByteArray out =>
[Word8] -> Digest hashAlg -> out
addDigestPrefix [0x30,0x2d,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x05,0x05,0x00,0x04,0x1c]
instance HashAlgorithmASN1 SHA512t_256 where
hashDigestASN1 :: Digest SHA512t_256 -> out
hashDigestASN1 = [Word8] -> Digest SHA512t_256 -> out
forall out hashAlg.
ByteArray out =>
[Word8] -> Digest hashAlg -> out
addDigestPrefix [0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x06,0x05,0x00,0x04,0x20]
instance HashAlgorithmASN1 RIPEMD160 where
hashDigestASN1 :: Digest RIPEMD160 -> out
hashDigestASN1 = [Word8] -> Digest RIPEMD160 -> out
forall out hashAlg.
ByteArray out =>
[Word8] -> Digest hashAlg -> out
addDigestPrefix [0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x24,0x03,0x02,0x01,0x05,0x00,0x04,0x14]
addDigestPrefix :: ByteArray out => [Word8] -> Digest hashAlg -> out
addDigestPrefix :: [Word8] -> Digest hashAlg -> out
addDigestPrefix prefix :: [Word8]
prefix digest :: 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
pad :: (MonadRandom m, ByteArray message) => Int -> message -> m (Either Error message)
pad :: Int -> message -> m (Either Error message)
pad len :: Int
len m :: 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
- 11 = Either Error message -> m (Either Error message)
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
- 3)
Either Error message -> m (Either Error message)
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 [0,2], message
padding, [Word8] -> message
forall a. ByteArray a => [Word8] -> a
B.pack [0], message
m ]
where
getNonNullRandom :: (ByteArray bytearray, MonadRandom m) => Int -> m bytearray
getNonNullRandom :: Int -> m bytearray
getNonNullRandom n :: Int
n = do
Bytes
bs0 <- Int -> m Bytes
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
/= 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
== 0
then bytearray -> m bytearray
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 (m :: * -> *) a. Monad m => a -> m a
return (bytearray
bytes bytearray -> bytearray -> bytearray
forall bs. ByteArray bs => bs -> bs -> bs
`B.append` bytearray
bend)
padSignature :: ByteArray signature => Int -> signature -> Either Error signature
padSignature :: Int -> signature -> Either Error signature
padSignature klen :: Int
klen signature :: 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
+ 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 = 0 Word8 -> [Word8] -> [Word8]
forall a. a -> [a] -> [a]
: 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
- 3) 0xff [Word8] -> [Word8] -> [Word8]
forall a. [a] -> [a] -> [a]
++ [0])
unpad :: ByteArray bytearray => bytearray -> Either Error bytearray
unpad :: bytearray -> Either Error bytearray
unpad packed :: 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
(zt :: bytearray
zt, ps0m :: bytearray
ps0m) = Int -> bytearray -> (bytearray, bytearray)
forall bs. ByteArray bs => Int -> bs -> (bs, bs)
B.splitAt 2 bytearray
packed
(ps :: bytearray
ps, zm :: 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
/= 0) bytearray
ps0m
(z :: bytearray
z, m :: bytearray
m) = Int -> bytearray -> (bytearray, bytearray)
forall bs. ByteArray bs => Int -> bs -> (bs, bs)
B.splitAt 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 [0,2] :: Bytes)
, bytearray
z bytearray -> bytearray -> Bool
forall a. Eq a => a -> a -> Bool
== Int -> bytearray
forall ba. ByteArray ba => Int -> ba
B.zero 1
, bytearray -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length bytearray
ps Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= 8
]
decrypt :: Maybe Blinder
-> PrivateKey
-> ByteString
-> Either Error ByteString
decrypt :: Maybe Blinder
-> PrivateKey -> ByteString -> Either Error ByteString
decrypt blinder :: Maybe Blinder
blinder pk :: PrivateKey
pk c :: 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
decryptSafer :: MonadRandom m
=> PrivateKey
-> ByteString
-> m (Either Error ByteString)
decryptSafer :: PrivateKey -> ByteString -> m (Either Error ByteString)
decryptSafer pk :: PrivateKey
pk b :: 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 (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 :: MonadRandom m => PublicKey -> ByteString -> m (Either Error ByteString)
encrypt :: PublicKey -> ByteString -> m (Either Error ByteString)
encrypt pk :: PublicKey
pk m :: 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 err :: Error
err -> Either Error ByteString -> m (Either Error ByteString)
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 em :: ByteString
em -> Either Error ByteString -> m (Either Error ByteString)
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 :: HashAlgorithmASN1 hashAlg
=> Maybe Blinder
-> Maybe hashAlg
-> PrivateKey
-> ByteString
-> Either Error ByteString
sign :: Maybe Blinder
-> Maybe hashAlg
-> PrivateKey
-> ByteString
-> Either Error ByteString
sign blinder :: Maybe Blinder
blinder hashDescr :: Maybe hashAlg
hashDescr pk :: PrivateKey
pk m :: 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 (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
signSafer :: (HashAlgorithmASN1 hashAlg, MonadRandom m)
=> Maybe hashAlg
-> PrivateKey
-> ByteString
-> m (Either Error ByteString)
signSafer :: Maybe hashAlg
-> PrivateKey -> ByteString -> m (Either Error ByteString)
signSafer hashAlg :: Maybe hashAlg
hashAlg pk :: PrivateKey
pk m :: 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 (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 :: HashAlgorithmASN1 hashAlg
=> Maybe hashAlg
-> PublicKey
-> ByteString
-> ByteString
-> Bool
verify :: Maybe hashAlg -> PublicKey -> ByteString -> ByteString -> Bool
verify hashAlg :: Maybe hashAlg
hashAlg pk :: PublicKey
pk m :: ByteString
m sm :: 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 _ -> Bool
False
Right s :: 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)
makeSignature :: HashAlgorithmASN1 hashAlg
=> Maybe hashAlg
-> Int
-> ByteString
-> Either Error ByteString
makeSignature :: Maybe hashAlg -> Int -> ByteString -> Either Error ByteString
makeSignature Nothing klen :: Int
klen m :: 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
hashAlg) klen :: Int
klen m :: ByteString
m = Int -> ByteString -> Either Error ByteString
forall signature.
ByteArray signature =>
Int -> signature -> Either Error signature
padSignature Int
klen (Digest hashAlg -> ByteString
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)