From 395f75c6b7f66d313b4d44be4ed1317f9d7c7042 Mon Sep 17 00:00:00 2001 From: joe Date: Sun, 15 Dec 2013 22:06:29 -0500 Subject: Adapted to new ecc solutoin for OpenPGP-Haskell --- Data/OpenPGP/Util/Base.hs | 16 +++++ Data/OpenPGP/Util/Sign.hs | 143 +++++++++++++++++++++++--------------------- Data/OpenPGP/Util/Verify.hs | 23 +++++++ openpgp-util.cabal | 1 + 4 files changed, 116 insertions(+), 67 deletions(-) diff --git a/Data/OpenPGP/Util/Base.hs b/Data/OpenPGP/Util/Base.hs index 802d503..aaa02c7 100644 --- a/Data/OpenPGP/Util/Base.hs +++ b/Data/OpenPGP/Util/Base.hs @@ -14,6 +14,8 @@ import Crypto.Hash.SHA224 as SHA224 import Crypto.Hash.RIPEMD160 as RIPEMD160 import qualified Crypto.PubKey.RSA as Vincent.RSA import Crypto.PubKey.HashDescr as Vincent +import qualified Crypto.Types.PubKey.ECC as Vincent.ECDSA +import qualified Crypto.Types.PubKey.ECDSA as Vincent.ECDSA import Data.OpenPGP.Util.Fingerprint (fingerprint) @@ -25,6 +27,20 @@ hashBySymbol OpenPGP.SHA512 = SHA512.hashlazy hashBySymbol OpenPGP.SHA224 = SHA224.hashlazy hashBySymbol OpenPGP.RIPEMD160 = RIPEMD160.hashlazy +curveFromOID :: Integer -> Vincent.ECDSA.Curve +curveFromOID 0x2a8648ce3d030107 = Vincent.ECDSA.getCurveByName Vincent.ECDSA.SEC_p256r1 -- NIST P-256 +curveFromOID 0x2B81040022 = Vincent.ECDSA.getCurveByName Vincent.ECDSA.SEC_p384r1 -- NIST P-384 +curveFromOID 0x2B81040023 = Vincent.ECDSA.getCurveByName Vincent.ECDSA.SEC_p521r1 -- NIST P-521 +curveFromOID 0x2b8104000a = Vincent.ECDSA.getCurveByName Vincent.ECDSA.SEC_p256k1 -- bitcoin curve +curveFromOID n = error $ "Unknown curve: "++ show n + +ecdsaKey k = Vincent.ECDSA.PublicKey curve (Vincent.ECDSA.Point x y) + where + x = keyParam 'x' k + y = keyParam 'y' k + curve = curveFromOID (keyParam 'c' k) + + toStrictBS :: LZ.ByteString -> BS.ByteString toStrictBS = BS.concat . LZ.toChunks diff --git a/Data/OpenPGP/Util/Sign.hs b/Data/OpenPGP/Util/Sign.hs index e492f95..4a6eb4f 100644 --- a/Data/OpenPGP/Util/Sign.hs +++ b/Data/OpenPGP/Util/Sign.hs @@ -17,9 +17,15 @@ import qualified Crypto.Random as Vincent import qualified Crypto.PubKey.DSA as Vincent.DSA import qualified Crypto.PubKey.RSA as Vincent.RSA import qualified Crypto.PubKey.RSA.PKCS15 as Vincent.RSA +import qualified Crypto.PubKey.ECC.ECDSA as Vincent.ECDSA import Data.OpenPGP.Util.Base +privateECDSAkey :: OpenPGP.Packet -> Vincent.ECDSA.PrivateKey +privateECDSAkey k = Vincent.ECDSA.PrivateKey curve d + where + d = keyParam 'd' k + curve = curveFromOID (keyParam 'c' k) privateDSAkey :: OpenPGP.Packet -> Vincent.DSA.PrivateKey privateDSAkey k = Vincent.DSA.PrivateKey @@ -46,74 +52,77 @@ privateRSAkey k = -- Operation is unsafe in that it silently re-uses "random" bytes when -- entropy runs out. Use pgpSign for a safer interface. unsafeSign :: (Vincent.CPRG g) => -- CryptoRandomGen g) => - OpenPGP.Message -- ^ SecretKeys, one of which will be used - -> OpenPGP.SignatureOver -- ^ Data to sign, and optional signature packet - -> OpenPGP.HashAlgorithm -- ^ HashAlgorithm to use in signature - -> String -- ^ KeyID of key to choose - -> Integer -- ^ Timestamp for signature (unless sig supplied) - -> g -- ^ Random number generator - -> (OpenPGP.SignatureOver, g) + OpenPGP.Message -- ^ SecretKeys, one of which will be used + -> OpenPGP.SignatureOver -- ^ Data to sign, and optional signature packet + -> OpenPGP.HashAlgorithm -- ^ HashAlgorithm to use in signature + -> String -- ^ KeyID of key to choose + -> Integer -- ^ Timestamp for signature (unless sig supplied) + -> g -- ^ Random number generator + -> (OpenPGP.SignatureOver, g) unsafeSign keys over hsh keyid timestamp g = (over {OpenPGP.signatures_over = [sig]}, g') - where - (final, g') = case OpenPGP.key_algorithm sig of - OpenPGP.DSA -> ([dsaR, dsaS], dsaG) - kalgo | kalgo `elem` [OpenPGP.RSA,OpenPGP.RSA_S] -> ([toNum rsaFinal], g) - | otherwise -> - error ("Unsupported key algorithm " ++ show kalgo ++ "in sign") - (Vincent.DSA.Signature dsaR dsaS,dsaG) = let k' = privateDSAkey k in - Vincent.DSA.sign g k' (dsaTruncate k' . bhash) dta - (Right rsaFinal,_) = Vincent.RSA.signSafer g desc (privateRSAkey k) dta - dsaTruncate (Vincent.DSA.PrivateKey (Vincent.DSA.Params _ _ q) _) = BS.take (integerBytesize q) - dta = toStrictBS $ encode over `LZ.append` OpenPGP.trailer sig - sig = findSigOrDefault (listToMaybe $ OpenPGP.signatures_over over) - -- padding = emsa_pkcs1_v1_5_hash_padding hsh - desc = hashAlgoDesc hsh - bhash = hashBySymbol hsh . toLazyBS - toNum = BS.foldl (\a b -> a `shiftL` 8 .|. fromIntegral b) 0 - Just k = find_key keys keyid - - -- Either a SignaturePacket was found, or we need to make one - findSigOrDefault (Just s) = OpenPGP.signaturePacket - (OpenPGP.version s) - (OpenPGP.signature_type s) - (OpenPGP.key_algorithm k) -- force to algo of key - hsh -- force hash algorithm - (OpenPGP.hashed_subpackets s) - (OpenPGP.unhashed_subpackets s) - (OpenPGP.hash_head s) - (map OpenPGP.MPI final) - findSigOrDefault Nothing = OpenPGP.signaturePacket - 4 - defaultStype - (OpenPGP.key_algorithm k) -- force to algo of key - hsh - ([ - -- Do we really need to pass in timestamp just for the default? - OpenPGP.SignatureCreationTimePacket $ fromIntegral timestamp, - OpenPGP.IssuerPacket $ fingerprint k - ] ++ (case over of - OpenPGP.KeySignature {} -> [OpenPGP.KeyFlagsPacket { - OpenPGP.certify_keys = True, - OpenPGP.sign_data = True, - OpenPGP.encrypt_communication = False, - OpenPGP.encrypt_storage = False, - OpenPGP.split_key = False, - OpenPGP.authentication = False, - OpenPGP.group_key = False - }] - _ -> [] - )) - [] - 0 -- TODO - (map OpenPGP.MPI final) - - defaultStype = case over of - OpenPGP.DataSignature ld _ - | OpenPGP.format ld == 'b' -> 0x00 - | otherwise -> 0x01 - OpenPGP.KeySignature {} -> 0x1F - OpenPGP.SubkeySignature {} -> 0x18 - OpenPGP.CertificationSignature {} -> 0x13 + where + (final, g') = case OpenPGP.key_algorithm sig of + OpenPGP.DSA -> ([dsaR, dsaS], dsaG) + OpenPGP.ECDSA -> ([ecdsaR,ecdsaS],ecdsaG) + kalgo | kalgo `elem` [OpenPGP.RSA,OpenPGP.RSA_S] -> ([toNum rsaFinal], g) + | otherwise -> + error ("Unsupported key algorithm " ++ show kalgo ++ " in sign") + (Vincent.DSA.Signature dsaR dsaS,dsaG) = let k' = privateDSAkey k in + Vincent.DSA.sign g k' (dsaTruncate k' . bhash) dta + (Vincent.ECDSA.Signature ecdsaR ecdsaS,ecdsaG) = let k' = privateECDSAkey k in + Vincent.ECDSA.sign g k' bhash dta + (Right rsaFinal,_) = Vincent.RSA.signSafer g desc (privateRSAkey k) dta + dsaTruncate (Vincent.DSA.PrivateKey (Vincent.DSA.Params _ _ q) _) = BS.take (integerBytesize q) + dta = toStrictBS $ encode over `LZ.append` OpenPGP.trailer sig + sig = findSigOrDefault (listToMaybe $ OpenPGP.signatures_over over) + -- padding = emsa_pkcs1_v1_5_hash_padding hsh + desc = hashAlgoDesc hsh + bhash = hashBySymbol hsh . toLazyBS + toNum = BS.foldl (\a b -> a `shiftL` 8 .|. fromIntegral b) 0 + Just k = find_key keys keyid + + -- Either a SignaturePacket was found, or we need to make one + findSigOrDefault (Just s) = OpenPGP.signaturePacket + (OpenPGP.version s) + (OpenPGP.signature_type s) + (OpenPGP.key_algorithm k) -- force to algo of key + hsh -- force hash algorithm + (OpenPGP.hashed_subpackets s) + (OpenPGP.unhashed_subpackets s) + (OpenPGP.hash_head s) + (map OpenPGP.MPI final) + findSigOrDefault Nothing = OpenPGP.signaturePacket + 4 + defaultStype + (OpenPGP.key_algorithm k) -- force to algo of key + hsh + ([ + -- Do we really need to pass in timestamp just for the default? + OpenPGP.SignatureCreationTimePacket $ fromIntegral timestamp, + OpenPGP.IssuerPacket $ fingerprint k + ] ++ (case over of + OpenPGP.KeySignature {} -> [OpenPGP.KeyFlagsPacket { + OpenPGP.certify_keys = True, + OpenPGP.sign_data = True, + OpenPGP.encrypt_communication = False, + OpenPGP.encrypt_storage = False, + OpenPGP.split_key = False, + OpenPGP.authentication = False, + OpenPGP.group_key = False + }] + _ -> [] + )) + [] + 0 -- TODO + (map OpenPGP.MPI final) + + defaultStype = case over of + OpenPGP.DataSignature ld _ + | OpenPGP.format ld == 'b' -> 0x00 + | otherwise -> 0x01 + OpenPGP.KeySignature {} -> 0x1F + OpenPGP.SubkeySignature {} -> 0x18 + OpenPGP.CertificationSignature {} -> 0x13 diff --git a/Data/OpenPGP/Util/Verify.hs b/Data/OpenPGP/Util/Verify.hs index 2367570..b42e664 100644 --- a/Data/OpenPGP/Util/Verify.hs +++ b/Data/OpenPGP/Util/Verify.hs @@ -1,5 +1,7 @@ +{-# LANGUAGE OverloadedStrings #-} module Data.OpenPGP.Util.Verify where +import Debug.Trace import qualified Data.OpenPGP as OpenPGP import Data.Maybe import Data.Binary (encode) @@ -9,6 +11,8 @@ import qualified Data.ByteString.Lazy as LZ import qualified Crypto.PubKey.DSA as Vincent.DSA import qualified Crypto.PubKey.RSA.PKCS15 as Vincent.RSA +import qualified Crypto.PubKey.ECC.ECDSA as Vincent.ECDSA +-- import Math.NumberTheory.Moduli import Data.OpenPGP.Util.Base @@ -19,6 +23,14 @@ dsaKey k = Vincent.DSA.PublicKey (keyParam 'y' k) +{- +applyCurve :: Vincent.ECDSA.CurveCommon -> Integer -> Integer +applyCurve curve x = x*x*x + x*a + b + where + a = Vincent.ECDSA.ecc_a curve + b = Vincent.ECDSA.ecc_b curve +-} + -- | Verify a message signature verify :: OpenPGP.Message -- ^ Keys that may have made the signature @@ -35,17 +47,28 @@ verifyOne keys sig over = fmap (const sig) $ maybeKey >>= verification >>= guard where verification = case OpenPGP.key_algorithm sig of OpenPGP.DSA -> dsaVerify + OpenPGP.ECDSA -> ecdsaVerify alg | alg `elem` [OpenPGP.RSA,OpenPGP.RSA_S] -> rsaVerify | otherwise -> const Nothing dsaVerify k = let k' = dsaKey k in Just $ Vincent.DSA.verify (dsaTruncate k' . bhash) k' dsaSig over + ecdsaVerify k = let k' = ecdsaKey k + r = Just $ Vincent.ECDSA.verify bhash k' ecdsaSig over + in r -- trace ("ecdsaVerify: "++show r) r rsaVerify k = Just $ Vincent.RSA.verify desc (rsaKey k) over rsaSig [rsaSig] = map (toStrictBS . LZ.drop 2 . encode) (OpenPGP.signature sig) dsaSig = let [OpenPGP.MPI r, OpenPGP.MPI s] = OpenPGP.signature sig in Vincent.DSA.Signature r s + ecdsaSig = let [OpenPGP.MPI r, OpenPGP.MPI s] = OpenPGP.signature sig in + Vincent.ECDSA.Signature r s dsaTruncate (Vincent.DSA.PublicKey (Vincent.DSA.Params _ _ q) _) = BS.take (integerBytesize q) + {- + ecdsaTruncate (Vincent.ECDSA.PublicKey _ (Vincent.ECDSA.Point x y)) = BS.take (integerBytesize x + + integerBytesize y ) + -} bhash = hashBySymbol hash_algo . toLazyBS desc = hashAlgoDesc hash_algo hash_algo = OpenPGP.hash_algorithm sig maybeKey = OpenPGP.signature_issuer sig >>= find_key keys + -- in trace ("maybeKey="++show (fmap OpenPGP.key_algorithm r)) r diff --git a/openpgp-util.cabal b/openpgp-util.cabal index 5bc4bfb..ca02709 100644 --- a/openpgp-util.cabal +++ b/openpgp-util.cabal @@ -45,6 +45,7 @@ library crypto-random >= 0.0.7, cryptohash >= 0.9.1, crypto-pubkey >= 0.2.3, + crypto-pubkey-types >= 0.4.1, cipher-cast5 -any, byteable, crypto-cipher-types >= 0.0.9, -- cgit v1.2.3