diff options
author | joe <joe@jerkface.net> | 2014-04-22 19:17:52 -0400 |
---|---|---|
committer | joe <joe@jerkface.net> | 2014-04-22 19:17:52 -0400 |
commit | bdfc90edae040cefccbe1018f1506c445608e460 (patch) | |
tree | 319b7d2fa8c7b27b1209ee429dd9d5ff9b9b8dd4 /kiki.hs | |
parent | 1257ddd6813fc75df11631d653a97eb45035188e (diff) |
more cleanup of module kiki.hs
Diffstat (limited to 'kiki.hs')
-rw-r--r-- | kiki.hs | 300 |
1 files changed, 69 insertions, 231 deletions
@@ -6,81 +6,49 @@ | |||
6 | {-# LANGUAGE FlexibleInstances #-} | 6 | {-# LANGUAGE FlexibleInstances #-} |
7 | {-# LANGUAGE DeriveDataTypeable #-} | 7 | {-# LANGUAGE DeriveDataTypeable #-} |
8 | {-# LANGUAGE CPP #-} | 8 | {-# LANGUAGE CPP #-} |
9 | module Main where | 9 | module Main ( main ) where |
10 | 10 | ||
11 | import Data.IORef | 11 | import Control.Applicative |
12 | import Data.Binary | ||
13 | import Data.OpenPGP as OpenPGP | ||
14 | import qualified Data.ByteString.Lazy as L | ||
15 | import qualified Data.ByteString.Lazy.Char8 as Char8 | ||
16 | import qualified Data.ByteString as S | ||
17 | import Control.Monad | 12 | import Control.Monad |
18 | -- import qualified Text.Show.Pretty as PP | 13 | import Data.ASN1.BinaryEncoding |
19 | -- import Text.PrettyPrint as PP hiding ((<>)) | 14 | import Data.ASN1.Encoding |
15 | import Data.ASN1.Types | ||
16 | import Data.Binary | ||
17 | import Data.Bits | ||
18 | import Data.Char | ||
19 | import Data.IORef | ||
20 | import Data.List | 20 | import Data.List |
21 | import Data.OpenPGP.Util (verify,fingerprint) | ||
22 | import Data.Ord | ||
23 | import Data.Maybe | 21 | import Data.Maybe |
24 | import Data.Bits | 22 | import Data.OpenPGP |
25 | import qualified Data.Text as T | 23 | import Data.Ord |
26 | import Data.Text.Encoding | 24 | import Data.Text.Encoding |
27 | import qualified Codec.Binary.Base64 as Base64 | ||
28 | import qualified Crypto.Hash.SHA256 as SHA256 | ||
29 | import qualified Crypto.Hash.RIPEMD160 as RIPEMD160 | ||
30 | -- import qualified Crypto.Types.PubKey.ECDSA as ECDSA | ||
31 | -- import qualified Crypto.PubKey.ECC.ECDSA as ECDSA | ||
32 | |||
33 | -- import Crypto.Random (newGenIO,SystemRandom) | ||
34 | import Data.ASN1.Types | ||
35 | import Data.ASN1.Encoding | ||
36 | import Data.ASN1.BinaryEncoding | ||
37 | import Control.Applicative | ||
38 | import System.Environment | 25 | import System.Environment |
39 | import System.Exit | 26 | import System.Exit |
40 | import System.IO (hPutStrLn,stderr) | 27 | import System.IO (hPutStrLn,stderr) |
41 | import Data.Char | 28 | import qualified Codec.Binary.Base64 as Base64 |
42 | import Control.Arrow (first,second) | 29 | import qualified Crypto.Hash.RIPEMD160 as RIPEMD160 |
43 | -- import Data.Traversable hiding (mapM,forM,sequence) | 30 | import qualified Crypto.Hash.SHA256 as SHA256 |
44 | -- import qualified Data.Traversable as Traversable (mapM,forM,sequence) | 31 | import qualified Data.ByteString as S |
45 | -- import System.Console.CmdArgs | 32 | import qualified Data.ByteString.Lazy as L |
46 | -- import System.Posix.Time | 33 | import qualified Data.ByteString.Lazy.Char8 as Char8 |
47 | -- import Data.X509 | ||
48 | import qualified Data.Map as Map | 34 | import qualified Data.Map as Map |
49 | import DotLock | 35 | import qualified Data.Text as T |
50 | -- import Codec.Crypto.ECC.Base -- hecc package | 36 | import Control.Arrow (first,second) |
51 | -- import Text.Printf | ||
52 | import qualified CryptoCoins | ||
53 | import LengthPrefixedBE | ||
54 | import Data.Binary.Put (putWord32be,runPut,putByteString) | ||
55 | import Data.Binary.Get (runGet) | 37 | import Data.Binary.Get (runGet) |
38 | import Data.Binary.Put (putWord32be,runPut,putByteString) | ||
56 | 39 | ||
40 | import DotLock | ||
41 | import LengthPrefixedBE | ||
57 | import KeyRing | 42 | import KeyRing |
58 | import Base58 | 43 | import Base58 |
44 | import qualified CryptoCoins | ||
45 | import Data.OpenPGP.Util (verify,fingerprint) | ||
59 | 46 | ||
60 | -- {-# ANN module ("HLint: ignore Eta reduce"::String) #-} | 47 | -- {-# ANN module ("HLint: ignore Eta reduce"::String) #-} |
61 | -- {-# ANN module ("HLint: ignore Use camelCase"::String) #-} | 48 | -- {-# ANN module ("HLint: ignore Use camelCase"::String) #-} |
62 | 49 | ||
63 | -- instance Default S.ByteString where def = S.empty | ||
64 | |||
65 | warn str = hPutStrLn stderr str | 50 | warn str = hPutStrLn stderr str |
66 | 51 | ||
67 | |||
68 | |||
69 | {- | ||
70 | RSAPrivateKey ::= SEQUENCE { | ||
71 | version Version, | ||
72 | modulus INTEGER, -- n | ||
73 | publicExponent INTEGER, -- e | ||
74 | privateExponent INTEGER, -- d | ||
75 | prime1 INTEGER, -- p | ||
76 | prime2 INTEGER, -- q | ||
77 | exponent1 INTEGER, -- d mod (p1) -- ?? d mod (p-1) | ||
78 | exponent2 INTEGER, -- d mod (q-1) | ||
79 | coefficient INTEGER, -- (inverse of q) mod p | ||
80 | otherPrimeInfos OtherPrimeInfos OPTIONAL | ||
81 | } | ||
82 | -} | ||
83 | |||
84 | sshrsa :: Integer -> Integer -> Char8.ByteString | 52 | sshrsa :: Integer -> Integer -> Char8.ByteString |
85 | sshrsa e n = runPut $ do | 53 | sshrsa e n = runPut $ do |
86 | putWord32be 7 | 54 | putWord32be 7 |
@@ -98,18 +66,6 @@ decode_sshrsa bs = do | |||
98 | return $ RSAKey (MPI n) (MPI e) | 66 | return $ RSAKey (MPI n) (MPI e) |
99 | return rsakey | 67 | return rsakey |
100 | 68 | ||
101 | |||
102 | |||
103 | {- | ||
104 | getPackets :: IO [Packet] | ||
105 | getPackets = do | ||
106 | input <- L.getContents | ||
107 | case decodeOrFail input of | ||
108 | Right (_,_,Message pkts) -> return pkts | ||
109 | Left (_,_,_) -> return [] | ||
110 | -} | ||
111 | |||
112 | |||
113 | isCertificationSig (CertificationSignature {}) = True | 69 | isCertificationSig (CertificationSignature {}) = True |
114 | isCertificationSig _ = True | 70 | isCertificationSig _ = True |
115 | 71 | ||
@@ -214,12 +170,6 @@ fpmatch grip key = | |||
214 | 170 | ||
215 | listKeys pkts = listKeysFiltered [] pkts | 171 | listKeys pkts = listKeysFiltered [] pkts |
216 | 172 | ||
217 | {- | ||
218 | ecc_curve k = printf "%x" num :: String | ||
219 | where unmpi (MPI num) = num | ||
220 | num = maybe 0 unmpi $ lookup 'c' (key k) | ||
221 | -} | ||
222 | |||
223 | listKeysFiltered grips pkts = do | 173 | listKeysFiltered grips pkts = do |
224 | let (certs,bs) = getBindings pkts | 174 | let (certs,bs) = getBindings pkts |
225 | as = accBindings bs | 175 | as = accBindings bs |
@@ -304,9 +254,9 @@ listKeysFiltered grips pkts = do | |||
304 | "master-key " ++ fingerprint top ++ "\n" ++ uid ++" ...\n" ++ subkeys ++ "\n" | 254 | "master-key " ++ fingerprint top ++ "\n" ++ uid ++" ...\n" ++ subkeys ++ "\n" |
305 | 255 | ||
306 | 256 | ||
307 | |||
308 | |||
309 | {- | 257 | {- |
258 | - modify a UID to test the verify function properly | ||
259 | - fails | ||
310 | modifyUID (UserIDPacket str) = UserIDPacket str' | 260 | modifyUID (UserIDPacket str) = UserIDPacket str' |
311 | where | 261 | where |
312 | (fstname,rst) = break (==' ') str | 262 | (fstname,rst) = break (==' ') str |
@@ -316,11 +266,6 @@ modifyUID (UserIDPacket str) = UserIDPacket str' | |||
316 | modifyUID other = other | 266 | modifyUID other = other |
317 | -} | 267 | -} |
318 | 268 | ||
319 | |||
320 | |||
321 | -- type TimeStamp = Word32 | ||
322 | |||
323 | |||
324 | readPublicKey :: Char8.ByteString -> RSAPublicKey | 269 | readPublicKey :: Char8.ByteString -> RSAPublicKey |
325 | readPublicKey bs = fromMaybe er $ do | 270 | readPublicKey bs = fromMaybe er $ do |
326 | let (pre,bs1) = Char8.splitAt 7 bs | 271 | let (pre,bs1) = Char8.splitAt 7 bs |
@@ -333,18 +278,8 @@ readPublicKey bs = fromMaybe er $ do | |||
333 | where | 278 | where |
334 | er = error "Unsupported key format" | 279 | er = error "Unsupported key format" |
335 | 280 | ||
336 | {- | 281 | -- | Returns the given list with its last element modified. |
337 | getPassphrase cmd = | 282 | toLast :: (x -> x) -> [x] -> [x] |
338 | case passphrase_fd cmd of | ||
339 | Just fd -> do pwh <- fdToHandle (toEnum fd) | ||
340 | fmap trimCR $ S.hGetContents pwh | ||
341 | Nothing -> return "" | ||
342 | -} | ||
343 | |||
344 | |||
345 | #define HOMEOPTION (def &= explicit &= name "homedir" &= typDir ) | ||
346 | |||
347 | |||
348 | toLast f [] = [] | 283 | toLast f [] = [] |
349 | toLast f [x] = [f x] | 284 | toLast f [x] = [f x] |
350 | toLast f (x:xs) = x : toLast f xs | 285 | toLast f (x:xs) = x : toLast f xs |
@@ -417,41 +352,6 @@ show_wip keyspec wkgrip db = do | |||
417 | let nwb = maybe 0x80 CryptoCoins.secretByteFromName $ snd s | 352 | let nwb = maybe 0x80 CryptoCoins.secretByteFromName $ snd s |
418 | putStrLn $ walletImportFormat nwb k | 353 | putStrLn $ walletImportFormat nwb k |
419 | 354 | ||
420 | |||
421 | {- | ||
422 | applyCurve curve x = x*x*x + x*a + b where (a,b)=(geta curve,getb curve) | ||
423 | |||
424 | secp256k1_oid = [1,3,132,0,10] | ||
425 | secp256k1_curve = ECi l a b p r | ||
426 | where | ||
427 | -- y² = x³ + 7 (mod p) | ||
428 | p = 0x0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F | ||
429 | a = 0 | ||
430 | b = 7 | ||
431 | -- group order (also order of base point G) | ||
432 | r = n | ||
433 | n = 0x0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 | ||
434 | -- cofactor | ||
435 | h = 1 | ||
436 | -- bit length | ||
437 | l = 256 | ||
438 | |||
439 | secp256k1_G = ECPa secp256k1_curve | ||
440 | 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798 | ||
441 | 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8 | ||
442 | {- | ||
443 | The base point G in compressed form is: | ||
444 | |||
445 | G = 02 79BE667E F9DCBBAC 55A06295 CE870B07 029BFCDB 2DCE28D9 59F2815B 16F81798 | ||
446 | |||
447 | and in uncompressed form is: | ||
448 | |||
449 | G = 04 79BE667E F9DCBBAC 55A06295 CE870B07 029BFCDB 2DCE28D9 59F2815B 16F81798 | ||
450 | 483ADA77 26A3C465 5DA4FBFC 0E1108A8 FD17B448 A6855419 9C47D08F FB10D4B8 | ||
451 | -} | ||
452 | -} | ||
453 | |||
454 | |||
455 | cannonical_eckey x y = 0x4:pad32(numToBytes x) ++ pad32(numToBytes y) :: [Word8] | 355 | cannonical_eckey x y = 0x4:pad32(numToBytes x) ++ pad32(numToBytes y) :: [Word8] |
456 | where | 356 | where |
457 | numToBytes n = reverse $ unfoldr getbyte n | 357 | numToBytes n = reverse $ unfoldr getbyte n |
@@ -473,22 +373,6 @@ bitcoinAddress network_id k = address | |||
473 | hash = S.cons network_id . RIPEMD160.hash . SHA256.hash . S.pack $ pub | 373 | hash = S.cons network_id . RIPEMD160.hash . SHA256.hash . S.pack $ pub |
474 | address = base58_encode hash | 374 | address = base58_encode hash |
475 | 375 | ||
476 | -- gpg supported ECDSA curve: 2A8648CE3D030107 | ||
477 | -- 2A 86 48 CE 3D 03 01 07 | ||
478 | -- 1,2,134,72,206,61,3,1,7 | ||
479 | -- 6*128+0x48 840 | ||
480 | -- 0x4e*128+0x3d 10045 | ||
481 | -- 1.2.840.10045.3.1.7 --> NIST P-256 | ||
482 | -- | ||
483 | |||
484 | |||
485 | {- | ||
486 | onionName :: KeyData -> (SockAddr,L.ByteString) | ||
487 | onionName kd = (addr,name) | ||
488 | where | ||
489 | (addr,(name:_,_)) = getHostnames kd | ||
490 | -} | ||
491 | |||
492 | whoseKey :: RSAPublicKey -> KeyDB -> [KeyData] | 376 | whoseKey :: RSAPublicKey -> KeyDB -> [KeyData] |
493 | whoseKey rsakey db = filter matchkey (Map.elems db) | 377 | whoseKey rsakey db = filter matchkey (Map.elems db) |
494 | where | 378 | where |
@@ -510,6 +394,12 @@ whoseKey rsakey db = filter matchkey (Map.elems db) | |||
510 | s2 <- signatures . Message $ [k,sub,subsig] | 394 | s2 <- signatures . Message $ [k,sub,subsig] |
511 | signatures_over $ verify (Message [sub]) s2 | 395 | signatures_over $ verify (Message [sub]) s2 |
512 | 396 | ||
397 | isSameKey a b = sort (key apub) == sort (key bpub) | ||
398 | where | ||
399 | apub = secretToPublic a | ||
400 | bpub = secretToPublic b | ||
401 | |||
402 | |||
513 | 403 | ||
514 | kiki_usage = putStr . unlines $ | 404 | kiki_usage = putStr . unlines $ |
515 | ["kiki - a pgp key editing utility" | 405 | ["kiki - a pgp key editing utility" |
@@ -599,22 +489,40 @@ kiki_usage = putStr . unlines $ | |||
599 | ," --help Shows this help screen." | 489 | ," --help Shows this help screen." |
600 | ] | 490 | ] |
601 | 491 | ||
492 | doAutosign rt kd@(KeyData k ksigs umap submap) = ops | ||
493 | where | ||
494 | ops = map (\u -> InducerSignature u []) us | ||
495 | us = filter torStyle $ Map.keys umap | ||
496 | torStyle str = and [ uid_topdomain parsed == "onion" | ||
497 | , uid_realname parsed `elem` ["","Anonymous"] | ||
498 | , uid_user parsed == "root" | ||
499 | , fmap (match . fst) (lookup (packet k) torbindings) | ||
500 | == Just True ] | ||
501 | where parsed = parseUID str | ||
502 | match = (==subdom) . take (fromIntegral len) | ||
503 | subdom0 = L.fromChunks [encodeUtf8 (uid_subdomain parsed)] | ||
504 | subdom = Char8.unpack subdom0 | ||
505 | len = T.length (uid_subdomain parsed) | ||
506 | torbindings = getTorKeys (map packet $ flattenTop "" True kd) | ||
507 | getTorKeys pub = do | ||
508 | xs <- groupBindings pub | ||
509 | (_,(top,sub),us,_,_) <- xs | ||
510 | guard ("tor" `elem` us) | ||
511 | let torhash = fromMaybe "" $ derToBase32 <$> derRSA sub | ||
512 | return (top,(torhash,sub)) | ||
513 | |||
514 | groupBindings pub = gs | ||
515 | where (_,bindings) = getBindings pub | ||
516 | bindings' = accBindings bindings | ||
517 | code (c,(m,s),_,_,_) = (fingerprint_material m,-c) | ||
518 | ownerkey (_,(a,_),_,_,_) = a | ||
519 | sameMaster (ownerkey->a) (ownerkey->b) | ||
520 | = fingerprint_material a==fingerprint_material b | ||
521 | gs = groupBy sameMaster (sortBy (comparing code) bindings') | ||
522 | |||
523 | |||
602 | main = do | 524 | main = do |
603 | dotlock_init | 525 | dotlock_init |
604 | {- | ||
605 | args <- cmdArgs $ modes | ||
606 | [ Cross_Merge HOMEOPTION | ||
607 | (def &= opt ("passphrase"::String) | ||
608 | &= typ "FD" | ||
609 | &= (help . concat) ["file descriptor from " | ||
610 | ,"which to read passphrase"]) | ||
611 | (def &= args &= typFile) | ||
612 | &= help "Merge multiple secret keyrings to stdout." | ||
613 | ] | ||
614 | &= program "kiki" | ||
615 | &= summary "kiki - a pgp key editing utility" | ||
616 | doCmd args | ||
617 | -} | ||
618 | args_raw <- getArgs | 526 | args_raw <- getArgs |
619 | let (args,trail1) = break (=="--") args_raw | 527 | let (args,trail1) = break (=="--") args_raw |
620 | trail = drop 1 trail1 | 528 | trail = drop 1 trail1 |
@@ -671,20 +579,12 @@ main = do | |||
671 | guard $ take 1 bdmcb == "}" | 579 | guard $ take 1 bdmcb == "}" |
672 | let cmd = (drop 1 . reverse . drop 1) bdmcb | 580 | let cmd = (drop 1 . reverse . drop 1) bdmcb |
673 | Just (spec,file,cmd) | 581 | Just (spec,file,cmd) |
674 | {- | ||
675 | publics = | ||
676 | flip map (fromMaybe [] $ Map.lookup "--public" margs) $ \specfile -> do | ||
677 | let (spec,efile) = break (=='=') specfile | ||
678 | guard $ take 1 efile=="=" | ||
679 | let file= drop 1 efile | ||
680 | Just (spec,file) | ||
681 | -} | ||
682 | keyrings_ = fromMaybe [] $ Map.lookup "--keyrings" margs | 582 | keyrings_ = fromMaybe [] $ Map.lookup "--keyrings" margs |
683 | wallets = fromMaybe [] $ Map.lookup "--wallets" margs | 583 | wallets = fromMaybe [] $ Map.lookup "--wallets" margs |
684 | passphrase_fd = concat <$> Map.lookup "--passphrase-fd" margs | 584 | passphrase_fd = concat <$> Map.lookup "--passphrase-fd" margs |
685 | 585 | ||
686 | when (any isNothing keypairs0) $ do | 586 | when (any isNothing keypairs0) $ do |
687 | warn "syntax error" | 587 | warn "Syntax error in key pair specification" |
688 | exitFailure | 588 | exitFailure |
689 | 589 | ||
690 | input_key <- maybe (return Nothing) | 590 | input_key <- maybe (return Nothing) |
@@ -692,15 +592,7 @@ main = do | |||
692 | $ Map.lookup "--show-whose-key" margs | 592 | $ Map.lookup "--show-whose-key" margs |
693 | 593 | ||
694 | let keypairs = catMaybes keypairs0 | 594 | let keypairs = catMaybes keypairs0 |
695 | 595 | homespec = join . take 1 <$> Map.lookup "--homedir" margs | |
696 | {- | ||
697 | putStrLn $ "wallets = "++show wallets | ||
698 | putStrLn $ "keypairs = "++show keypairs | ||
699 | putStrLn $ "keyrings = "++show keyrings_ | ||
700 | putStrLn $ "publics = "++show publics | ||
701 | -} | ||
702 | |||
703 | let homespec = join . take 1 <$> Map.lookup "--homedir" margs | ||
704 | passfd = fmap (FileDesc . read) passphrase_fd | 596 | passfd = fmap (FileDesc . read) passphrase_fd |
705 | pems = flip map keypairs | 597 | pems = flip map keypairs |
706 | $ \(usage,path,cmd) -> | 598 | $ \(usage,path,cmd) -> |
@@ -750,61 +642,7 @@ main = do | |||
750 | shargs = mapMaybe (\(x:xs) -> (,xs) <$> Map.lookup x shspec) sargs | 642 | shargs = mapMaybe (\(x:xs) -> (,xs) <$> Map.lookup x shspec) sargs |
751 | 643 | ||
752 | forM_ shargs $ \(cmd,args) -> cmd args (rtKeyDB rt) | 644 | forM_ shargs $ \(cmd,args) -> cmd args (rtKeyDB rt) |
753 | e -> putStrLn $ errorString e | 645 | err -> putStrLn $ errorString err |
754 | 646 | ||
755 | forM_ report $ \(fname,act) -> do | 647 | forM_ report $ \(fname,act) -> do |
756 | putStrLn $ fname ++ ": " ++ reportString act | 648 | putStrLn $ fname ++ ": " ++ reportString act |
757 | where | ||
758 | |||
759 | doAutosign rt kd@(KeyData k ksigs umap submap) = ops | ||
760 | where | ||
761 | ops = map (\u -> InducerSignature u []) us | ||
762 | us = filter torStyle $ Map.keys umap | ||
763 | torbindings = getTorKeys (map packet $ flattenTop "" True kd) | ||
764 | torStyle str = and [ uid_topdomain parsed == "onion" | ||
765 | , uid_realname parsed `elem` ["","Anonymous"] | ||
766 | , uid_user parsed == "root" | ||
767 | , fmap (match . fst) (lookup (packet k) torbindings) | ||
768 | == Just True ] | ||
769 | where parsed = parseUID str | ||
770 | match = (==subdom) . take (fromIntegral len) | ||
771 | subdom0 = L.fromChunks [encodeUtf8 (uid_subdomain parsed)] | ||
772 | subdom = Char8.unpack subdom0 | ||
773 | len = T.length (uid_subdomain parsed) | ||
774 | |||
775 | getTorKeys pub = do | ||
776 | xs <- groupBindings pub | ||
777 | (_,(top,sub),us,_,_) <- xs | ||
778 | guard ("tor" `elem` us) | ||
779 | let torhash = fromMaybe "" $ derToBase32 <$> derRSA sub | ||
780 | return (top,(torhash,sub)) | ||
781 | |||
782 | isSameKey a b = sort (key apub) == sort (key bpub) | ||
783 | where | ||
784 | apub = secretToPublic a | ||
785 | bpub = secretToPublic b | ||
786 | |||
787 | |||
788 | |||
789 | groupBindings pub = | ||
790 | let (_,bindings) = getBindings pub | ||
791 | bindings' = accBindings bindings | ||
792 | code (c,(m,s),_,_,_) = (fingerprint_material m,-c) | ||
793 | ownerkey (_,(a,_),_,_,_) = a | ||
794 | sameMaster (ownerkey->a) (ownerkey->b) = fingerprint_material a==fingerprint_material b | ||
795 | -- matchgrip ((code,(top,sub), kind, hashed,claimants):_) | fpmatch grip top = True | ||
796 | -- matchgrip _ = False | ||
797 | gs = {- filter matchgrip $ -} groupBy sameMaster (sortBy (comparing code) bindings') | ||
798 | in gs | ||
799 | |||
800 | |||
801 | |||
802 | {- | ||
803 | makeTorUID g timestamp wkun keyflags topkey torkey = uid:signatures_over sig | ||
804 | where | ||
805 | torhash sub = fromMaybe "" $ derToBase32 <$> derRSA sub | ||
806 | s = "Anonymous <root@" ++ take 16 (torhash torkey) ++ ".onion>" | ||
807 | uid = UserIDPacket s | ||
808 | sig = fst $ torsig g topkey wkun uid timestamp keyflags | ||
809 | -} | ||
810 | |||