summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Base58.hs37
-rw-r--r--KeyRing.hs313
-rw-r--r--kiki.hs272
3 files changed, 340 insertions, 282 deletions
diff --git a/Base58.hs b/Base58.hs
new file mode 100644
index 0000000..26f1cb2
--- /dev/null
+++ b/Base58.hs
@@ -0,0 +1,37 @@
1module Base58 where
2
3import qualified Crypto.Hash.SHA256 as SHA256
4import qualified Data.ByteString as S
5import Data.Maybe
6import Data.List
7import Data.Word ( Word8 )
8import Control.Monad
9
10base58chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
11
12base58digits :: [Char] -> Maybe [Int]
13base58digits str = sequence mbs
14 where
15 mbs = map (flip elemIndex base58chars) str
16
17-- 5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ
18base58_decode :: [Char] -> Maybe (Word8,[Word8])
19base58_decode str = do
20 ds <- base58digits str
21 let n = foldl' (\a b-> a*58 + b) 0 $ ( map fromIntegral ds :: [Integer] )
22 rbytes = unfoldr getbyte n
23 getbyte d = do
24 guard (d/=0)
25 let (q,b) = d `divMod` 256
26 return (fromIntegral b,q)
27
28 let (rcksum,rpayload) = splitAt 4 $ rbytes
29 a_payload = reverse rpayload
30 hash_result = S.take 4 . SHA256.hash . SHA256.hash . S.pack $ a_payload
31 expected_hash = S.pack $ reverse rcksum
32 (network_id,payload) = splitAt 1 a_payload
33
34 network_id <- listToMaybe network_id
35 guard (hash_result==expected_hash)
36 return (network_id,payload)
37
diff --git a/KeyRing.hs b/KeyRing.hs
index cdfcd34..2a80930 100644
--- a/KeyRing.hs
+++ b/KeyRing.hs
@@ -2,6 +2,7 @@
2{-# LANGUAGE TupleSections #-} 2{-# LANGUAGE TupleSections #-}
3{-# LANGUAGE ViewPatterns #-} 3{-# LANGUAGE ViewPatterns #-}
4{-# LANGUAGE ExistentialQuantification #-} 4{-# LANGUAGE ExistentialQuantification #-}
5{-# LANGUAGE OverloadedStrings #-}
5module KeyRing where 6module KeyRing where
6 7
7import System.Environment 8import System.Environment
@@ -11,17 +12,32 @@ import Data.Char
11import Data.List 12import Data.List
12import Data.OpenPGP 13import Data.OpenPGP
13import Data.Functor 14import Data.Functor
14import Control.Applicative ( (<$>) ) 15import Data.Bits ( (.|.) )
16-- import Control.Applicative ( (<$>) )
15import System.Directory ( getHomeDirectory, doesFileExist ) 17import System.Directory ( getHomeDirectory, doesFileExist )
16import Control.Arrow ( first, second ) 18import Control.Arrow ( first, second )
17import Data.OpenPGP.Util ( fingerprint ) 19import Data.OpenPGP.Util ( fingerprint )
18import Data.ByteString.Lazy ( ByteString ) 20import Data.ByteString.Lazy ( ByteString )
19import Text.Show.Pretty as PP ( ppShow ) 21import Text.Show.Pretty as PP ( ppShow )
22import Data.Word ( Word8 )
23import Data.Binary ( decode )
24import ControlMaybe ( handleIO_ )
20import qualified Data.Map as Map 25import qualified Data.Map as Map
21 26import qualified Data.ByteString.Lazy as L ( null, readFile, ByteString )
27import qualified Data.ByteString.Lazy.Char8 as Char8 ( span, unpack, break )
28import qualified Crypto.Types.PubKey.ECC as ECC
29import System.Posix.Types (EpochTime)
30import System.Posix.Files ( modificationTime, getFileStatus )
31
32import qualified CryptoCoins as CryptoCoins
33import Base58
22import FunctorToMaybe 34import FunctorToMaybe
23import DotLock 35import DotLock
24 36
37-- DER-encoded elliptic curve ids
38nistp256_id = 0x2a8648ce3d030107
39secp256k1_id = 0x2b8104000a
40
25data HomeDir = 41data HomeDir =
26 HomeDir { homevar :: String 42 HomeDir { homevar :: String
27 , appdir :: String 43 , appdir :: String
@@ -51,6 +67,7 @@ data KeyRingRuntime = KeyRingRuntime
51 , rtRings :: [FilePath] 67 , rtRings :: [FilePath]
52 , rtWallets :: [FilePath] 68 , rtWallets :: [FilePath]
53 , rtGrip :: Maybe String 69 , rtGrip :: Maybe String
70 , rtKeyDB :: KeyDB
54 } 71 }
55 72
56data KeyRingAction a = KeyRingAction a | RunTimeAction (KeyRingRuntime -> a) 73data KeyRingAction a = KeyRingAction a | RunTimeAction (KeyRingRuntime -> a)
@@ -61,17 +78,19 @@ data KeyRingData = KeyRingData
61 , homeSpec :: Maybe String 78 , homeSpec :: Maybe String
62 } 79 }
63 80
64filesToLock k secring pubring = do 81resolveInputFile secring pubring = resolve
65 (f,(rtyp,ftyp)) <- Map.toList (kFiles k)
66 case rtyp of
67 ConstRef -> []
68 MutableRef {} -> resolve f
69 where 82 where
70 resolve HomeSec = return secring 83 resolve HomeSec = return secring
71 resolve HomePub = return pubring 84 resolve HomePub = return pubring
72 resolve (ArgFile f) = return f 85 resolve (ArgFile f) = return f
73 resolve _ = [] 86 resolve _ = []
74 87
88filesToLock k secring pubring = do
89 (f,(rtyp,ftyp)) <- Map.toList (kFiles k)
90 case rtyp of
91 ConstRef -> []
92 MutableRef {} -> resolveInputFile secring pubring f
93
75 94
76-- kret :: a -> KeyRingData a 95-- kret :: a -> KeyRingData a
77-- kret x = KeyRingData Map.empty Nothing (KeyRingAction x) 96-- kret x = KeyRingData Map.empty Nothing (KeyRingAction x)
@@ -102,6 +121,188 @@ data KikiResult a = KikiResult
102 , kikiReport :: [ (FilePath, KikiReportAction) ] 121 , kikiReport :: [ (FilePath, KikiReportAction) ]
103 } 122 }
104 123
124keyPacket (KeyData k _ _ _) = packet k
125
126usage (NotationDataPacket
127 { human_readable = True
128 , notation_name = "usage@"
129 , notation_value = u
130 }) = Just u
131usage _ = Nothing
132
133keyflags flgs@(KeyFlagsPacket {}) =
134 Just . toEnum $
135 ( bit 0x1 certify_keys
136 .|. bit 0x2 sign_data
137 .|. bit 0x4 encrypt_communication
138 .|. bit 0x8 encrypt_storage ) :: Maybe PGPKeyFlags
139 -- other flags:
140 -- split_key
141 -- authentication (ssh-client)
142 -- group_key
143 where
144 bit v f = if f flgs then v else 0
145keyflags _ = Nothing
146
147
148data PGPKeyFlags =
149 Special
150 | Vouch -- Signkey
151 | Sign
152 | VouchSign
153 | Communication
154 | VouchCommunication
155 | SignCommunication
156 | VouchSignCommunication
157 | Storage
158 | VouchStorage
159 | SignStorage
160 | VouchSignStorage
161 | Encrypt
162 | VouchEncrypt
163 | SignEncrypt
164 | VouchSignEncrypt
165 deriving (Eq,Show,Read,Enum)
166usageString flgs =
167 case flgs of
168 Special -> "special"
169 Vouch -> "vouch" -- signkey
170 Sign -> "sign"
171 VouchSign -> "vouch-sign"
172 Communication -> "communication"
173 VouchCommunication -> "vouch-communication"
174 SignCommunication -> "sign-communication"
175 VouchSignCommunication -> "vouch-sign-communication"
176 Storage -> "storage"
177 VouchStorage -> "vouch-storage"
178 SignStorage -> "sign-storage"
179 VouchSignStorage -> "vouch-sign-storage"
180 Encrypt -> "encrypt"
181 VouchEncrypt -> "vouch-encrypt"
182 SignEncrypt -> "sign-encrypt"
183 VouchSignEncrypt -> "vouch-sign-encrypt"
184
185
186
187
188-- matchpr computes the fingerprint of the given key truncated to
189-- be the same lenght as the given fingerprint for comparison.
190matchpr fp k = reverse $ zipWith const (reverse (fingerprint k)) fp
191
192keyFlags wkun uids = keyFlags0 wkun (filter isSignaturePacket uids)
193keyFlags0 wkun uidsigs = concat
194 [ keyflags
195 , preferredsym
196 , preferredhash
197 , preferredcomp
198 , features ]
199
200 where
201 subs = concatMap hashed_subpackets uidsigs
202 keyflags = filterOr isflags subs $
203 KeyFlagsPacket { certify_keys = True
204 , sign_data = True
205 , encrypt_communication = False
206 , encrypt_storage = False
207 , split_key = False
208 , authentication = False
209 , group_key = False
210 }
211 preferredsym = filterOr ispreferedsym subs $
212 PreferredSymmetricAlgorithmsPacket
213 [ AES256
214 , AES192
215 , AES128
216 , CAST5
217 , TripleDES
218 ]
219 preferredhash = filterOr ispreferedhash subs $
220 PreferredHashAlgorithmsPacket
221 [ SHA256
222 , SHA1
223 , SHA384
224 , SHA512
225 , SHA224
226 ]
227 preferredcomp = filterOr ispreferedcomp subs $
228 PreferredCompressionAlgorithmsPacket
229 [ ZLIB
230 , BZip2
231 , ZIP
232 ]
233 features = filterOr isfeatures subs $
234 FeaturesPacket { supports_mdc = True
235 }
236
237 filterOr pred xs def = if null rs then [def] else rs where rs=filter pred xs
238
239 isflags (KeyFlagsPacket {}) = True
240 isflags _ = False
241 ispreferedsym (PreferredSymmetricAlgorithmsPacket {}) = True
242 ispreferedsym _ = False
243 ispreferedhash (PreferredHashAlgorithmsPacket {}) = True
244 ispreferedhash _ = False
245 ispreferedcomp (PreferredCompressionAlgorithmsPacket {}) = True
246 ispreferedcomp _ = False
247 isfeatures (FeaturesPacket {}) = True
248 isfeatures _ = False
249
250
251matchSpec (KeyGrip grip) (_,KeyData p _ _ _)
252 | matchpr grip (packet p)==grip = True
253 | otherwise = False
254
255matchSpec (KeyTag key tag) (_,KeyData _ sigs _ _) = not . null $ filter match ps
256 where
257 ps = map (packet .fst) sigs
258 match p = isSignaturePacket p
259 && has_tag tag p
260 && has_issuer key p
261 has_issuer key p = isJust $ do
262 issuer <- signature_issuer p
263 guard $ matchpr issuer key == issuer
264 has_tag tag p = tag `elem` mapMaybe usage (hashed_subpackets p)
265 || tag `elem` map usageString (mapMaybe keyflags (hashed_subpackets p))
266
267matchSpec (KeyUidMatch pat) (_,KeyData _ _ uids _) = not $ null us
268 where
269 us = filter (isInfixOf pat) $ Map.keys uids
270
271
272data KeySpec =
273 KeyGrip String
274 | KeyTag Packet String
275 | KeyUidMatch String
276 deriving Show
277
278
279buildKeyDB :: FilePath -> FilePath -> Maybe String -> KeyRingData
280 -> IO ((KeyDB,String),[(FilePath,KikiReportAction)])
281buildKeyDB secring pubring grip0 keyring = do
282 let rings = do
283 (f,(rtyp,ftyp)) <- Map.toList (kFiles keyring)
284 let isring (KeyRingFile {}) = True
285 isring _ = False
286 guard (isring ftyp)
287 resolveInputFile secring pubring f
288 readp n = fmap (n,) (readPacketsFromFile n)
289 readw wk n = fmap (n,) (readPacketsFromWallet wk n)
290 ms <- mapM readp rings
291 let grip = grip0 `mplus` (fingerprint <$> fstkey)
292 where
293 fstkey = listToMaybe $ mapMaybe isSecringKey ms
294 where isSecringKey (fn,Message ps)
295 | fn==secring = listToMaybe ps
296 isSecringKey _ = Nothing
297 wk = listToMaybe $ do
298 fp <- maybeToList grip
299 elm <- Map.toList db0
300 guard $ matchSpec (KeyGrip fp) elm
301 return $ keyPacket (snd elm)
302 db0 = foldl' (uncurry . merge) Map.empty ms
303 db <- return db0 -- todo
304 return ( (db, todo), todo )
305
105runKeyRing :: KeyRingData -> (KeyRingRuntime -> a) -> IO (KikiResult a) 306runKeyRing :: KeyRingData -> (KeyRingRuntime -> a) -> IO (KikiResult a)
106runKeyRing keyring op = do 307runKeyRing keyring op = do
107 (homedir,secring,pubring,grip0) <- getHomeDir (homeSpec keyring) 308 (homedir,secring,pubring,grip0) <- getHomeDir (homeSpec keyring)
@@ -117,7 +318,7 @@ runKeyRing keyring op = do
117 ret = if null failed then KikiSuccess () else FailedToLock failed 318 ret = if null failed then KikiSuccess () else FailedToLock failed
118 ret <- case functorToEither ret of 319 ret <- case functorToEither ret of
119 Right {} -> do 320 Right {} -> do
120 report <- todo -- build db 321 ((db,grip), report1) <- buildKeyDB secring pubring grip0 keyring -- build db
121 322
122 a <- return $ op KeyRingRuntime 323 a <- return $ op KeyRingRuntime
123 { rtPubring = pubring 324 { rtPubring = pubring
@@ -125,10 +326,11 @@ runKeyRing keyring op = do
125 , rtRings = [] -- todo secring:pubring:keyringFiles keyring 326 , rtRings = [] -- todo secring:pubring:keyringFiles keyring
126 , rtWallets = [] -- todo walletFiles keyring 327 , rtWallets = [] -- todo walletFiles keyring
127 , rtGrip = grip0 328 , rtGrip = grip0
329 , rtKeyDB = db
128 } 330 }
129 report <- todo report -- write files 331 report2 <- todo -- write files
130 332
131 return $ KikiResult (KikiSuccess a) report 333 return $ KikiResult (KikiSuccess a) (report1 ++ report2)
132 Left err -> return $ KikiResult err [] 334 Left err -> return $ KikiResult err []
133 335
134 forM_ lked $ \(Just lk, fname) -> do dotlock_release lk 336 forM_ lked $ \(Just lk, fname) -> do dotlock_release lk
@@ -196,6 +398,97 @@ isUserID _ = False
196isTrust (TrustPacket {}) = True 398isTrust (TrustPacket {}) = True
197isTrust _ = False 399isTrust _ = False
198 400
401slurpWIPKeys :: System.Posix.Types.EpochTime -> L.ByteString -> ( [(Word8,Packet)], [L.ByteString])
402slurpWIPKeys stamp "" = ([],[])
403slurpWIPKeys stamp cs =
404 let (b58,xs) = Char8.span (\x -> elem x base58chars) cs
405 mb = decode_btc_key stamp (Char8.unpack b58)
406 in if L.null b58
407 then let (ys,xs') = Char8.break (\x -> elem x base58chars) cs
408 (ks,js) = slurpWIPKeys stamp xs'
409 in (ks,ys:js)
410 else let (ks,js) = slurpWIPKeys stamp xs
411 in maybe (ks,b58:js) (\(net,Message [k])->((net,k):ks,js)) mb
412
413
414decode_btc_key timestamp str = do
415 (network_id,us) <- base58_decode str
416 return . (network_id,) $ Message $ do
417 let d = foldl' (\a b->a*256+b) 0 (map fromIntegral us :: [Integer])
418 {-
419 xy = secp256k1_G `pmul` d
420 x = getx xy
421 y = gety xy
422 -- y² = x³ + 7 (mod p)
423 y' = sqrtModP' (applyCurve secp256k1_curve x) (getp secp256k1_curve)
424 y'' = sqrtModPList (applyCurve secp256k1_curve x) (getp secp256k1_curve)
425 -}
426 secp256k1 = ECC.getCurveByName ECC.SEC_p256k1
427 ECC.Point x y = ECC.ecc_g $ ECC.common_curve secp256k1
428 -- pub = cannonical_eckey x y
429 -- hash = S.cons network_id . RIPEMD160.hash . SHA256.hash . S.pack $ pub
430 -- address = base58_encode hash
431 -- pubstr = concatMap (printf "%02x") $ pub
432 -- _ = pubstr :: String
433 return $ {- trace (unlines ["pub="++show pubstr
434 ,"add="++show address
435 ,"y ="++show y
436 ,"y' ="++show y'
437 ,"y''="++show y'']) -}
438 SecretKeyPacket
439 { version = 4
440 , timestamp = toEnum (fromEnum timestamp)
441 , key_algorithm = ECDSA
442 , key = [ -- public fields...
443 ('c',MPI secp256k1_id) -- secp256k1 (bitcoin curve)
444 ,('l',MPI 256)
445 ,('x',MPI x)
446 ,('y',MPI y)
447 -- secret fields
448 ,('d',MPI d)
449 ]
450 , s2k_useage = 0
451 , s2k = S2K 100 ""
452 , symmetric_algorithm = Unencrypted
453 , encrypted_data = ""
454 , is_subkey = True
455 }
456
457readPacketsFromWallet ::
458 Maybe Packet
459 -> FilePath
460 -> IO [(Packet,Packet,(Packet,Map.Map FilePath Packet))]
461readPacketsFromWallet wk fname = do
462 timestamp <- handleIO_ (error $ fname++": modificaiton time?") $
463 modificationTime <$> getFileStatus fname
464 input <- L.readFile fname
465 let (ks,_) = slurpWIPKeys timestamp input
466 when (not (null ks)) $ do
467 -- decrypt wk
468 -- create sigs
469 -- return key/sig pairs
470 return ()
471 return $ do
472 wk <- maybeToList wk
473 guard (not $ null ks)
474 let prep (tagbyte,k) = (wk,k,(k,Map.singleton tag wk))
475 where tag = CryptoCoins.nameFromSecretByte tagbyte
476 (wk,MarkerPacket,(MarkerPacket,Map.empty))
477 :map prep ks
478
479readPacketsFromFile :: FilePath -> IO Message
480readPacketsFromFile fname = do
481 -- warn $ fname ++ ": reading..."
482 input <- L.readFile fname
483#if MIN_VERSION_binary(0,6,4)
484 return $
485 case decodeOrFail input of
486 Right (_,_,msg ) -> msg
487 Left (_,_,_) -> trace (fname++": read fail") $ Message []
488#else
489 return $ decode input
490#endif
491
199 492
200data OriginFlags = OriginFlags { 493data OriginFlags = OriginFlags {
201 originallyPublic :: Bool, 494 originallyPublic :: Bool,
diff --git a/kiki.hs b/kiki.hs
index 365562b..d7ea9c7 100644
--- a/kiki.hs
+++ b/kiki.hs
@@ -347,13 +347,6 @@ isPublicMaster _ = False
347 347
348now = floor <$> Data.Time.Clock.POSIX.getPOSIXTime 348now = floor <$> Data.Time.Clock.POSIX.getPOSIXTime
349 349
350usage (NotationDataPacket
351 { human_readable = True
352 , notation_name = "usage@"
353 , notation_value = u
354 }) = Just u
355usage _ = Nothing
356
357verifyBindings keys nonkeys = (top ++ filter isSubkeySignature embedded,othersigs) 350verifyBindings keys nonkeys = (top ++ filter isSubkeySignature embedded,othersigs)
358 where 351 where
359 verified = do 352 verified = do
@@ -380,10 +373,6 @@ grip k = drop 32 $ fingerprint k
380 373
381smallpr k = drop 24 $ fingerprint k 374smallpr k = drop 24 $ fingerprint k
382 375
383-- matchpr computes the fingerprint of the given key truncated to
384-- be the same lenght as the given fingerprint for comparison.
385matchpr fp k = reverse $ zipWith const (reverse (fingerprint k)) fp
386
387 376
388disjoint_fp ks = {- concatMap group2 $ -} transpose grouped 377disjoint_fp ks = {- concatMap group2 $ -} transpose grouped
389 where 378 where
@@ -587,58 +576,6 @@ listKeysFiltered grips pkts = do
587 "master-key " ++ fingerprint top ++ "\n" ++ uid ++" ...\n" ++ subkeys ++ "\n" 576 "master-key " ++ fingerprint top ++ "\n" ++ uid ++" ...\n" ++ subkeys ++ "\n"
588 577
589 578
590data PGPKeyFlags =
591 Special
592 | Vouch -- Signkey
593 | Sign
594 | VouchSign
595 | Communication
596 | VouchCommunication
597 | SignCommunication
598 | VouchSignCommunication
599 | Storage
600 | VouchStorage
601 | SignStorage
602 | VouchSignStorage
603 | Encrypt
604 | VouchEncrypt
605 | SignEncrypt
606 | VouchSignEncrypt
607 deriving (Eq,Show,Read,Enum)
608
609usageString flgs =
610 case flgs of
611 Special -> "special"
612 Vouch -> "vouch" -- signkey
613 Sign -> "sign"
614 VouchSign -> "vouch-sign"
615 Communication -> "communication"
616 VouchCommunication -> "vouch-communication"
617 SignCommunication -> "sign-communication"
618 VouchSignCommunication -> "vouch-sign-communication"
619 Storage -> "storage"
620 VouchStorage -> "vouch-storage"
621 SignStorage -> "sign-storage"
622 VouchSignStorage -> "vouch-sign-storage"
623 Encrypt -> "encrypt"
624 VouchEncrypt -> "vouch-encrypt"
625 SignEncrypt -> "sign-encrypt"
626 VouchSignEncrypt -> "vouch-sign-encrypt"
627
628
629keyflags flgs@(KeyFlagsPacket {}) =
630 Just . toEnum $
631 ( bit 0x1 certify_keys
632 .|. bit 0x2 sign_data
633 .|. bit 0x4 encrypt_communication
634 .|. bit 0x8 encrypt_storage ) :: Maybe PGPKeyFlags
635 -- other flags:
636 -- split_key
637 -- authentication (ssh-client)
638 -- group_key
639 where
640 bit v f = if f flgs then v else 0
641keyflags _ = Nothing
642 579
643 580
644modifyUID (UserIDPacket str) = UserIDPacket str' 581modifyUID (UserIDPacket str) = UserIDPacket str'
@@ -666,53 +603,6 @@ expandPath path [] = []
666 603
667-- type TimeStamp = Word32 604-- type TimeStamp = Word32
668 605
669slurpWIPKeys :: System.Posix.Types.EpochTime -> L.ByteString -> ( [(Word8,Packet)], [L.ByteString])
670slurpWIPKeys stamp "" = ([],[])
671slurpWIPKeys stamp cs =
672 let (b58,xs) = Char8.span (\x -> elem x base58chars) cs
673 mb = decode_btc_key stamp (Char8.unpack b58)
674 in if L.null b58
675 then let (ys,xs') = Char8.break (\x -> elem x base58chars) cs
676 (ks,js) = slurpWIPKeys stamp xs'
677 in (ks,ys:js)
678 else let (ks,js) = slurpWIPKeys stamp xs
679 in maybe (ks,b58:js) (\(net,Message [k])->((net,k):ks,js)) mb
680
681readPacketsFromWallet ::
682 Maybe Packet
683 -> FilePath
684 -> IO [(Packet,Packet,(Packet,Map.Map FilePath Packet))]
685readPacketsFromWallet wk fname = do
686 timestamp <- handleIO_ (error $ fname++": modificaiton time?") $
687 modificationTime <$> getFileStatus fname
688 input <- L.readFile fname
689 let (ks,_) = slurpWIPKeys timestamp input
690 when (not (null ks)) $ do
691 -- decrypt wk
692 -- create sigs
693 -- return key/sig pairs
694 return ()
695 return $ do
696 wk <- maybeToList wk
697 guard (not $ null ks)
698 let prep (tagbyte,k) = (wk,k,(k,Map.singleton tag wk))
699 where tag = CryptoCoins.nameFromSecretByte tagbyte
700 (wk,MarkerPacket,(MarkerPacket,Map.empty))
701 :map prep ks
702
703readPacketsFromFile :: FilePath -> IO Message
704readPacketsFromFile fname = do
705 -- warn $ fname ++ ": reading..."
706 input <- L.readFile fname
707#if MIN_VERSION_binary(0,6,4)
708 return $
709 case decodeOrFail input of
710 Right (_,_,msg ) -> msg
711 Left (_,_,_) -> trace (fname++": read fail") $ Message []
712#else
713 return $ decode input
714#endif
715
716-- | Attempts to lock each file in the list. 606-- | Attempts to lock each file in the list.
717-- Returns a list of locks and a list of filenames 607-- Returns a list of locks and a list of filenames
718-- that could not be locked. 608-- that could not be locked.
@@ -984,12 +874,6 @@ getPassphrase cmd =
984 874
985#define HOMEOPTION (def &= explicit &= name "homedir" &= typDir ) 875#define HOMEOPTION (def &= explicit &= name "homedir" &= typDir )
986 876
987data KeySpec =
988 KeyGrip String
989 | KeyTag Packet String
990 | KeyUidMatch String
991 deriving Show
992
993is40digitHex xs = ys == xs && length ys==40 877is40digitHex xs = ys == xs && length ys==40
994 where 878 where
995 ys = filter ishex xs 879 ys = filter ishex xs
@@ -1062,7 +946,6 @@ sortByHint fname f = sortBy (comparing gethint)
1062 defnum = -1 946 defnum = -1
1063 947
1064keyMappedPacket (KeyData k _ _ _) = k 948keyMappedPacket (KeyData k _ _ _) = k
1065keyPacket (KeyData k _ _ _) = packet k
1066 949
1067writeOutKeyrings :: Map.Map FilePath t -> KeyDB -> IO () 950writeOutKeyrings :: Map.Map FilePath t -> KeyDB -> IO ()
1068writeOutKeyrings lkmap db = do 951writeOutKeyrings lkmap db = do
@@ -1417,34 +1300,6 @@ secp256k1_G = ECPa secp256k1_curve
1417 -} 1300 -}
1418-} 1301-}
1419 1302
1420base58chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
1421
1422base58digits :: [Char] -> Maybe [Int]
1423base58digits str = sequence mbs
1424 where
1425 mbs = map (flip elemIndex base58chars) str
1426
1427-- 5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ
1428base58_decode :: [Char] -> Maybe (Word8,[Word8])
1429base58_decode str = do
1430 ds <- base58digits str
1431 let n = foldl' (\a b-> a*58 + b) 0 $ ( map fromIntegral ds :: [Integer] )
1432 rbytes = unfoldr getbyte n
1433 getbyte d = do
1434 guard (d/=0)
1435 let (q,b) = d `divMod` 256
1436 return (fromIntegral b,q)
1437
1438 let (rcksum,rpayload) = splitAt 4 $ rbytes
1439 a_payload = reverse rpayload
1440 hash_result = S.take 4 . SHA256.hash . SHA256.hash . S.pack $ a_payload
1441 expected_hash = S.pack $ reverse rcksum
1442 (network_id,payload) = splitAt 1 a_payload
1443
1444 network_id <- listToMaybe network_id
1445 guard (hash_result==expected_hash)
1446 return (network_id,payload)
1447
1448walletImportFormat idbyte k = secret_base58_foo 1303walletImportFormat idbyte k = secret_base58_foo
1449 where 1304 where
1450 -- isSecret (SecretKeyPacket {}) = True 1305 -- isSecret (SecretKeyPacket {}) = True
@@ -1530,48 +1385,6 @@ bitcoinAddress network_id k = address
1530-- 0x4e*128+0x3d 10045 1385-- 0x4e*128+0x3d 10045
1531-- 1.2.840.10045.3.1.7 --> NIST P-256 1386-- 1.2.840.10045.3.1.7 --> NIST P-256
1532-- 1387--
1533decode_btc_key timestamp str = do
1534 (network_id,us) <- base58_decode str
1535 return . (network_id,) $ Message $ do
1536 let d = foldl' (\a b->a*256+b) 0 (map fromIntegral us :: [Integer])
1537 {-
1538 xy = secp256k1_G `pmul` d
1539 x = getx xy
1540 y = gety xy
1541 -- y² = x³ + 7 (mod p)
1542 y' = sqrtModP' (applyCurve secp256k1_curve x) (getp secp256k1_curve)
1543 y'' = sqrtModPList (applyCurve secp256k1_curve x) (getp secp256k1_curve)
1544 -}
1545 secp256k1 = ECC.getCurveByName ECC.SEC_p256k1
1546 ECC.Point x y = ECC.ecc_g $ ECC.common_curve secp256k1
1547 -- pub = cannonical_eckey x y
1548 -- hash = S.cons network_id . RIPEMD160.hash . SHA256.hash . S.pack $ pub
1549 -- address = base58_encode hash
1550 -- pubstr = concatMap (printf "%02x") $ pub
1551 -- _ = pubstr :: String
1552 return $ {- trace (unlines ["pub="++show pubstr
1553 ,"add="++show address
1554 ,"y ="++show y
1555 ,"y' ="++show y'
1556 ,"y''="++show y'']) -}
1557 SecretKeyPacket
1558 { version = 4
1559 , timestamp = toEnum (fromEnum timestamp)
1560 , key_algorithm = ECDSA
1561 , key = [ -- public fields...
1562 ('c',MPI secp256k1_id) -- secp256k1 (bitcoin curve)
1563 ,('l',MPI 256)
1564 ,('x',MPI x)
1565 ,('y',MPI y)
1566 -- secret fields
1567 ,('d',MPI d)
1568 ]
1569 , s2k_useage = 0
1570 , s2k = S2K 100 ""
1571 , symmetric_algorithm = Unencrypted
1572 , encrypted_data = ""
1573 , is_subkey = True
1574 }
1575 1388
1576doBTCImport doDecrypt db (ms,subspec,content) = do 1389doBTCImport doDecrypt db (ms,subspec,content) = do
1577 let fetchkey = do 1390 let fetchkey = do
@@ -2494,26 +2307,6 @@ selectKey0 wantPublic (spec,mtag) db = do
2494 zs = snd $ seek_key subspec ys1 2307 zs = snd $ seek_key subspec ys1
2495 listToMaybe zs 2308 listToMaybe zs
2496 2309
2497matchSpec (KeyGrip grip) (_,KeyData p _ _ _)
2498 | matchpr grip (packet p)==grip = True
2499 | otherwise = False
2500
2501matchSpec (KeyTag key tag) (_,KeyData _ sigs _ _) = not . null $ filter match ps
2502 where
2503 ps = map (packet .fst) sigs
2504 match p = isSignaturePacket p
2505 && has_tag tag p
2506 && has_issuer key p
2507 has_issuer key p = isJust $ do
2508 issuer <- signature_issuer p
2509 guard $ matchpr issuer key == issuer
2510 has_tag tag p = tag `elem` mapMaybe usage (hashed_subpackets p)
2511 || tag `elem` map usageString (mapMaybe keyflags (hashed_subpackets p))
2512
2513matchSpec (KeyUidMatch pat) (_,KeyData _ _ uids _) = not $ null us
2514 where
2515 us = filter (isInfixOf pat) $ Map.keys uids
2516
2517seek_key :: KeySpec -> [Packet] -> ([Packet],[Packet]) 2310seek_key :: KeySpec -> [Packet] -> ([Packet],[Packet])
2518seek_key (KeyGrip grip) sec = (pre, subs) 2311seek_key (KeyGrip grip) sec = (pre, subs)
2519 where 2312 where
@@ -2614,68 +2407,3 @@ sigpackets typ hashed unhashed = return $
2614 0 -- Word16 -- Left 16 bits of the signed hash value 2407 0 -- Word16 -- Left 16 bits of the signed hash value
2615 [] -- [MPI] 2408 [] -- [MPI]
2616 2409
2617keyFlags wkun uids = keyFlags0 wkun (filter isSignaturePacket uids)
2618 {-
2619 where
2620 vs = map (verify (Message [wkun])) (signatures (Message (wkun:uids)))
2621 ws = map signatures_over vs
2622 xs = filter null ws
2623 -}
2624
2625keyFlags0 wkun uidsigs = concat
2626 [ keyflags
2627 , preferredsym
2628 , preferredhash
2629 , preferredcomp
2630 , features ]
2631
2632 where
2633 subs = concatMap hashed_subpackets uidsigs
2634 keyflags = filterOr isflags subs $
2635 KeyFlagsPacket { certify_keys = True
2636 , sign_data = True
2637 , encrypt_communication = False
2638 , encrypt_storage = False
2639 , split_key = False
2640 , authentication = False
2641 , group_key = False
2642 }
2643 preferredsym = filterOr ispreferedsym subs $
2644 PreferredSymmetricAlgorithmsPacket
2645 [ AES256
2646 , AES192
2647 , AES128
2648 , CAST5
2649 , TripleDES
2650 ]
2651 preferredhash = filterOr ispreferedhash subs $
2652 PreferredHashAlgorithmsPacket
2653 [ SHA256
2654 , SHA1
2655 , SHA384
2656 , SHA512
2657 , SHA224
2658 ]
2659 preferredcomp = filterOr ispreferedcomp subs $
2660 PreferredCompressionAlgorithmsPacket
2661 [ ZLIB
2662 , BZip2
2663 , ZIP
2664 ]
2665 features = filterOr isfeatures subs $
2666 FeaturesPacket { supports_mdc = True
2667 }
2668
2669 filterOr pred xs def = if null rs then [def] else rs where rs=filter pred xs
2670
2671 isflags (KeyFlagsPacket {}) = True
2672 isflags _ = False
2673 ispreferedsym (PreferredSymmetricAlgorithmsPacket {}) = True
2674 ispreferedsym _ = False
2675 ispreferedhash (PreferredHashAlgorithmsPacket {}) = True
2676 ispreferedhash _ = False
2677 ispreferedcomp (PreferredCompressionAlgorithmsPacket {}) = True
2678 ispreferedcomp _ = False
2679 isfeatures (FeaturesPacket {}) = True
2680 isfeatures _ = False
2681