diff --git a/Crypto/PubKey/HashDescr.hs b/Crypto/PubKey/HashDescr.hs deleted file mode 100644 index acc2aa0..0000000 --- a/Crypto/PubKey/HashDescr.hs +++ /dev/null @@ -1,101 +0,0 @@ --- | --- Module : Crypto.PubKey.HashDescr --- License : BSD-style --- Maintainer : Vincent Hanquez --- Stability : experimental --- Portability : Good --- --- Standard digests wrapped in ASN1 structure --- -module Crypto.PubKey.HashDescr - ( - -- * Types - HashDescr - , runHashDescr - -- * List of known hash description - , hashDescrMD2 - , hashDescrMD5 - , hashDescrSHA1 - , hashDescrSHA224 - , hashDescrSHA256 - , hashDescrSHA384 - , hashDescrSHA512 - , hashDescrRIPEMD160 - ) where - -import Data.Word -import Crypto.Hash -import qualified Crypto.Internal.ByteArray as B - --- --- ** 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 --- ,OID oid --- ,Null --- ,End Sequence --- ,OctetString digest --- ,End Sequence - -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 65351a1..dd37405 100644 --- a/Crypto/PubKey/RSA/PKCS15.hs +++ b/Crypto/PubKey/RSA/PKCS15.hs @@ -19,6 +19,8 @@ module Crypto.PubKey.RSA.PKCS15 -- * public key operations , encrypt , verify + -- * hash ASN1 description + , HashAlgorithmASN1 ) where import Crypto.Random.Types @@ -26,14 +28,59 @@ import Crypto.PubKey.Internal (and') import Crypto.PubKey.RSA.Types import Crypto.PubKey.RSA.Prim import Crypto.PubKey.RSA (generateBlinder) -import Crypto.PubKey.HashDescr -import Crypto.Hash (HashAlgorithm) +import Crypto.Hash import Data.ByteString (ByteString) +import Data.Word import Crypto.Internal.ByteArray (ByteArray, Bytes) import qualified Crypto.Internal.ByteArray as B +-- | A specialized class for hash algorithm that can product +-- a ASN1 wrapped description the algorithm plus the content +-- of the digest. +class HashAlgorithm hashAlg => HashAlgorithmASN1 hashAlg where + hashDigestASN1 :: ByteArray out => Digest hashAlg -> out + +instance HashAlgorithmASN1 MD2 where + hashDigestASN1 = addDigestPrefix [0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x02,0x05,0x00,0x04,0x10] +instance HashAlgorithmASN1 MD5 where + hashDigestASN1 = addDigestPrefix [0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x04,0x10] +instance HashAlgorithmASN1 SHA1 where + hashDigestASN1 = addDigestPrefix [0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,0x04,0x14] +instance HashAlgorithmASN1 SHA224 where + hashDigestASN1 = 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 = 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 = 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 = addDigestPrefix [0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04,0x40] +instance HashAlgorithmASN1 RIPEMD160 where + hashDigestASN1 = addDigestPrefix [0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x24,0x03,0x02,0x01,0x05,0x00,0x04,0x14] + +-- +-- ** 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 +-- ,OID oid +-- ,Null +-- ,End Sequence +-- ,OctetString digest +-- ,End Sequence +addDigestPrefix :: ByteArray out => [Word8] -> Digest hashAlg -> out +addDigestPrefix prefix digest = + B.pack prefix `B.append` B.convert digest + -- | This produce a standard PKCS1.5 padding for encryption pad :: (MonadRandom m, ByteArray message) => Int -> message -> m (Either Error message) pad len m @@ -116,40 +163,40 @@ 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 :: HashAlgorithm hashAlg +sign :: HashAlgorithmASN1 hashAlg => Maybe Blinder -- ^ optional blinder - -> HashDescr hashAlg ByteString -- ^ hash descriptor + -> hashAlg -- ^ hash algorithm -> 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 :: (HashAlgorithm hashAlg, MonadRandom m) - => HashDescr hashAlg ByteString -- ^ Hash descriptor +signSafer :: (HashAlgorithmASN1 hashAlg, MonadRandom m) + => hashAlg -- ^ Hash algorithm -> PrivateKey -- ^ private key -> ByteString -- ^ message to sign -> m (Either Error ByteString) -signSafer hashDescr pk m = do +signSafer hashAlg pk m = do blinder <- generateBlinder (private_n pk) - return (sign (Just blinder) hashDescr pk m) + return (sign (Just blinder) hashAlg pk m) -- | verify message with the signed message -verify :: HashAlgorithm hashAlg - => HashDescr hashAlg ByteString +verify :: HashAlgorithmASN1 hashAlg + => hashAlg -> PublicKey -> ByteString -> ByteString -> Bool -verify hashDescr pk m sm = - case makeSignature hashDescr (public_size pk) m of +verify hashAlg pk m sm = + case makeSignature hashAlg (public_size pk) m of Left _ -> False Right s -> s == (ep pk sm) -- | make signature digest, used in 'sign' and 'verify' -makeSignature :: HashAlgorithm hashAlg - => HashDescr hashAlg ByteString +makeSignature :: HashAlgorithmASN1 hashAlg + => hashAlg -> Int -> ByteString -> Either Error ByteString -makeSignature hashDescr klen m = padSignature klen (runHashDescr hashDescr m) +makeSignature hashAlg klen m = padSignature klen (hashDigestASN1 $ hashWith hashAlg m) diff --git a/cryptonite.cabal b/cryptonite.cabal index 637f599..8107f0f 100644 --- a/cryptonite.cabal +++ b/cryptonite.cabal @@ -1,5 +1,5 @@ Name: cryptonite -Version: 0.2 +Version: 0.3 Synopsis: Cryptography Primitives sink Description: A repository of cryptographic primitives. @@ -93,7 +93,6 @@ Library Crypto.Hash.IO Crypto.Hash.Algorithms Crypto.PubKey.Curve25519 - Crypto.PubKey.HashDescr Crypto.PubKey.MaskGenFunction Crypto.PubKey.DH Crypto.PubKey.DSA