[RSA] remove the need for bytestring in HashDescr and work towards more removal

This commit is contained in:
Vincent Hanquez 2015-05-21 09:46:13 +01:00
parent 8065c26c2d
commit c7de32a6f6
2 changed files with 86 additions and 78 deletions

View File

@ -11,8 +11,8 @@
module Crypto.PubKey.HashDescr module Crypto.PubKey.HashDescr
( (
-- * Types -- * Types
HashFunction HashDescr
, HashDescr(..) , runHashDescr
-- * List of known hash description -- * List of known hash description
, hashDescrMD2 , hashDescrMD2
, hashDescrMD5 , hashDescrMD5
@ -24,73 +24,20 @@ module Crypto.PubKey.HashDescr
, hashDescrRIPEMD160 , hashDescrRIPEMD160
) where ) where
import Data.ByteString.Char8 ()
import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import Data.Word import Data.Word
import Crypto.Hash import Crypto.Hash
import qualified Crypto.Internal.ByteArray as B (convert) import qualified Crypto.Internal.ByteArray as B
-- | A standard hash function returning a digest object --
type HashFunction = ByteString -> ByteString -- ** Hack **
--
-- | Describe a hash function and a way to wrap the digest into -- this happens to not need a real ASN1 encoder, because
-- an DER encoded ASN1 marshalled structure. -- thanks to the digest being a specific size AND
data HashDescr = HashDescr { hashFunction :: HashFunction -- ^ hash function -- that the digest data is the last bytes in the encoding,
, digestToASN1 :: ByteString -> ByteString -- ^ convertion to an ASN1 wrapped digest bytestring -- this allows to just prepend the right prefix to the
} -- computed digest, to make it in the expected and valid shape.
--
-- | Describe the MD2 hashing algorithm -- Otherwise the expected structure is in the following form:
hashDescrMD2 :: HashDescr
hashDescrMD2 =
HashDescr { hashFunction = B.convert . (hash :: ByteString -> Digest MD2)
, digestToASN1 = toHashWithInfo [0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x02,0x05,0x00,0x04,0x10]
}
-- | Describe the MD5 hashing algorithm
hashDescrMD5 :: HashDescr
hashDescrMD5 =
HashDescr { hashFunction = B.convert . (hash :: ByteString -> Digest MD5)
, digestToASN1 = toHashWithInfo [0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x04,0x10]
}
-- | Describe the SHA1 hashing algorithm
hashDescrSHA1 :: HashDescr
hashDescrSHA1 =
HashDescr { hashFunction = B.convert . (hash :: ByteString -> Digest SHA1)
, digestToASN1 = toHashWithInfo [0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,0x04,0x14]
}
-- | Describe the SHA224 hashing algorithm
hashDescrSHA224 :: HashDescr
hashDescrSHA224 =
HashDescr { hashFunction = B.convert . (hash :: ByteString -> Digest SHA224)
, digestToASN1 = toHashWithInfo [0x30,0x2d,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x04,0x05,0x00,0x04,0x1c]
}
-- | Describe the SHA256 hashing algorithm
hashDescrSHA256 :: HashDescr
hashDescrSHA256 =
HashDescr { hashFunction = B.convert . (hash :: ByteString -> Digest SHA256)
, digestToASN1 = toHashWithInfo [0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,0x20]
}
-- | Describe the SHA384 hashing algorithm
hashDescrSHA384 :: HashDescr
hashDescrSHA384 =
HashDescr { hashFunction = B.convert . (hash :: ByteString -> Digest SHA384)
, digestToASN1 = toHashWithInfo [0x30,0x41,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00,0x04,0x30]
}
-- | Describe the SHA512 hashing algorithm
hashDescrSHA512 :: HashDescr
hashDescrSHA512 =
HashDescr { hashFunction = B.convert . (hash :: ByteString -> Digest SHA512)
, digestToASN1 = toHashWithInfo [0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04,0x40]
}
-- | Describe the RIPEMD160 hashing algorithm
hashDescrRIPEMD160 :: HashDescr
hashDescrRIPEMD160 =
HashDescr { hashFunction = B.convert . (hash :: ByteString -> Digest RIPEMD160)
, digestToASN1 = toHashWithInfo [0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x24,0x03,0x02,0x01,0x05,0x00,0x04,0x14]
}
-- | Generate the marshalled structure with the following ASN1 structure:
-- --
-- Start Sequence -- Start Sequence
-- ,Start Sequence -- ,Start Sequence
@ -99,6 +46,57 @@ hashDescrRIPEMD160 =
-- ,End Sequence -- ,End Sequence
-- ,OctetString digest -- ,OctetString digest
-- ,End Sequence -- ,End Sequence
--
toHashWithInfo :: [Word8] -> ByteString -> ByteString hashDescr :: (B.ByteArray ba, HashAlgorithm hashAlg)
toHashWithInfo pre digest = B.pack pre `B.append` digest => hashAlg -- ^ hash algorithm to use
-> [Word8] -- ^ the raw DER encoded ASN1 description of hash algorithm followed by the digest to be filled
-> HashDescr hashAlg ba
hashDescr hashAlg preASN1Descr =
HashDescr (\input -> B.pack preASN1Descr `B.append` B.convert (hashWith hashAlg input))
-- | A hash methods to generate a ASN.1 structure digest
data HashDescr hashAlg ba = HashDescr { unHashDescr :: ba -> ba }
-- | Run the digest function on some input and get the raw bytes
runHashDescr :: (HashAlgorithm hashAlg, B.ByteArray ba) => HashDescr hashAlg ba -> ba -> ba
runHashDescr h = unHashDescr h
-- | Describe the MD2 hashing algorithm
hashDescrMD2 :: B.ByteArray ba => HashDescr MD2 ba
hashDescrMD2 =
hashDescr MD2 [0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x02,0x05,0x00,0x04,0x10]
-- | Describe the MD5 hashing algorithm
hashDescrMD5 :: B.ByteArray ba => HashDescr MD5 ba
hashDescrMD5 =
hashDescr MD5 [0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x04,0x10]
-- | Describe the SHA1 hashing algorithm
hashDescrSHA1 :: B.ByteArray ba => HashDescr SHA1 ba
hashDescrSHA1 =
hashDescr SHA1 [0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,0x04,0x14]
-- | Describe the SHA224 hashing algorithm
hashDescrSHA224 :: B.ByteArray ba => HashDescr SHA224 ba
hashDescrSHA224 =
hashDescr SHA224 [0x30,0x2d,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x04,0x05,0x00,0x04,0x1c]
-- | Describe the SHA256 hashing algorithm
hashDescrSHA256 :: B.ByteArray ba => HashDescr SHA256 ba
hashDescrSHA256 =
hashDescr SHA256 [0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,0x20]
-- | Describe the SHA384 hashing algorithm
hashDescrSHA384 :: B.ByteArray ba => HashDescr SHA384 ba
hashDescrSHA384 =
hashDescr SHA384 [0x30,0x41,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00,0x04,0x30]
-- | Describe the SHA512 hashing algorithm
hashDescrSHA512 :: B.ByteArray ba => HashDescr SHA512 ba
hashDescrSHA512 =
hashDescr SHA512 [0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04,0x40]
-- | Describe the RIPEMD160 hashing algorithm
hashDescrRIPEMD160 :: B.ByteArray ba => HashDescr RIPEMD160 ba
hashDescrRIPEMD160 =
hashDescr RIPEMD160 [0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x24,0x03,0x02,0x01,0x05,0x00,0x04,0x14]

