packages feed

crypto-pubkey 0.2.2 → 0.2.3

raw patch · 12 files changed

+336/−49 lines, 12 filesdep +deepseqdep ~crypto-pubkey-types

Dependencies added: deepseq

Dependency ranges changed: crypto-pubkey-types

Files

Benchs/Bench.hs view
@@ -10,13 +10,18 @@ import Crypto.PubKey.RSA.OAEP as OAEP import Crypto.PubKey.RSA.PSS as PSS import Crypto.PubKey.HashDescr+import Crypto.PubKey.ECC.ECDSA as ECDSA import Crypto.Random+import Control.DeepSeq  import qualified Data.ByteString as B  right (Right r) = r right (Left _)  = error "left received" +instance NFData Signature where+    rnf (Signature r s) = rnf r `seq` rnf s+ main = do     rng <- cprgCreate `fmap` createEntropyPool :: IO SystemRNG     let !bs = B.replicate 32 0@@ -28,6 +33,8 @@         !blinder = fst $ generateBlinder rng (RSA.public_n rsaPublickey)         oaepParams = OAEP.defaultOAEPParams SHA1.hash         pssParams  = PSS.defaultPSSParamsSHA1+        ecdsaSignatureP = fst $ ECDSA.sign rng ecdsaPrivatekeyP SHA1.hash bs+        ecdsaSignatureB = fst $ ECDSA.sign rng ecdsaPrivatekeyB SHA1.hash bs     defaultMain         [ bgroup "RSA PKCS15"             [ bench "encryption" $ nf (right . fst . PKCS15.encrypt rng rsaPublickey) bs@@ -62,5 +69,13 @@                 , bench "fast+blinding" $ nf (right . fst . PSS.sign rng (Just blinder) pssParams rsaPrivatekey) bs                 ]             , bench "verify" $ nf (PSS.verify pssParams rsaPublickey bs) signedMsgPSS+            ]+        , bgroup "ECDSA secp160r1"+            [ bench "sign" $ nf (fst . ECDSA.sign rng ecdsaPrivatekeyP SHA1.hash) bs+            , bench "verify"  $ nf (ECDSA.verify SHA1.hash ecdsaPublickeyP ecdsaSignatureP) bs+            ]+        , bgroup "ECDSA sect163k1"+            [ bench "sign" $ nf (fst . ECDSA.sign rng ecdsaPrivatekeyB SHA1.hash) bs+            , bench "verify"  $ nf (ECDSA.verify SHA1.hash ecdsaPublickeyB ecdsaSignatureB) bs             ]         ]
Benchs/PregenKeys.hs view
@@ -3,6 +3,8 @@ import qualified Crypto.PubKey.RSA as RSA import qualified Crypto.PubKey.DSA as DSA import qualified Crypto.PubKey.DH as DH+import qualified Crypto.PubKey.ECC.ECDSA as ECDSA+import qualified Crypto.Types.PubKey.ECC as ECC  rsaPrivatekey = RSA.PrivateKey     { RSA.private_pub  = rsaPublickey@@ -36,3 +38,20 @@     , DSA.public_y      = 0x4fa505e86e32922f1fa1702a120abdba088bb4be801d4c44f7fc6b9094d85cd52c429cbc2b39514e30909b31e2e2e0752b0fc05c1a7d9c05c3e52e49e6edef4c     } +ecdsaCurveP = ECC.getCurveByName ECC.SEC_p160r1++ecdsaPrivatekeyP = ECDSA.PrivateKey ecdsaCurveP 971761939728640320549601132085879836204587084162++ecdsaPublickeyP = ECDSA.PublicKey+     ecdsaCurveP+    (ECC.Point 466448783855397898016055842232266600516272889280+               1110706324081757720403272427311003102474457754220)++ecdsaCurveB = ECC.getCurveByName ECC.SEC_t163k1++ecdsaPrivatekeyB = ECDSA.PrivateKey ecdsaCurveB 5321230001203043918714616464614664646674949479949++ecdsaPublickeyB = ECDSA.PublicKey+    ecdsaCurveB+   (ECC.Point 0x37d529fa37e42195f10111127ffb2bb38644806bc+              0x447026eee8b34157f3eb51be5185d2be0249ed776)
Crypto/PubKey/DH.hs view
@@ -20,7 +20,7 @@  import Crypto.Number.ModArithmetic (expSafe) import Crypto.Number.Prime (generateSafePrime)-import Crypto.Number.Generate (generateOfSize)+import Crypto.Number.Generate (generateMax) import Crypto.Types.PubKey.DH import Crypto.Random.API import Control.Arrow (first)@@ -33,8 +33,8 @@  -- | generate a private number with no specific property -- this number is usually called X in DH text.-generatePrivate :: CPRG g => g -> Int -> (PrivateNumber, g)-generatePrivate rng bits = first PrivateNumber $ generateOfSize rng bits+generatePrivate :: CPRG g => g -> Params -> (PrivateNumber, g)+generatePrivate rng (Params p _) = first PrivateNumber $ generateMax rng p  -- | generate a public number that is for the other party benefits. -- this number is usually called Y in DH text.
+ Crypto/PubKey/ECC/ECDSA.hs view
@@ -0,0 +1,81 @@+-- | /WARNING:/ Signature operations may leak the private key. Signature verification+-- should be safe.+module Crypto.PubKey.ECC.ECDSA+    ( module Crypto.Types.PubKey.ECDSA+    , signWith+    , sign+    , verify+    ) where++import Control.Monad+import Crypto.Random.API+import Data.Bits (shiftR)+import Data.ByteString (ByteString)+import Crypto.Number.ModArithmetic (inverse)+import Crypto.Number.Serialize+import Crypto.Number.Generate+import Crypto.Types.PubKey.ECDSA+import Crypto.Types.PubKey.ECC+import Crypto.PubKey.HashDescr+import Crypto.PubKey.ECC.Prim++-- | Sign message using the private key and an explicit k number.+--+-- /WARNING:/ Vulnerable to timing attacks.+signWith :: Integer         -- ^ k random number+         -> PrivateKey      -- ^ private key+         -> HashFunction    -- ^ hash function+         -> ByteString      -- ^ message to sign+         -> Maybe Signature+signWith k (PrivateKey curve d) hash msg = do+    let z = tHash hash msg n+        CurveCommon _ _ g n _ = common_curve curve+    let point = pointMul curve k g+    r <- case point of+              PointO    -> Nothing+              Point x _ -> return $ x `mod` n+    kInv <- inverse k n+    let s = kInv * (z + r * d) `mod` n+    when (r == 0 || s == 0) Nothing+    return $ Signature r s++-- | Sign message using the private key.+--+-- /WARNING:/ Vulnerable to timing attacks.+sign :: CPRG g => g -> PrivateKey -> HashFunction -> ByteString -> (Signature, g)+sign rng pk hash msg =+    case signWith k pk hash msg of+         Nothing  -> sign rng' pk hash msg+         Just sig -> (sig, rng')+  where n = ecc_n . common_curve $ private_curve pk+        (k, rng') = generateBetween rng 1 (n - 1)++-- | Verify a bytestring using the public key.+verify :: HashFunction -> PublicKey -> Signature -> ByteString -> Bool+verify _ (PublicKey _ PointO) _ _ = False+verify hash pk@(PublicKey curve q) (Signature r s) msg+    | r < 1 || r >= n || s < 1 || s >= n = False+    | otherwise = maybe False (r ==) $ do+        w <- inverse s n+        let z  = tHash hash msg n+            u1 = z * w `mod` n+            u2 = r * w `mod` n+            -- TODO: Use Shamir's trick+            g' = pointMul curve u1 g+            q' = pointMul curve u2 q+            x  = pointAdd curve g' q'+        case x of+             PointO     -> Nothing+             Point x1 _ -> return $ x1 `mod` n+  where n = ecc_n cc+        g = ecc_g cc+        cc = common_curve $ public_curve pk++-- | Truncate and hash.+tHash ::  HashFunction -> ByteString -> Integer -> Integer+tHash hash m n+    | d > 0 = shiftR e d+    | otherwise = e+  where e = os2ip $ hash m+        d = log2 e - log2 n+        log2 = ceiling . logBase (2 :: Double) . fromIntegral
+ Crypto/PubKey/ECC/Generate.hs view
@@ -0,0 +1,29 @@+-- | Signature generation.+module Crypto.PubKey.ECC.Generate where++import Crypto.Random (CPRG)+import Crypto.Types.PubKey.ECC+import Crypto.Types.PubKey.ECDSA+import Crypto.Number.Generate+import Crypto.PubKey.ECC.Prim++-- | Generate Q given d.+--+-- /WARNING:/ Vulnerable to timing attacks.+generateQ :: Curve+          -> Integer+          -> Point+generateQ curve d = pointMul curve d g+  where g = ecc_g $ common_curve curve++-- | Generate a pair of (private, public) key.+--+-- /WARNING:/ Vulnerable to timing attacks.+generate :: CPRG g+         => g     -- ^ CPRG+         -> Curve -- ^ Elliptic Curve+         -> ((PublicKey, PrivateKey), g)+generate rng curve = ((PublicKey curve q, PrivateKey curve d), rng')+  where (d, rng') = generateBetween rng 1 (n - 1)+        q = generateQ curve d+        n = ecc_n $ common_curve curve
+ Crypto/PubKey/ECC/Prim.hs view
@@ -0,0 +1,68 @@+-- | Elliptic Curve Arithmetic.+--+-- /WARNING:/ These functions are vulnerable to timing attacks.+module Crypto.PubKey.ECC.Prim+    ( pointAdd+    , pointDouble+    , pointMul+    ) where++import Data.Maybe+import Crypto.Number.ModArithmetic+import Crypto.Number.F2m+import Crypto.Types.PubKey.ECC++-- | Elliptic Curve point addition.+--+-- /WARNING:/ Vulnerable to timing attacks.+pointAdd :: Curve -> Point -> Point -> Point+pointAdd _ PointO PointO = PointO+pointAdd _ PointO q = q+pointAdd _ p PointO = p+pointAdd c@(CurveFP (CurvePrime pr _)) p@(Point xp yp) q@(Point xq yq)+    | p == Point xq (-yq) = PointO+    | p == q = pointDouble c p+    | otherwise = let s  = divmod (yp - yq) (xp - xq) pr+                      xr = (s ^ (2::Int) - xp - xq) `mod` pr+                      yr = (s * (xp - xr) - yp) `mod` pr+                  in Point xr yr+pointAdd c@(CurveF2m (CurveBinary fx cc)) p@(Point xp yp) q@(Point xq yq)+    | p == Point xq (xq `addF2m` yq) = PointO+    | p == q = pointDouble c p+    | otherwise = fromMaybe PointO $ do+                     s <- divF2m fx (yp `addF2m` yq) (xp `addF2m` xq)+                     let xr = mulF2m fx s s `addF2m` s `addF2m` xp `addF2m` xq `addF2m` a+                         yr = mulF2m fx s (xp `addF2m` xr) `addF2m` xr `addF2m` yp+                     return $ Point xr yr+  where a = ecc_a cc++-- | Elliptic Curve point doubling.+--+-- /WARNING:/ Vulnerable to timing attacks.+pointDouble :: Curve -> Point -> Point+pointDouble _ PointO = PointO+pointDouble (CurveFP (CurvePrime pr cc)) (Point xp yp) =+    let l = divmod (3 * xp ^ (2::Int) + a) (2 * yp) pr+        xr = (l ^ (2::Int) - 2 * xp) `mod` pr+        yr = (l * (xp - xr) - yp) `mod` pr+    in Point xr yr+  where a = ecc_a cc+pointDouble (CurveF2m (CurveBinary fx cc)) (Point xp yp) = fromMaybe PointO $ do+    s <- return . addF2m xp =<< divF2m fx yp xp+    let xr = mulF2m fx s s `addF2m` s `addF2m` a+        yr = mulF2m fx xp xp `addF2m` mulF2m fx xr (s `addF2m` 1)+    return $ Point xr yr+  where a = ecc_a cc++-- | Elliptic curve point multiplication (double and add algorithm).+--+-- /WARNING:/ Vulnerable to timing attacks.+pointMul :: Curve -> Integer -> Point -> Point+pointMul c n p+    | n == 1 = p+    | odd n = pointAdd c p (pointMul c (n - 1) p)+    | otherwise = pointMul c (n `div` 2) (pointDouble c p)++-- | div and mod+divmod :: Integer -> Integer -> Integer -> Integer+divmod y x m = y * fromJust (inverse (x `mod` m) m) `mod` m
Tests/KAT.hs view
@@ -19,6 +19,7 @@ import KAT.OAEP import KAT.PSS import KAT.DSA+import KAT.ECDSA  data VectorMgf = VectorMgf { seed :: ByteString                            , dbMask :: ByteString@@ -39,4 +40,5 @@     , pssTests     , oaepTests     , dsaTests+    , ecdsaTests     ]
+ Tests/KAT/ECDSA.hs view
@@ -0,0 +1,66 @@+-- Test vectors are taken from GEC2: www.secg.org/collateral/gec2.pdf+{-# LANGUAGE OverloadedStrings #-}+module KAT.ECDSA (ecdsaTests) where++import Data.ByteString (ByteString)++import qualified Crypto.PubKey.ECC.ECDSA as ECDSA+import qualified Crypto.Types.PubKey.ECC as ECC+import qualified Crypto.Hash.SHA1 as SHA1++import Test.HUnit+import Test.Framework (testGroup)+import Test.Framework.Providers.HUnit (testCase)++data VectorECDSA = VectorECDSA+    { curve :: ECC.Curve+    , msg   :: ByteString+    , d     :: Integer+    , q     :: ECC.Point+    , k     :: Integer+    , r     :: Integer+    , s     :: Integer+    }++vectorsSHA1 =+    [ VectorECDSA+        { curve = ECC.getCurveByName ECC.SEC_p160r1+        , msg   = "abc"+        , d     = 971761939728640320549601132085879836204587084162+        , q     = ECC.Point 466448783855397898016055842232266600516272889280+                            1110706324081757720403272427311003102474457754220+        , k     = 702232148019446860144825009548118511996283736794+        , r     = 1176954224688105769566774212902092897866168635793+        , s     = 299742580584132926933316745664091704165278518100+        }+    , VectorECDSA+        { curve = ECC.getCurveByName ECC.SEC_t163k1+        , msg   = "abc"+        , d     = 5321230001203043918714616464614664646674949479949+        , q     = ECC.Point 0x037d529fa37e42195f10111127ffb2bb38644806bc+                            0x0447026eee8b34157f3eb51be5185d2be0249ed776+        , k     = 936523985789236956265265265235675811949404040044+        , r     = 875196600601491789979810028167552198674202899628+        , s     = 1935199835333115956886966454901154618180070051199+        }+    ]++vectorToPrivate :: VectorECDSA -> ECDSA.PrivateKey+vectorToPrivate vector = ECDSA.PrivateKey (curve vector) (d vector)++vectorToPublic :: VectorECDSA -> ECDSA.PublicKey+vectorToPublic vector = ECDSA.PublicKey (curve vector) (q vector)++doSignatureTest (i, vector) = testCase (show i) (expected @=? actual)+  where expected = Just $ ECDSA.Signature (r vector) (s vector)+        actual   = ECDSA.signWith (k vector) (vectorToPrivate vector) SHA1.hash (msg vector)++doVerifyTest (i, vector) = testCase (show i) (True @=? actual)+  where actual = ECDSA.verify SHA1.hash (vectorToPublic vector) (ECDSA.Signature (r vector) (s vector)) (msg vector)++ecdsaTests = testGroup "DSA"+    [ testGroup "SHA1"+        [ testGroup "signature" $ map doSignatureTest (zip [0..] vectorsSHA1)+        , testGroup "verify" $ map doVerifyTest (zip [0..] vectorsSHA1)+        ]+    ]
Tests/PregenKeys.hs view
@@ -2,6 +2,8 @@  import qualified Crypto.PubKey.RSA as RSA import qualified Crypto.PubKey.DSA as DSA+import qualified Crypto.PubKey.ECC.ECDSA as ECDSA+import qualified Crypto.Types.PubKey.ECC as ECC import qualified Crypto.PubKey.DH as DH  rsaPrivatekey = RSA.PrivateKey@@ -36,3 +38,20 @@     , DSA.public_y      = 0x4fa505e86e32922f1fa1702a120abdba088bb4be801d4c44f7fc6b9094d85cd52c429cbc2b39514e30909b31e2e2e0752b0fc05c1a7d9c05c3e52e49e6edef4c     } +ecdsaCurveP = ECC.getCurveByName ECC.SEC_p160r1++ecdsaPrivatekeyP = ECDSA.PrivateKey ecdsaCurveP 971761939728640320549601132085879836204587084162++ecdsaPublickeyP = ECDSA.PublicKey+     ecdsaCurveP+    (ECC.Point 466448783855397898016055842232266600516272889280+               1110706324081757720403272427311003102474457754220)++ecdsaCurveB = ECC.getCurveByName ECC.SEC_t163k1++ecdsaPrivatekeyB = ECDSA.PrivateKey ecdsaCurveB 5321230001203043918714616464614664646674949479949++ecdsaPublickeyB = ECDSA.PublicKey+    ecdsaCurveB+   (ECC.Point 0x37d529fa37e42195f10111127ffb2bb38644806bc+              0x447026eee8b34157f3eb51be5185d2be0249ed776)
− Tests/T.hs
@@ -1,44 +0,0 @@-{-# LANGUAGE BangPatterns #-}-module Main where--import PregenKeys-import Control.Applicative-import qualified Crypto.Hash.SHA1 as SHA1-import qualified Crypto.PubKey.RSA as RSA-import qualified Crypto.PubKey.RSA.OAEP as RSAOAEP-import qualified Crypto.PubKey.RSA.PKCS15 as RSAPKCS15-import qualified Data.ByteString as B--import Crypto.Random--priv = rsaPrivatekey-pub  = rsaPublickey-oaepParams = RSAOAEP.defaultOAEPParams SHA1.hash--doEncrypt = False--nbEncrypt = 944242-nbDecrypt = 64325--main = do-    system <- cprgCreate <$> createEntropyPool :: IO SystemRNG-    if doEncrypt-        then do-            putStrLn $ show $ justEncrypt system nbEncrypt B.empty-        else do-            let t = either (error . show) id $ fst $ RSAPKCS15.encrypt system pub msg-    --let t = either (error . show) id $ RSAOAEP.encryptWithSeed (B.replicate 20 0) oaepParams pub msg- -            putStrLn $ show $ decryptEncrypt nbDecrypt (t, msg)-  where msg = B.replicate 10 4-        decryptEncrypt 0 (!bEnc, !b) = b-        decryptEncrypt n (!bEnc, !b) =-            let bDec = either (error . show) id $ RSAPKCS15.decrypt Nothing priv bEnc in-            --let bDec = either (error . show) id $ RSAOAEP.decrypt Nothing oaepParams priv bEnc in-            decryptEncrypt (n-1) (bEnc, bDec)--        justEncrypt _ 0 (!bEnc) = bEnc-        justEncrypt rng n (!bEnc) =-            let bEnc2 = either (error . show) id $ fst $ RSAPKCS15.encrypt rng pub msg in-            justEncrypt rng (n-1) bEnc2 -            
Tests/Tests.hs view
@@ -22,6 +22,9 @@ import qualified Crypto.PubKey.RSA.PKCS15 as RSAPKCS15 import qualified Crypto.PubKey.RSA.OAEP as RSAOAEP import qualified Crypto.PubKey.DSA as DSA+import qualified Crypto.PubKey.ECC.ECDSA as ECDSA+import Crypto.Types.PubKey.ECC+import Crypto.PubKey.ECC.Generate import qualified Crypto.PubKey.DH as DH import Crypto.Number.Serialize (i2osp) import Crypto.PubKey.HashDescr@@ -116,6 +119,26 @@ prop_dsa_valid (RSAMessage _ msg) = DSA.verify (SHA1.hash) dsaPublickey signature msg     where (signature, rng') = DSA.sign rng dsaPrivatekey (SHA1.hash) msg +prop_ecdsa_prime_valid (RSAMessage _ msg) = ECDSA.verify SHA1.hash ecdsaPublickeyP signature msg+    where (signature, rng') = ECDSA.sign rng ecdsaPrivatekeyP SHA1.hash msg++prop_ecdsa_binary_valid (RSAMessage _ msg) = ECDSA.verify SHA1.hash ecdsaPublickeyB signature msg+    where (signature, rng') = ECDSA.sign rng ecdsaPrivatekeyB SHA1.hash msg++prop_ecdsa_curve_valid keypair = ECDSA.verify SHA1.hash pubkey signature "test"+    where (signature, rng') = ECDSA.sign rng privkey SHA1.hash "test"+          pubkey  = ECDSA.toPublicKey keypair+          privkey = ECDSA.toPrivateKey keypair++instance Arbitrary ECDSA.KeyPair where+    arbitrary = do curve <- arbitrary+                   d     <- getPositive <$> (arbitrary :: Gen (Positive Integer))+                   let q = generateQ curve d+                   return $ ECDSA.KeyPair curve q d++instance Arbitrary Curve where+    arbitrary = elements $ map getCurveByName $ enumFrom SEC_p112r1+ instance Arbitrary DH.PrivateNumber where     arbitrary = fromIntegral <$> (suchThat (arbitrary :: Gen Integer) (\x -> x >= 1)) @@ -143,6 +166,9 @@     [ testProperty "RSA(PKCS15) (slow)" prop_rsa_sign_slow_valid     , testProperty "RSA(PKCS15) (fast)" prop_rsa_sign_fast_valid     , testProperty "DSA" prop_dsa_valid+    , testProperty "ECDSA Prime" prop_ecdsa_prime_valid+    , testProperty "ECDSA Binary" prop_ecdsa_binary_valid+    , testProperty "ECDSA Curve" prop_ecdsa_curve_valid     ]  asymOtherTests = testGroup "assymetric other tests"
crypto-pubkey.cabal view
@@ -1,5 +1,5 @@ Name:                crypto-pubkey-Version:             0.2.2+Version:             0.2.3 Description:     Public Key cryptography     .@@ -29,7 +29,7 @@                    , bytestring                    , byteable                    , crypto-random >= 0.0 && < 0.1-                   , crypto-pubkey-types >= 0.4 && < 0.5+                   , crypto-pubkey-types >= 0.4.1 && < 0.5                    , cryptohash >= 0.9.1                    , crypto-numbers >= 0.2.2   Exposed-modules:   Crypto.PubKey.RSA@@ -41,6 +41,9 @@                      Crypto.PubKey.DH                      Crypto.PubKey.HashDescr                      Crypto.PubKey.MaskGenFunction+                     Crypto.PubKey.ECC.Generate+                     Crypto.PubKey.ECC.Prim+                     Crypto.PubKey.ECC.ECDSA   other-modules:     Crypto.PubKey.ElGamal                      Crypto.PubKey.RSA.Types                      Crypto.PubKey.Internal@@ -55,6 +58,7 @@                    , byteable                    , cryptohash                    , crypto-pubkey+                   , crypto-pubkey-types                    , crypto-numbers                    , crypto-random                    , QuickCheck >= 2@@ -72,8 +76,10 @@                    , cryptohash                    , crypto-random                    , crypto-pubkey+                   , crypto-pubkey-types                    , criterion                    , mtl+                   , deepseq  source-repository head   type:     git