diff --git a/Crypto/PubKey/HashDescr.hs b/Crypto/PubKey/HashDescr.hs index 6ddf0e1..97e48ef 100644 --- a/Crypto/PubKey/HashDescr.hs +++ b/Crypto/PubKey/HashDescr.hs @@ -11,8 +11,8 @@ module Crypto.PubKey.HashDescr ( -- * Types - HashFunction - , HashDescr(..) + HashDescr + , runHashDescr -- * List of known hash description , hashDescrMD2 , hashDescrMD5 @@ -24,73 +24,20 @@ module Crypto.PubKey.HashDescr , hashDescrRIPEMD160 ) where -import Data.ByteString.Char8 () -import Data.ByteString (ByteString) -import qualified Data.ByteString as B import Data.Word 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 - --- | Describe a hash function and a way to wrap the digest into --- an DER encoded ASN1 marshalled structure. -data HashDescr = HashDescr { hashFunction :: HashFunction -- ^ hash function - , digestToASN1 :: ByteString -> ByteString -- ^ convertion to an ASN1 wrapped digest bytestring - } - --- | Describe the MD2 hashing algorithm -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: +-- +-- ** Hack ** +-- +-- this happens to not need a real ASN1 encoder, because +-- thanks to the digest being a specific size AND +-- that the digest data is the last bytes in the encoding, +-- this allows to just prepend the right prefix to the +-- computed digest, to make it in the expected and valid shape. +-- +-- Otherwise the expected structure is in the following form: -- -- Start Sequence -- ,Start Sequence @@ -99,6 +46,57 @@ hashDescrRIPEMD160 = -- ,End Sequence -- ,OctetString digest -- ,End Sequence --- -toHashWithInfo :: [Word8] -> ByteString -> ByteString -toHashWithInfo pre digest = B.pack pre `B.append` digest + +hashDescr :: (B.ByteArray ba, HashAlgorithm hashAlg) + => 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] diff --git a/Crypto/PubKey/RSA/PKCS15.hs b/Crypto/PubKey/RSA/PKCS15.hs index deebc4a..e5e9e2d 100644 --- a/Crypto/PubKey/RSA/PKCS15.hs +++ b/Crypto/PubKey/RSA/PKCS15.hs @@ -27,6 +27,7 @@ import Crypto.PubKey.RSA.Types import Crypto.PubKey.RSA.Prim import Crypto.PubKey.RSA (generateBlinder) import Crypto.PubKey.HashDescr +import Crypto.Hash (HashAlgorithm) 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. -- -- If unsure always set a blinder or use signSafer -sign :: Maybe Blinder -- ^ optional blinder - -> HashDescr -- ^ hash descriptor +sign :: HashAlgorithm hashAlg + => Maybe Blinder -- ^ optional blinder + -> HashDescr hashAlg ByteString -- ^ hash descriptor -> PrivateKey -- ^ private key -> ByteString -- ^ message to sign -> Either Error ByteString 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. -signSafer :: MonadRandom m - => HashDescr -- ^ Hash descriptor +signSafer :: (HashAlgorithm hashAlg, MonadRandom m) + => HashDescr hashAlg ByteString -- ^ Hash descriptor -> PrivateKey -- ^ private key -> ByteString -- ^ message to sign -> m (Either Error ByteString) @@ -133,13 +135,21 @@ signSafer hashDescr pk m = do return (sign (Just blinder) hashDescr pk m) -- | 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 = case makeSignature hashDescr (public_size pk) m of Left _ -> False Right s -> s == (ep pk sm) -{- makeSignature for sign and verify -} -makeSignature :: HashDescr -> Int -> ByteString -> Either Error ByteString -makeSignature hashDescr klen m = padSignature klen signature - where signature = (digestToASN1 hashDescr) $ (hashFunction hashDescr) m +-- | make signature digest, used in 'sign' and 'verify' +makeSignature :: HashAlgorithm hashAlg + => HashDescr hashAlg ByteString + -> Int + -> ByteString + -> Either Error ByteString +makeSignature hashDescr klen m = padSignature klen (runHashDescr hashDescr m)