View File

@ -27,6 +27,7 @@ import Crypto.PubKey.RSA.Types
import Crypto.PubKey.RSA.Prim import Crypto.PubKey.RSA.Prim
import Crypto.PubKey.RSA (generateBlinder) import Crypto.PubKey.RSA (generateBlinder)
import Crypto.PubKey.HashDescr import Crypto.PubKey.HashDescr
import Crypto.Hash (HashAlgorithm)
import Data.ByteString (ByteString) import Data.ByteString (ByteString)
@ -115,16 +116,17 @@ encrypt pk m = do
-- information from the timing of the operation, the blinder can be set to None. -- information from the timing of the operation, the blinder can be set to None.
-- --
-- If unsure always set a blinder or use signSafer -- If unsure always set a blinder or use signSafer
sign :: Maybe Blinder -- ^ optional blinder sign :: HashAlgorithm hashAlg
-> HashDescr -- ^ hash descriptor => Maybe Blinder -- ^ optional blinder
-> HashDescr hashAlg ByteString -- ^ hash descriptor
-> PrivateKey -- ^ private key -> PrivateKey -- ^ private key
-> ByteString -- ^ message to sign -> ByteString -- ^ message to sign
-> Either Error ByteString -> Either Error ByteString
sign blinder hashDescr pk m = dp blinder pk `fmap` makeSignature hashDescr (private_size pk) m sign blinder hashDescr pk m = dp blinder pk `fmap` makeSignature hashDescr (private_size pk) m
-- | sign message using the private key and by automatically generating a blinder. -- | sign message using the private key and by automatically generating a blinder.
signSafer :: MonadRandom m signSafer :: (HashAlgorithm hashAlg, MonadRandom m)
=> HashDescr -- ^ Hash descriptor => HashDescr hashAlg ByteString -- ^ Hash descriptor
-> PrivateKey -- ^ private key -> PrivateKey -- ^ private key
-> ByteString -- ^ message to sign -> ByteString -- ^ message to sign
-> m (Either Error ByteString) -> m (Either Error ByteString)
@ -133,13 +135,21 @@ signSafer hashDescr pk m = do
return (sign (Just blinder) hashDescr pk m) return (sign (Just blinder) hashDescr pk m)
-- | verify message with the signed message -- | verify message with the signed message
verify :: HashDescr -> PublicKey -> ByteString -> ByteString -> Bool verify :: HashAlgorithm hashAlg
=> HashDescr hashAlg ByteString
-> PublicKey
-> ByteString
-> ByteString
-> Bool
verify hashDescr pk m sm = verify hashDescr pk m sm =
case makeSignature hashDescr (public_size pk) m of case makeSignature hashDescr (public_size pk) m of
Left _ -> False Left _ -> False
Right s -> s == (ep pk sm) Right s -> s == (ep pk sm)
{- makeSignature for sign and verify -} -- | make signature digest, used in 'sign' and 'verify'
makeSignature :: HashDescr -> Int -> ByteString -> Either Error ByteString makeSignature :: HashAlgorithm hashAlg
makeSignature hashDescr klen m = padSignature klen signature => HashDescr hashAlg ByteString
where signature = (digestToASN1 hashDescr) $ (hashFunction hashDescr) m -> Int
-> ByteString
-> Either Error ByteString
makeSignature hashDescr klen m = padSignature klen (runHashDescr hashDescr m)