packages feed

hOpenPGP (empty) → 0.0.0

raw patch · 86 files changed

+1652/−0 lines, 86 filesdep +HUnitdep +basedep +bytestringsetup-changedbinary-added

Dependencies added: HUnit, base, bytestring, cereal, containers, test-framework, test-framework-hunit

Files

+ Codec/Encryption/OpenPGP/Serialize.hs view
@@ -0,0 +1,823 @@+-- Serialize.hs: OpenPGP (RFC4880) serialization (using cereal)+-- Copyright Ⓒ 2012  Clint Adams+-- This software is released under the terms of the Expat (MIT) license.+-- (See the LICENSE file).++module Codec.Encryption.OpenPGP.Serialize (+    getPackets+  , putPackets+) where++import Control.Applicative ((<$>),(<*>))+import Control.Monad (replicateM, mplus, when)+import Data.Bits ((.&.), (.|.), shiftL, shiftR)+import Data.ByteString (ByteString)+import qualified Data.ByteString as B+import qualified Data.ByteString.Char8 as BC8+import Data.List (mapAccumL)+import Data.Maybe (isJust, fromJust)+import Data.Serialize (Serialize, get, put)+import Data.Serialize.Get (Get, getWord8, getWord16be, getWord32be, getBytes, getByteString, getWord16le, runGet, remaining)+import Data.Serialize.Put (Put, putWord8, putWord16be, putWord32be, putByteString, putWord16le, runPut)+import Data.Set (Set)+import qualified Data.Set as Set+import Data.Word (Word8)++import Codec.Encryption.OpenPGP.Types++instance Serialize SigSubPacket where+    get = getSigSubPacket+    put = putSigSubPacket++-- instance Serialize (Set NotationFlag) where+--     put = putNotationFlagSet++instance Serialize CompressionAlgorithm where+    get = getWord8 >>= return . toFVal+    put = putWord8 . fromFVal++instance Serialize PubKeyAlgorithm where+    get = getWord8 >>= return . toFVal+    put = putWord8 . fromFVal++instance Serialize HashAlgorithm where+    get = getWord8 >>= return . toFVal+    put = putWord8 . fromFVal++instance Serialize SymmetricAlgorithm where+    get = getWord8 >>= return . toFVal+    put = putWord8 . fromFVal++instance Serialize MPI where+    get = getMPI+    put = putMPI++instance Serialize SigType where+    get = getWord8 >>= return . toFVal+    put = putWord8 . fromFVal++instance Serialize UserAttrSubPacket where+    get = getUserAttrSubPacket+    put = putUserAttrSubPacket++instance Serialize S2K where+    get = getS2K+    put = putS2K++getSigSubPacket :: Get SigSubPacket+getSigSubPacket = do+    l <- getSubPacketLength+    (crit, pt) <- getSigSubPacketType+    getSigSubPacket' pt crit l+    where+        getSigSubPacket' :: Word8 -> Bool -> Int -> Get SigSubPacket+        getSigSubPacket' pt crit l+            | pt == 2 = do+                       et <- getWord32be+                       return $ SigCreationTime crit et+            | pt == 3 = do+                       et <- getWord32be+                       return $ SigExpirationTime crit et+            | pt == 4 = do+                       e <- get+                       return $ ExportableCertification crit e+            | pt == 5 = do+                       tl <- getWord8+                       ta <- getWord8+                       return $ TrustSignature crit tl ta+            | pt == 6 = do+                       apdre <- getByteString (l - 2)+                       return $ RegularExpression crit (B.copy apdre)+            | pt == 7 = do+                       r <- get+                       return $ Revocable crit r+            | pt == 9 = do+                       et <- getWord32be+                       return $ KeyExpirationTime crit et+            | pt == 11 = do+                       sa <- replicateM (l - 1) get+                       return $ PreferredSymmetricAlgorithms crit sa+            | pt == 12 = do+                       rclass <- getWord8+                       algid <- get+                       fp <- getByteString 20+                       return $ RevocationKey crit (bsToFFSet . B.singleton $ rclass) algid fp+            | pt == 16 = do+                       keyid <- getByteString (l - 1)+                       return $ Issuer crit keyid+            | pt == 20 = do+                       flags <- getByteString 4+                       nl <- getWord16be+                       vl <- getWord16be+                       nd <- getByteString (fromIntegral nl)+                       nv <- getByteString (fromIntegral vl)+                       return $ NotationData crit (bsToFFSet flags) nd nv+            | pt == 21 = do+                       ha <- replicateM (l - 1) get+                       return $ PreferredHashAlgorithms crit ha+            | pt == 22 = do+                       ca <- replicateM (l - 1) get+                       return $ PreferredCompressionAlgorithms crit ca+            | pt == 23 = do+                       ksps <- getByteString (l - 1)+                       return $ KeyServerPreferences crit (bsToFFSet ksps)+            | pt == 24 = do+                       pks <- getByteString (l - 1)+                       return $ PreferredKeyServer crit pks+            | pt == 25 = do+                       primacy <- get+                       return $ PreferredKeyServer crit primacy+            | pt == 26 = do+                       url <- getByteString (l - 1)+                       return $ PolicyURL crit url+            | pt == 27 = do+                       kfs <- getByteString (l - 1)+                       return $ KeyFlags crit (bsToFFSet kfs)+            | pt == 28 = do+                       uid <- getByteString (l - 1)+                       return $ SignersUserId crit uid+            | pt == 29 = do+                       rcode <- getWord8+                       rreason <- getByteString (l - 2)+                       return $ ReasonForRevocation crit (toFVal rcode) rreason+            | pt == 30 = do+                       fbs <- getByteString (l - 1)+                       return $ Features crit (bsToFFSet fbs)+            | pt == 31 = do+                       pka <- get+                       ha <- get+                       hash <- getByteString (l - 3)+                       return $ SignatureTarget crit pka ha hash+            | pt == 32 = do+                       spb <- getByteString (l - 1)+                       return $ EmbeddedSignature crit spb -- FIXME: should be sigpacket+            | pt > 99 && pt < 111 = do+                       payload <- getByteString (l - 1)+                       return $ UserDefinedSigSub crit pt payload+            | otherwise = do+                       payload <- getByteString (l - 1)+                       return $ OtherSigSub crit pt payload++putSigSubPacket :: SigSubPacket -> Put+putSigSubPacket (SigCreationTime crit et) = do+    putSubPacketLength 5+    putSigSubPacketType crit 2+    putWord32be et+putSigSubPacket (SigExpirationTime crit et) = do+    putSubPacketLength 5+    putSigSubPacketType crit 3+    putWord32be et+putSigSubPacket (ExportableCertification crit e) = do+    putSubPacketLength 2+    putSigSubPacketType crit 4+    put e+putSigSubPacket (TrustSignature crit tl ta) = do+    putSubPacketLength 3+    putSigSubPacketType crit 5+    put tl+    put ta+putSigSubPacket (RegularExpression crit apdre) = do+    putSubPacketLength (2 + B.length apdre)+    putSigSubPacketType crit 6+    putByteString apdre+    putWord8 0+putSigSubPacket (Revocable crit r) = do+    putSubPacketLength 2+    putSigSubPacketType crit 7+    put r+putSigSubPacket (KeyExpirationTime crit et) = do+    putSubPacketLength 5+    putSigSubPacketType crit 9+    putWord32be et+putSigSubPacket (PreferredSymmetricAlgorithms crit ess) = do+    putSubPacketLength (1 + length ess)+    putSigSubPacketType crit 11+    mapM_ put ess+putSigSubPacket (RevocationKey crit rclass algid fp) = do+    putSubPacketLength 23+    putSigSubPacketType crit 12+    putByteString . ffSetToFixedLengthBS 1 $ rclass+    put algid+    putByteString fp -- 20 octets+putSigSubPacket (Issuer crit keyid) = do+    putSubPacketLength 9+    putSigSubPacketType crit 16+    putByteString keyid -- 8 octets+putSigSubPacket (NotationData crit nfs nn nv) = do+    putSubPacketLength (9 + B.length nn + B.length nv)+    putSigSubPacketType crit 20+    putByteString . ffSetToFixedLengthBS 4 $ nfs+    putWord16be . fromIntegral . B.length $ nn+    putWord16be . fromIntegral . B.length $ nv+    putByteString nn+    putByteString nv+putSigSubPacket (PreferredHashAlgorithms crit ehs) = do+    putSubPacketLength (1 + length ehs)+    putSigSubPacketType crit 21+    mapM_ put ehs+putSigSubPacket (PreferredCompressionAlgorithms crit ecs) = do+    putSubPacketLength (1 + length ecs)+    putSigSubPacketType crit 22+    mapM_ put ecs+putSigSubPacket (KeyServerPreferences crit ksps) = do+    let kbs = ffSetToBS ksps+    putSubPacketLength (1 + B.length kbs)+    putSigSubPacketType crit 23+    putByteString kbs+putSigSubPacket (PreferredKeyServer crit ks) = do+    putSubPacketLength (1 + B.length ks)+    putSigSubPacketType crit 24+    putByteString ks+putSigSubPacket (PrimaryUserId crit primacy) = do+    putSubPacketLength 2+    putSigSubPacketType crit 25+    put primacy+putSigSubPacket (PolicyURL crit url) = do+    putSubPacketLength (1 + B.length url)+    putSigSubPacketType crit 26+    putByteString url+putSigSubPacket (KeyFlags crit kfs) = do+    let kbs = ffSetToBS kfs+    putSubPacketLength (1 + B.length kbs)+    putSigSubPacketType crit 27+    putByteString kbs+putSigSubPacket (SignersUserId crit userid) = do+    putSubPacketLength (1 + B.length userid)+    putSigSubPacketType crit 28+    putByteString userid+putSigSubPacket (ReasonForRevocation crit rcode rreason) = do+    putSubPacketLength (2 + B.length rreason)+    putSigSubPacketType crit 29+    putWord8 . fromFVal $ rcode+    putByteString rreason+putSigSubPacket (Features crit fs) = do+    let fbs = ffSetToBS fs+    putSubPacketLength (1 + B.length fbs)+    putSigSubPacketType crit 30+    putByteString fbs+putSigSubPacket (SignatureTarget crit pka ha hash) = do+    putSubPacketLength (3 + B.length hash)+    putSigSubPacketType crit 31+    put pka+    put ha+    putByteString hash+putSigSubPacket (EmbeddedSignature crit spb) = do+    putSubPacketLength (1 + B.length spb)+    putSigSubPacketType crit 32+    putByteString spb+putSigSubPacket (UserDefinedSigSub crit ptype payload) = do+    putSubPacketLength (1 + B.length payload)+    putSigSubPacketType crit ptype+    putByteString payload+putSigSubPacket (OtherSigSub crit ptype payload) = do+    putSubPacketLength (1 + B.length payload)+    putSigSubPacketType crit ptype+    putByteString payload++getSubPacketLength :: Integral a => Get a+getSubPacketLength = getSubPacketLength' =<< getWord8+    where+        getSubPacketLength' :: Integral a => Word8 -> Get a+        getSubPacketLength' f+            | f < 192 = return . fromIntegral $ f+            | f < 224 = do+                           secondOctet <- getWord8+                           return . fromIntegral $ shiftL (fromIntegral (f - 192) :: Int) 8 + (fromIntegral secondOctet :: Int) + 192+            | f == 255 = do+                           len <- getWord32be+                           return . fromIntegral $ len+            | otherwise = fail "Partial body length invalid."++putSubPacketLength :: Integral a => a -> Put+putSubPacketLength l+    | l < 192 = putWord8 (fromIntegral l)+    | l < 8384 = putWord8 (fromIntegral ((fromIntegral (l - 192) `shiftR` 8) + 192 :: Int)) >> putWord8 (fromIntegral (l - 192) .&. 0xff)+    | l < 0x100000000 = putWord8 255 >> putWord32be (fromIntegral l)+    | otherwise = fail "too big"++getSigSubPacketType :: Get (Bool, Word8)+getSigSubPacketType = do+                         x <- getWord8+                         if x .&. 0x80 == 0x80 then return (True, x .&. 0x7f) else return (False, x)++putSigSubPacketType :: Bool -> Word8 -> Put+putSigSubPacketType False sst = putWord8 sst+putSigSubPacketType True sst = putWord8 (sst .|. 0x80)++bsToFFSet :: FutureFlag a => ByteString -> Set a+bsToFFSet bs = Set.fromAscList .  concat . snd $ mapAccumL (\acc y -> (acc+8, concatMap (\x -> if y .&. (shiftR 128 x) == (shiftR 128 x) then [toFFlag (acc + x)] else []) [0..7])) 0 (B.unpack bs)++ffSetToFixedLengthBS :: (Integral a, FutureFlag b) => a -> Set b -> ByteString+ffSetToFixedLengthBS len ffs = B.take (fromIntegral len) (B.append (ffSetToBS ffs) (B.pack (replicate 5 0)))++ffSetToBS :: FutureFlag a => Set a -> ByteString+ffSetToBS = B.pack . ffSetToBS'+    where+        ffSetToBS' :: FutureFlag a => Set a -> [Word8]+        ffSetToBS' ks = map (foldl (.|.) 0 . map (shiftR 128 . flip mod 8 . fromFFlag) . Set.toAscList) (map (\x -> Set.filter (\y -> fromFFlag y `div` 8 == x) ks) [0..(fromFFlag $ Set.findMax ks) `div` 8])++fromS2K :: S2K -> ByteString+fromS2K (Simple hashalgo) = B.pack [0, fromIntegral . fromFVal $ hashalgo]+fromS2K (Salted hashalgo salt)+    | B.length salt == 8 = B.pack [1, fromIntegral . fromFVal $ hashalgo] `B.append` salt+fromS2K (IteratedSalted hashalgo salt count)+    | B.length salt == 8 = B.pack [3, fromIntegral . fromFVal $ hashalgo] `B.append` salt `B.snoc` (encodeIterationCount count)+fromS2K (OtherS2K t bs) = bs+++getPacketLength :: Integral a => Get a+getPacketLength = do+    firstOctet <- getWord8+    getPacketLength' firstOctet+    where+        getPacketLength' :: Integral a => Word8 -> Get a+        getPacketLength' f+            | f < 192 = return . fromIntegral $ f+            | f < 224 = do+                           secondOctet <- getWord8+                           return . fromIntegral $ shiftL (fromIntegral (f - 192) :: Int) 8 + (fromIntegral secondOctet :: Int) + 192+            | f == 255 = do+                           len <- getWord32be+                           return . fromIntegral $ len+            | otherwise = fail "Partial body length support missing." --FIXME++putPacketLength :: Integral a => a -> Put+putPacketLength l+    | l < 192 = putWord8 (fromIntegral l)+    | l < 8384 = putWord8 (fromIntegral ((fromIntegral (l - 192) `shiftR` 8) + 192 :: Int)) >> putWord8 (fromIntegral (l - 192) .&. 0xff)+    | l < 0x100000000 = putWord8 255 >> putWord32be (fromIntegral l)+    | otherwise = fail "partial body length support needed" -- FIXME++getS2K :: Get S2K+getS2K = getS2K' =<< getWord8+    where+        getS2K' :: Word8 -> Get S2K+        getS2K' t+            | t == 0 = do+                          ha <- getWord8+                          return $ Simple (toFVal ha)+            | t == 1 = do+                          ha <- getWord8+                          salt <- getByteString 8+                          return $ Salted (toFVal ha) salt+            | t == 3 = do+                          ha <- getWord8+                          salt <- getByteString 8+                          count <- getWord8+                          return $ IteratedSalted (toFVal ha) salt (decodeIterationCount count)+            | otherwise = error "Unknown S2K"++putS2K :: S2K -> Put+putS2K (IteratedSalted ha salt count) = do+    putWord8 3+    put ha+    putByteString salt+    putWord8 $ encodeIterationCount count++getPacketTypeAndLength :: Get (Word8, Int)+getPacketTypeAndLength = do+    tag <- getWord8 -- FIXME: bit 7 must be 1, check?+    case tag .&. 0x40 of+        0x00 -> do+                   let t = shiftR (tag .&. 0x3c) 2+                   case tag .&. 0x03 of+                       0 -> do len <- getWord8+                               return (t, fromIntegral len)+                       1 -> do len <- getWord16be+                               return (t, fromIntegral len)+                       2 -> do len <- getWord32be+                               return (t, fromIntegral len)+                       3 -> return (t, maxBound)  -- FIXME: express this better+        0x40 -> do+                   len <- getPacketLength+                   return (tag .&. 0x3f, len)++getPacket :: Get Packet+getPacket = do+               (t, len) <- getPacketTypeAndLength+               getPacket' t len+    where+        getPacket' :: Word8 -> Int -> Get Packet+        getPacket' t len+            | t == 1 = do+                          pv <- getWord8+                          eokeyid <- getByteString 8+                          pkalgo <- getWord8+                          sk <- getByteString (len - 10)+                          return $ PKESK pv eokeyid (toFVal pkalgo) sk+            | t == 2 = do+                          pv <- getWord8+                          case pv of+                              3 -> do+                                      hashlen <- getWord8 -- must be 5+                                      st <- getWord8+                                      ctime <- getWord32be+                                      eok <- getByteString 8+                                      pka <- get+                                      ha <- get+                                      left16 <- getWord16be+                                      mpib <- getBytes (len - 19)+                                      case runGet (many getMPI) mpib of+                                          Left e -> error e+                                          Right mpis -> return $ Signature $ SigV3 (toFVal st) ctime eok (toFVal pka) (toFVal ha) left16 mpis+                              4 -> do+                                      st <- getWord8+                                      pka <- get+                                      ha <- get+                                      hlen <- getWord16be+                                      hb <- getBytes (fromIntegral hlen)+                                      let hashed = case runGet (many getSigSubPacket) hb of+                                                        Left err -> error err+                                                        Right h -> h+                                      ulen <- getWord16be+                                      ub <- getBytes (fromIntegral ulen)+                                      let unhashed = case runGet (many getSigSubPacket) ub of+                                                        Left err -> error err+                                                        Right u -> u+                                      left16 <- getWord16be+                                      mpib <- getBytes (len - (10 + (fromIntegral hlen) + (fromIntegral ulen)))+                                      case runGet (many getMPI) mpib of+                                          Left e -> error e+                                          Right mpis -> return $ Signature $ SigV4 (toFVal st) (toFVal pka) (toFVal ha) hashed unhashed left16 mpis+                              otherwise -> do+                                               bs <- getByteString (len - 1)+                                               return $ Signature $ SigVOther pv bs+            | t == 3 = do+                          pv <- getWord8+                          symalgo <- getWord8+                          s2k <- getS2K+                          let partiallen = case s2k of+                                               Simple _ -> 1 + 3+                                               Salted _ _ -> 9 + 3+                                               IteratedSalted _ _ _ -> 10 + 3+                          msk <- getMSK len partiallen+                          return $ SKESK pv (toFVal symalgo) s2k msk+            | t == 4 = do+                          pv <- getWord8+                          sigtype <- getWord8+                          ha <- getWord8+                          pka <- getWord8+                          skeyid <- getByteString 8+                          nested <- getWord8+                          return $ OnePassSignature pv (toFVal sigtype) (toFVal ha) (toFVal pka) skeyid (nested == 0)+            | t == 5 = do+                          bs <- getBytes len+                          let ps = flip runGet bs $ do pkp <- getPKPayload+                                                       ska <- getSKAddendum (pubKeyAlgo pkp)+                                                       return $ SecretKey pkp ska+                          case ps of+                              Left err -> error err+                              Right key -> return key+            | t == 6 = do+                          pkp <- getPKPayload+                          return $ PublicKey pkp+            | t == 7 = do+                          bs <- getBytes len+                          let ps = flip runGet bs $ do pkp <- getPKPayload+                                                       ska <- getSKAddendum (pubKeyAlgo pkp)+                                                       return $ SecretSubkey pkp ska+                          case ps of+                              Left err -> error err+                              Right key -> return key+            | t == 8 = do+                          ca <- getWord8+                          cdata <- getByteString (len - 1)+                          return $ CompressedData (toFVal ca) cdata+            | t == 9 = do+                          sdata <- getByteString len+                          return $ SymEncData sdata+            | t == 10 = do+                          marker <- getByteString len+                          return $ Marker marker+            | t == 11 = do+                          dt <- getWord8+                          flen <- getWord8+                          fn <- getByteString (fromIntegral flen)+                          ts <- getWord32be+                          ldata <- getByteString (len - (6 + (fromIntegral flen)))+                          return $ LiteralData (toFVal dt) fn ts ldata+            | t == 12 = do+                          tdata <- getByteString len+                          return $ Trust tdata+            | t == 13 = do+                          udata <- getBytes len+                          return $ UserId (BC8.unpack udata)+            | t == 14 = do+                          pkp <- getPKPayload+                          return $ PublicSubkey pkp+            | t == 17 = do+                        bs <- getBytes len+                        case runGet (many getUserAttrSubPacket) bs of+                            Left err -> error err+                            Right uas -> return $ UserAttribute uas+            | t == 18 = do+                          pv <- getWord8 -- should be 1+                          b <- getByteString (len - 1)+                          return $ SymEncIntegrityProtectedData pv b+            | t == 19 = do+                          hash <- getByteString 20+                          return $ ModificationDetectionCode hash+            | otherwise = do+                          payload <- getByteString len+                          return $ OtherPacket t payload+            where+                          getMSK :: Int -> Int -> Get (Maybe SessionKey)+                          getMSK len partiallen+                              | len == partiallen = return Nothing+                              | len > partiallen = do+                                                      sk <- getByteString (len - partiallen)+                                                      return $ Just sk+                              | otherwise = error "Overread"++getUserAttrSubPacket :: Get UserAttrSubPacket+getUserAttrSubPacket = do+    l <- getSubPacketLength+    t <- getWord8+    getUserAttrSubPacket' t l+        where+            getUserAttrSubPacket' :: Word8 -> Int -> Get UserAttrSubPacket+            getUserAttrSubPacket' t l+                | t == 1 = do+                              ihlen <- getWord16le+                              hver <- getWord8 -- should be 1+                              iformat <- getWord8+                              _ <- getBytes 12 -- should be NULs+                              bs <- getByteString (l - 17)+                              return $ ImageAttribute (ImageHV1 (toFVal iformat)) bs+                | otherwise = do+                                 bs <- getByteString (l - 1)+                                 return $ OtherUASub t bs++putUserAttrSubPacket :: UserAttrSubPacket -> Put+putUserAttrSubPacket ua = do+    let sp = runPut $ putUserAttrSubPacket' ua+    putSubPacketLength . B.length $ sp+    putByteString sp+    where+        putUserAttrSubPacket' (ImageAttribute (ImageHV1 iformat) idata) = do+            putWord8 1+            putWord16le 16+            putWord8 1+            putWord8 (fromFVal iformat)+            mapM_ putWord8 $ replicate 12 0+            putByteString idata+        putUserAttrSubPacket' (OtherUASub t bs) = do+            putWord8 t+            putByteString bs++putPacket :: Packet -> Put+putPacket (PKESK pv eokeyid pkalgo sk) = do+    putWord8 (0xc0 .|. 1)+    let bsk = sk+    putPacketLength $ 10 + (B.length bsk)+    putWord8 pv -- must be 3+    putByteString eokeyid -- must be 8 octets+    putWord8 $ fromIntegral . fromFVal $ pkalgo+    putByteString bsk+putPacket (Signature (SigV3 st ctime eok pka ha left16 mpis)) = do+    putWord8 (0xc0 .|. 2)+    let bs = runPut $ do+                        putWord8 3+                        put st+                        putWord32be ctime+                        putByteString eok+                        put pka+                        put ha+                        putWord16be left16+                        mapM_ put mpis+    putPacketLength . B.length $ bs+    putByteString bs+putPacket (Signature (SigV4 st pka ha hashed unhashed left16 mpis)) = do+    putWord8 (0xc0 .|. 2)+    let bs = runPut $ do+                        putWord8 4+                        put st+                        put pka+                        put ha+                        let hb = runPut $ mapM_ put hashed+                        putWord16be . fromIntegral . B.length $ hb+                        putByteString hb+                        let ub = runPut $ mapM_ put unhashed+                        putWord16be . fromIntegral . B.length $ ub+                        putByteString ub+                        putWord16be left16+                        mapM_ put mpis+    putPacketLength . B.length $ bs+    putByteString bs+putPacket (SKESK pv symalgo s2k msk) = do+    putWord8 (0xc0 .|. 3)+    let bs2k = fromS2K s2k+    putPacketLength $ 2 + (B.length bs2k) + (maybe 0 B.length msk)+    putWord8 pv -- should be 4+    putWord8 $ fromIntegral . fromFVal $ symalgo+    putByteString bs2k+    when (isJust msk) $ putByteString (fromJust msk)+putPacket (OnePassSignature pv sigtype ha pka skeyid nested) = do+    putWord8 (0xc0 .|. 4)+    let bs = runPut $ do+                putWord8 pv -- should be 3+                putWord8 $ fromIntegral . fromFVal $ sigtype+                putWord8 $ fromIntegral . fromFVal $ ha+                putWord8 $ fromIntegral . fromFVal $ pka+                putByteString skeyid+                putWord8 . fromIntegral . fromEnum $ nested -- FIXME: what do other values mean?+    putPacketLength $ B.length bs+    putByteString bs+putPacket (SecretKey pkp ska) = do+    putWord8 (0xc0 .|. 5)+    let bs = runPut (putPKPayload pkp >> putSKAddendum ska)+    putPacketLength $ B.length bs+    putByteString bs+putPacket (PublicKey pkp) = do+    putWord8 (0xc0 .|. 6)+    let bs = runPut $ putPKPayload pkp+    putPacketLength $ B.length bs+    putByteString bs+putPacket (SecretSubkey pkp ska) = do+    putWord8 (0xc0 .|. 7)+    let bs = runPut (putPKPayload pkp >> putSKAddendum ska)+    putPacketLength $ B.length bs+    putByteString bs+putPacket (CompressedData ca cdata) = do+    putWord8 (0xc0 .|. 8)+    let bs = runPut $ do+                         putWord8 $ fromIntegral . fromFVal $ ca+                         putByteString cdata+    putPacketLength $ B.length bs+    putByteString bs+putPacket (SymEncData b) = do+    putWord8 (0xc0 .|. 9)+    putPacketLength $ B.length b+    putByteString b+putPacket (Marker b) = do+    putWord8 (0xc0 .|. 10)+    putPacketLength $ B.length b+    putByteString b+putPacket (LiteralData dt fn ts b) = do+    putWord8 (0xc0 .|. 11)+    let bs = runPut $ do+                        putWord8 $ fromIntegral . fromFVal $ dt+                        putWord8 $ fromIntegral . B.length $ fn+                        putByteString fn+                        putWord32be ts+                        putByteString b+    putPacketLength $ B.length bs+    putByteString bs+putPacket (Trust b) = do+    putWord8 (0xc0 .|. 12)+    putPacketLength . B.length $ b+    putByteString b+putPacket (UserId u) = do+    putWord8 (0xc0 .|. 13)+    let bs = BC8.pack u+    putPacketLength $ B.length bs+    putByteString bs+putPacket (PublicSubkey pkp) = do+    putWord8 (0xc0 .|. 14)+    let bs = runPut $ putPKPayload pkp+    putPacketLength $ B.length bs+    putByteString bs+putPacket (UserAttribute us) = do+    putWord8 (0xc0 .|. 17)+    let bs = runPut $ mapM_ put us+    putPacketLength $ B.length bs+    putByteString bs+putPacket (SymEncIntegrityProtectedData pv b) = do+    putWord8 (0xc0 .|. 18)+    putPacketLength $ (B.length b) + 1+    putWord8 pv -- should be 1+    putByteString b+putPacket (ModificationDetectionCode hash) = do+    putWord8 (0xc0 .|. 19)+    putPacketLength . B.length $ hash+    putByteString hash+putPacket (OtherPacket t payload) = do+    putWord8 (0xc0 .|. t) -- FIXME: restrict t+    putPacketLength . B.length $ payload+    putByteString payload+++getMPI :: Get MPI+getMPI = do mpilen <- getWord16be+            bs <- getByteString ((fromIntegral (mpilen - 1) `div` 8) + 1)+            return $ MPI bs++getMPIs :: PubKeyAlgorithm -> Get [MPI]+getMPIs RSA = replicateM 2 get+getMPIs RSAEncryptOnly = replicateM 2 get+getMPIs RSASignOnly = replicateM 2 get+getMPIs DSA = replicateM 4 get+getMPIs ElgamalEncryptOnly = replicateM 3 get+getMPIs Elgamal = replicateM 3 get++getSecretMPIs :: PubKeyAlgorithm -> Get [MPI]+getSecretMPIs RSA = replicateM 4 get+getSecretMPIs RSAEncryptOnly = replicateM 4 get+getSecretMPIs RSASignOnly = replicateM 1 get+getSecretMPIs DSA = replicateM 1 get+getSecretMPIs ElgamalEncryptOnly = replicateM 1 get+getSecretMPIs Elgamal = replicateM 1 get++indefiniteMPIs :: ByteString -> [MPI]+indefiniteMPIs bs = do+    case runGet (many getMPI) bs of+        Left e -> error e+        Right mpis -> mpis++putMPI :: MPI -> Put+putMPI (MPI bs) = do putWord16be . (*8) . fromIntegral . B.length $ bs -- FIXME: odd bits+                     putByteString bs++getPackets :: Get [Packet]+getPackets = many getPacket++putPackets :: [Packet] -> Put+putPackets = mapM_ putPacket++getPKPayload :: Get PKPayload+getPKPayload = do+    version <- getWord8+    ctime <- getWord32be+    case version `elem` [2,3] of+                               True -> do v3exp <-  getWord16be+                                          pka <- get+                                          mpis <- getMPIs pka+                                          return $ PubV3 ctime v3exp pka mpis+                               False -> do+                                          pka <- get+                                          mpis <- getMPIs pka+                                          return $ PubV4 ctime pka mpis++putPKPayload :: PKPayload -> Put+putPKPayload (PubV3 ctime v3exp pka mpis) = do+    putWord8 3+    putWord32be ctime+    putWord16be v3exp+    put pka+    mapM_ put mpis+putPKPayload (PubV4 ctime pka mpis) = do+    putWord8 4+    putWord32be ctime+    put pka+    mapM_ put mpis++pubKeyAlgo :: PKPayload -> PubKeyAlgorithm+pubKeyAlgo (PubV3 _ _ pka _) = pka+pubKeyAlgo (PubV4 _ pka _) = pka++getSKAddendum :: PubKeyAlgorithm -> Get SKAddendum+getSKAddendum pka = do+    s2kusage <- getWord8+    case s2kusage of+        0 -> do mpis <- getSecretMPIs pka+                checksum <- getWord16be+                return $ SUUnencrypted mpis checksum+        255 -> do symenc <- getWord8+                  s2k <- getS2K+                  iv <- getByteString (symEncBlockSize . toFVal $ symenc)+                  remainder <- remaining+                  encryptedblock <- getByteString remainder+                  return $ SUS16bit (toFVal symenc) s2k iv encryptedblock+        254 -> do symenc <- getWord8+                  s2k <- getS2K+                  iv <- getByteString (symEncBlockSize . toFVal $ symenc)+                  remainder <- remaining+                  encryptedblock <- getByteString remainder+                  return $ SUSSHA1 (toFVal symenc) s2k iv encryptedblock+        symenc -> do iv <- getByteString (symEncBlockSize . toFVal $ symenc)+                     remainder <- remaining+                     encryptedblock <- getByteString remainder+                     return $ SUSym (toFVal symenc) iv encryptedblock++putSKAddendum :: SKAddendum -> Put+putSKAddendum (SUSSHA1 symenc s2k iv encryptedblock) = do+    putWord8 254+    put symenc+    put s2k+    putByteString iv+    putByteString encryptedblock++symEncBlockSize :: SymmetricAlgorithm -> Int+symEncBlockSize (Plaintext) = 0+symEncBlockSize (IDEA) = 8+symEncBlockSize (TripleDES) = 8+symEncBlockSize (CAST5) = 8+symEncBlockSize (Blowfish) = 8+symEncBlockSize (AES128) = 16+symEncBlockSize (AES192) = 16+symEncBlockSize (AES256) = 16+symEncBlockSize (Twofish) = 16+symEncBlockSize x = 8 -- FIXME++decodeIterationCount :: Word8 -> Int+decodeIterationCount c = fromIntegral $ (16 + (c .&. 15)) `shiftL` ((fromIntegral c `shiftR` 4) + 6)++encodeIterationCount :: Int -> Word8+encodeIterationCount c = fromIntegral c -- FIXME++-- Stolen from Axman6+many :: Get a -> Get [a]+many p = many1 p `mplus` return []++many1 :: Get a -> Get [a]+many1 p = (:) <$> p <*> many p
+ Codec/Encryption/OpenPGP/Types.hs view
@@ -0,0 +1,520 @@+-- Types.hs: OpenPGP (RFC4880) data types+-- Copyright Ⓒ 2012  Clint Adams+-- This software is released under the terms of the Expat (MIT) license.+-- (See the LICENSE file).++module Codec.Encryption.OpenPGP.Types (+   SigSubPacket(..)+ , CompressionAlgorithm(..)+ , HashAlgorithm(..)+ , PubKeyAlgorithm(..)+ , SymmetricAlgorithm(..)+ , MPI(MPI)+ , Packet(..)+ , S2K(..)+ , SignaturePayload(..)+ , UserAttrSubPacket(..)+ , SigType(..)+ , ImageHeader(..)+ , ImageFormat(..)+ , PKPayload(..)+ , SKAddendum(..)+ , EightOctetKeyId+ , SessionKey+ , FutureFlag+ , FutureVal+ , fromFVal+ , fromFFlag+ , toFVal+ , toFFlag+) where++import Data.ByteString (ByteString)+import Data.Set (Set)+import Data.Word (Word8, Word16, Word32)++type TimeStamp = Word32+type Exportability = Bool+type TrustLevel = Word8+type TrustAmount = Word8+type AlmostPublicDomainRegex = ByteString+type Revocability = Bool+type RevocationReason = ByteString+type TwentyOctetFingerprint = ByteString+type EightOctetKeyId = ByteString+type KeyServer = ByteString+type URL = ByteString+type NotationName = ByteString+type NotationValue = ByteString+type UserId = ByteString+type SignaturePacketBody = ByteString+type SignatureHash = ByteString+type PacketVersion = Word8+type SessionKey = ByteString+type Salt = ByteString+type Count = Int+type V3Expiration = Word16+type CompressedDataPayload = ByteString+type FileName = ByteString+type ImageData = ByteString+type NestedFlag = Bool+type IV = ByteString++data SymmetricAlgorithm = Plaintext+                        | IDEA+                        | TripleDES+                        | CAST5+                        | Blowfish+                        | ReservedSAFER+                        | ReservedDES+                        | AES128+                        | AES192+                        | AES256+                        | Twofish+                        | OtherSA Word8+     deriving (Show)++instance Eq SymmetricAlgorithm where+    (==) a b = fromFVal a == fromFVal b++instance Ord SymmetricAlgorithm where+    compare a b = fromFVal a `compare` fromFVal b++instance FutureVal SymmetricAlgorithm where+    fromFVal Plaintext = 0+    fromFVal IDEA = 1+    fromFVal TripleDES = 2+    fromFVal CAST5 = 3+    fromFVal Blowfish = 4+    fromFVal AES128 = 7+    fromFVal AES192 = 8+    fromFVal AES256 = 9+    fromFVal Twofish = 10+    fromFVal (OtherSA o) = o+    toFVal 0 = Plaintext+    toFVal 1 = IDEA+    toFVal 2 = TripleDES+    toFVal 3 = CAST5+    toFVal 4 = Blowfish+    toFVal 7 = AES128+    toFVal 8 = AES192+    toFVal 9 = AES256+    toFVal 10 = Twofish+    toFVal o = OtherSA o++data NotationFlag = HumanReadable+                  | OtherNF Int+     deriving (Show)++instance Eq NotationFlag where+    (==) a b = fromFFlag a == fromFFlag b++instance Ord NotationFlag where+    compare a b = fromFFlag a `compare` fromFFlag b++instance FutureFlag NotationFlag where+    fromFFlag HumanReadable = 0+    fromFFlag (OtherNF o) = fromIntegral o++    toFFlag 0 = HumanReadable+    toFFlag o = OtherNF (fromIntegral o)++data SigSubPacket = SigCreationTime Bool TimeStamp+                  | SigExpirationTime Bool TimeStamp+                  | ExportableCertification Bool Exportability+                  | TrustSignature Bool TrustLevel TrustAmount+                  | RegularExpression Bool AlmostPublicDomainRegex+                  | Revocable Bool Revocability+                  | KeyExpirationTime Bool TimeStamp+                  | PreferredSymmetricAlgorithms Bool [SymmetricAlgorithm]+                  | RevocationKey Bool (Set RevocationClass) PubKeyAlgorithm TwentyOctetFingerprint+                  | Issuer Bool EightOctetKeyId+                  | NotationData Bool (Set NotationFlag) NotationName NotationValue+                  | PreferredHashAlgorithms Bool [HashAlgorithm]+                  | PreferredCompressionAlgorithms Bool [CompressionAlgorithm]+                  | KeyServerPreferences Bool (Set KSPFlag)+                  | PreferredKeyServer Bool KeyServer+                  | PrimaryUserId Bool Bool+                  | PolicyURL Bool URL+                  | KeyFlags Bool (Set KeyFlag)+                  | SignersUserId Bool UserId+                  | ReasonForRevocation Bool RevocationCode RevocationReason+                  | Features Bool (Set FeatureFlag)+                  | SignatureTarget Bool PubKeyAlgorithm HashAlgorithm SignatureHash+                  | EmbeddedSignature Bool SignaturePacketBody+                  | UserDefinedSigSub Bool Word8 ByteString+                  | OtherSigSub Bool Word8 ByteString+    deriving (Show, Eq) -- FIXME++data HashAlgorithm = DeprecatedMD5+                   | SHA1+                   | RIPEMD160+                   | SHA256+                   | SHA384+                   | SHA512+                   | SHA224+                   | OtherHA Word8+    deriving (Show)++instance Eq HashAlgorithm where+    (==) a b = fromFVal a == fromFVal b++instance Ord HashAlgorithm where+    compare a b = fromFVal a `compare` fromFVal b++instance FutureVal HashAlgorithm where+    fromFVal DeprecatedMD5 = 1+    fromFVal SHA1 = 2+    fromFVal RIPEMD160 = 3+    fromFVal SHA256 = 8+    fromFVal SHA384 = 9+    fromFVal SHA512 = 10+    fromFVal SHA224 = 11+    fromFVal (OtherHA o) = o+    toFVal 1 = DeprecatedMD5+    toFVal 2 = SHA1+    toFVal 3 = RIPEMD160+    toFVal 8 = SHA256+    toFVal 9 = SHA384+    toFVal 10 = SHA512+    toFVal 11 = SHA224+    toFVal o = OtherHA o++data CompressionAlgorithm = Uncompressed+                          | ZIP+                          | ZLIB+                          | BZip2+                          | OtherCA Word8+    deriving (Show)++instance Eq CompressionAlgorithm where+    (==) a b = fromFVal a == fromFVal b++instance Ord CompressionAlgorithm where+    compare a b = fromFVal a `compare` fromFVal b++instance FutureVal CompressionAlgorithm where+    fromFVal Uncompressed = 0+    fromFVal ZIP = 1+    fromFVal ZLIB = 2+    fromFVal BZip2 = 3+    fromFVal (OtherCA o) = o+    toFVal 0 = Uncompressed+    toFVal 1 = ZIP+    toFVal 2 = ZLIB+    toFVal 3 = BZip2+    toFVal o = OtherCA o++class (Eq a, Ord a) => FutureVal a where+   fromFVal :: a -> Word8+   toFVal :: Word8 -> a++data PubKeyAlgorithm = RSA+                     | RSAEncryptOnly+                     | RSASignOnly+                     | ElgamalEncryptOnly+                     | DSA+                     | EC+                     | ECDSA+                     | Elgamal+                     | DH+                     | OtherPKA Word8+    deriving (Show)++instance Eq PubKeyAlgorithm where+    (==) a b = fromFVal a == fromFVal b++instance Ord PubKeyAlgorithm where+    compare a b = fromFVal a `compare` fromFVal b++instance FutureVal PubKeyAlgorithm where+    fromFVal RSA = 1+    fromFVal RSAEncryptOnly = 2+    fromFVal RSASignOnly = 3+    fromFVal ElgamalEncryptOnly = 16+    fromFVal DSA = 17+    fromFVal EC = 18+    fromFVal ECDSA = 19+    fromFVal Elgamal = 20+    fromFVal DH = 21+    fromFVal (OtherPKA o) = o+    toFVal 1 = RSA+    toFVal 2 = RSAEncryptOnly+    toFVal 3 = RSASignOnly+    toFVal 16 = ElgamalEncryptOnly+    toFVal 17 = DSA+    toFVal 18 = EC+    toFVal 19 = ECDSA+    toFVal 20 = Elgamal+    toFVal 21 = DH+    toFVal o = OtherPKA o++class (Eq a, Ord a) => FutureFlag a where+    fromFFlag :: Integral b => a -> b+    toFFlag :: Integral b => b-> a++data KSPFlag = NoModify+             | KSPOther Int+    deriving (Show)++instance Eq KSPFlag where+    (==) a b = fromFFlag a == fromFFlag b++instance Ord KSPFlag where+    compare a b = fromFFlag a `compare` fromFFlag b++instance FutureFlag KSPFlag where+    fromFFlag NoModify = 0+    fromFFlag (KSPOther i) = fromIntegral i++    toFFlag 0 = NoModify+    toFFlag i = KSPOther (fromIntegral i)++data KeyFlag = GroupKey+             | AuthKey+             | SplitKey+             | EncryptStorageKey+             | EncryptCommunicationsKey+             | SignDataKey+             | CertifyKeysKey+             | KFOther Int+    deriving (Show)++instance Eq KeyFlag where+    (==) a b = fromFFlag a == fromFFlag b++instance Ord KeyFlag where+    compare a b = fromFFlag a `compare` fromFFlag b++instance FutureFlag KeyFlag where+    fromFFlag GroupKey = 0+    fromFFlag AuthKey = 2+    fromFFlag SplitKey = 3+    fromFFlag EncryptStorageKey = 4+    fromFFlag EncryptCommunicationsKey = 5+    fromFFlag SignDataKey = 6+    fromFFlag CertifyKeysKey = 7+    fromFFlag (KFOther i) = fromIntegral i++    toFFlag 0 = GroupKey+    toFFlag 2 = AuthKey+    toFFlag 3 = SplitKey+    toFFlag 4 = EncryptStorageKey+    toFFlag 5 = EncryptCommunicationsKey+    toFFlag 6 = SignDataKey+    toFFlag 7 = CertifyKeysKey+    toFFlag i = KFOther (fromIntegral i)++data RevocationClass = SensitiveRK+                     | RClOther Int+    deriving (Show)++instance Eq RevocationClass where+    (==) a b = fromFFlag a == fromFFlag b++instance Ord RevocationClass where+    compare a b = fromFFlag a `compare` fromFFlag b++instance FutureFlag RevocationClass where+    fromFFlag SensitiveRK = 1+    fromFFlag (RClOther i) = fromIntegral i++    toFFlag 1 = SensitiveRK+    toFFlag i = RClOther (fromIntegral i)++data RevocationCode = NoReason+                    | KeySuperseded+                    | KeyMaterialCompromised+                    | KeyRetiredAndNoLongerUsed+                    | UserIdInfoNoLongerValid+                    | RCoOther Word8+    deriving (Show)++instance Eq RevocationCode where+    (==) a b = fromFVal a == fromFVal b++instance Ord RevocationCode where+    compare a b = fromFVal a `compare` fromFVal b++instance FutureVal RevocationCode where+    fromFVal NoReason = 0+    fromFVal KeySuperseded = 1+    fromFVal KeyMaterialCompromised = 2+    fromFVal KeyRetiredAndNoLongerUsed = 3+    fromFVal UserIdInfoNoLongerValid = 32+    fromFVal (RCoOther o) = o+    toFVal 0 = NoReason+    toFVal 1 = KeySuperseded+    toFVal 2 = KeyMaterialCompromised+    toFVal 3 = KeyRetiredAndNoLongerUsed+    toFVal 32 = UserIdInfoNoLongerValid+    toFVal o = RCoOther o++data FeatureFlag = ModificationDetection+                 | FeatureOther Int+    deriving (Show)++instance Eq FeatureFlag where+    (==) a b = fromFFlag a == fromFFlag b++instance Ord FeatureFlag where+    compare a b = fromFFlag a `compare` fromFFlag b++instance FutureFlag FeatureFlag where+    fromFFlag ModificationDetection = 7+    fromFFlag (FeatureOther i) = fromIntegral i++    toFFlag 7 = ModificationDetection+    toFFlag i = FeatureOther (fromIntegral i)++data MPI = MPI ByteString+    deriving (Show, Eq)++data SignaturePayload = SigV3 SigType Word32 EightOctetKeyId PubKeyAlgorithm HashAlgorithm Word16 [MPI]+                      | SigV4 SigType PubKeyAlgorithm HashAlgorithm [SigSubPacket] [SigSubPacket] Word16 [MPI]+                      | SigVOther Word8 ByteString+    deriving (Show, Eq) -- FIXME++data PKPayload = PubV3 TimeStamp V3Expiration PubKeyAlgorithm [MPI]+               | PubV4 TimeStamp PubKeyAlgorithm [MPI]+    deriving (Show, Eq)++data SKAddendum = SUS16bit SymmetricAlgorithm S2K IV ByteString+                | SUSSHA1 SymmetricAlgorithm S2K IV ByteString+                | SUSym SymmetricAlgorithm IV ByteString+                | SUUnencrypted [MPI] Word16+    deriving (Show, Eq)++data DataType = BinaryData+              | TextData+              | UTF8Data+              | OtherData Word8+    deriving (Show)++instance Eq DataType where+    (==) a b = fromFVal a == fromFVal b++instance Ord DataType where+    compare a b = fromFVal a `compare` fromFVal b++instance FutureVal DataType where+    fromFVal BinaryData = fromIntegral . fromEnum $ 'b'+    fromFVal TextData = fromIntegral . fromEnum $ 't'+    fromFVal UTF8Data = fromIntegral . fromEnum $ 'u'+    fromFVal (OtherData o) = o++    toFVal 0x62 = BinaryData+    toFVal 0x74 = TextData+    toFVal 0x75 = UTF8Data+    toFVal o = OtherData o++data Packet = PKESK PacketVersion EightOctetKeyId PubKeyAlgorithm SessionKey+            | Signature SignaturePayload+            | SKESK PacketVersion SymmetricAlgorithm S2K (Maybe SessionKey)+            | OnePassSignature PacketVersion SigType HashAlgorithm PubKeyAlgorithm EightOctetKeyId NestedFlag+            | SecretKey PKPayload SKAddendum+            | PublicKey PKPayload+            | SecretSubkey PKPayload SKAddendum+            | CompressedData CompressionAlgorithm CompressedDataPayload+            | SymEncData ByteString+            | Marker ByteString+            | LiteralData DataType FileName TimeStamp ByteString+            | Trust ByteString+            | UserId String+            | PublicSubkey PKPayload+            | UserAttribute [UserAttrSubPacket]+            | SymEncIntegrityProtectedData PacketVersion ByteString+            | ModificationDetectionCode ByteString+            | OtherPacket Word8 ByteString+    deriving (Show, Eq) -- FIXME++data S2K = Simple HashAlgorithm+         | Salted HashAlgorithm Salt+         | IteratedSalted HashAlgorithm Salt Count+         | OtherS2K Word8 ByteString+    deriving (Show, Eq) -- FIXME++data UserAttrSubPacket = ImageAttribute ImageHeader ImageData+                       | OtherUASub Word8 ByteString+    deriving (Show, Eq) -- FIXME++data ImageHeader = ImageHV1 ImageFormat+    deriving (Show, Eq)++data ImageFormat = JPEG+                 | OtherImage Word8+    deriving (Show)++instance Eq ImageFormat where+    (==) a b = fromFVal a == fromFVal b++instance Ord ImageFormat where+    compare a b = fromFVal a `compare` fromFVal b++instance FutureVal ImageFormat where+    fromFVal JPEG = 1+    fromFVal (OtherImage o) = o++    toFVal 1 = JPEG+    toFVal o = OtherImage o++data SigType = BinarySig+             | CanonicalTextSig+             | StandaloneSig+             | GenericCert+             | PersonaCert+             | CasualCert+             | PositiveCert+             | SubkeyBindingSig+             | PrimaryKeyBindingSig+             | SignatureDirectlyOnAKey+             | KeyRevocationSig+             | SubkeyRevocationSig+             | CertRevocationSig+             | TimestampSig+             | ThirdPartyConfirmationSig+             | OtherSig Word8+    deriving (Show)++instance Eq SigType where+    (==) a b = fromFVal a == fromFVal b++instance Ord SigType where+    compare a b = fromFVal a `compare` fromFVal b++instance FutureVal SigType where+    fromFVal BinarySig = 0x00+    fromFVal CanonicalTextSig = 0x01+    fromFVal StandaloneSig = 0x02+    fromFVal GenericCert = 0x10+    fromFVal PersonaCert = 0x11+    fromFVal CasualCert = 0x12+    fromFVal PositiveCert = 0x13+    fromFVal SubkeyBindingSig = 0x18+    fromFVal PrimaryKeyBindingSig = 0x19+    fromFVal SignatureDirectlyOnAKey = 0x1F+    fromFVal KeyRevocationSig = 0x20+    fromFVal SubkeyRevocationSig = 0x28+    fromFVal CertRevocationSig = 0x30+    fromFVal TimestampSig = 0x40+    fromFVal ThirdPartyConfirmationSig = 0x50+    fromFVal (OtherSig o) = o++    toFVal 0x00 = BinarySig+    toFVal 0x01 = CanonicalTextSig+    toFVal 0x02 = StandaloneSig+    toFVal 0x10 = GenericCert+    toFVal 0x11 = PersonaCert+    toFVal 0x12 = CasualCert+    toFVal 0x13 = PositiveCert+    toFVal 0x18 = SubkeyBindingSig+    toFVal 0x19 = PrimaryKeyBindingSig+    toFVal 0x1F = SignatureDirectlyOnAKey+    toFVal 0x20 = KeyRevocationSig+    toFVal 0x28 = SubkeyRevocationSig+    toFVal 0x30 = CertRevocationSig+    toFVal 0x40 = TimestampSig+    toFVal 0x50 = ThirdPartyConfirmationSig+    toFVal o = OtherSig o++
+ LICENSE view
@@ -0,0 +1,19 @@+Copyright Ⓒ 2012 Clint Adams++Permission is hereby granted, free of charge, to any person obtaining a copy of+this software and associated documentation files (the "Software"), to deal in+the Software without restriction, including without limitation the rights to+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies+of the Software, and to permit persons to whom the Software is furnished to do+so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ hOpenPGP.cabal view
@@ -0,0 +1,121 @@+Name:                hOpenPGP+Version:             0.0.0+Synopsis:            native Haskell implementation of OpenPGP (RFC4880)+Description:         native Haskell implementation of OpenPGP (RFC4880)+Homepage:            http://floss.scru.org/hOpenPGP/+License:             MIT+License-file:        LICENSE+Author:              Clint Adams+Maintainer:          Clint Adams <clint@debian.org>+Copyright:           2012, Clint Adams+Category:            Codec+Build-type:          Simple+Extra-source-files: tests/suite.hs+  , tests/data/000001-006.public_key+  , tests/data/000002-013.user_id+  , tests/data/000003-002.sig+  , tests/data/000004-012.ring_trust+  , tests/data/000005-002.sig+  , tests/data/000006-012.ring_trust+  , tests/data/000007-002.sig+  , tests/data/000008-012.ring_trust+  , tests/data/000009-002.sig+  , tests/data/000010-012.ring_trust+  , tests/data/000011-002.sig+  , tests/data/000012-012.ring_trust+  , tests/data/000013-014.public_subkey+  , tests/data/000014-002.sig+  , tests/data/000015-012.ring_trust+  , tests/data/000016-006.public_key+  , tests/data/000017-002.sig+  , tests/data/000018-012.ring_trust+  , tests/data/000019-013.user_id+  , tests/data/000020-002.sig+  , tests/data/000021-012.ring_trust+  , tests/data/000022-002.sig+  , tests/data/000023-012.ring_trust+  , tests/data/000024-014.public_subkey+  , tests/data/000025-002.sig+  , tests/data/000026-012.ring_trust+  , tests/data/000027-006.public_key+  , tests/data/000028-002.sig+  , tests/data/000029-012.ring_trust+  , tests/data/000030-013.user_id+  , tests/data/000031-002.sig+  , tests/data/000032-012.ring_trust+  , tests/data/000033-002.sig+  , tests/data/000034-012.ring_trust+  , tests/data/000035-006.public_key+  , tests/data/000036-013.user_id+  , tests/data/000037-002.sig+  , tests/data/000038-012.ring_trust+  , tests/data/000039-002.sig+  , tests/data/000040-012.ring_trust+  , tests/data/000041-017.attribute+  , tests/data/000042-002.sig+  , tests/data/000043-012.ring_trust+  , tests/data/000044-014.public_subkey+  , tests/data/000045-002.sig+  , tests/data/000046-012.ring_trust+  , tests/data/000047-005.secret_key+  , tests/data/000048-013.user_id+  , tests/data/000049-002.sig+  , tests/data/000050-012.ring_trust+  , tests/data/000051-007.secret_subkey+  , tests/data/000052-002.sig+  , tests/data/000053-012.ring_trust+  , tests/data/000054-005.secret_key+  , tests/data/000055-002.sig+  , tests/data/000056-012.ring_trust+  , tests/data/000057-013.user_id+  , tests/data/000058-002.sig+  , tests/data/000059-012.ring_trust+  , tests/data/000060-007.secret_subkey+  , tests/data/000061-002.sig+  , tests/data/000062-012.ring_trust+  , tests/data/000063-005.secret_key+  , tests/data/000064-002.sig+  , tests/data/000065-012.ring_trust+  , tests/data/000066-013.user_id+  , tests/data/000067-002.sig+  , tests/data/000068-012.ring_trust+  , tests/data/000069-005.secret_key+  , tests/data/000070-013.user_id+  , tests/data/000071-002.sig+  , tests/data/000072-012.ring_trust+  , tests/data/000073-017.attribute+  , tests/data/000074-002.sig+  , tests/data/000075-012.ring_trust+  , tests/data/000076-007.secret_subkey+  , tests/data/000077-002.sig+  , tests/data/000078-012.ring_trust+  , tests/data/pubring.gpg+  , tests/data/secring.gpg++Cabal-version:       >= 1.10+++Library+  Exposed-modules:     Codec.Encryption.OpenPGP.Types, Codec.Encryption.OpenPGP.Serialize+  Build-depends: base             > 4       && < 5+               , bytestring+               , cereal+               , containers+  default-language: Haskell2010+++Test-Suite tests+  type:       exitcode-stdio-1.0+  main-is:    tests/suite.hs+  Build-depends: base             > 4       && < 5+               , bytestring+               , cereal+               , containers+               , HUnit+               , test-framework+               , test-framework-hunit+  default-language: Haskell2010++source-repository head+  type:     git+  location: git://git.debian.org/users/clint/hOpenPGP.git
+ tests/data/000001-006.public_key view

binary file changed (absent → 171 bytes)

+ tests/data/000002-013.user_id view
@@ -0,0 +1,1 @@+´$Test Key (RSA) <testkey@example.org>
+ tests/data/000003-002.sig view

binary file changed (absent → 113 bytes)

+ tests/data/000004-012.ring_trust view

binary file changed (absent → 4 bytes)

+ tests/data/000005-002.sig view

binary file changed (absent → 113 bytes)

+ tests/data/000006-012.ring_trust view

binary file changed (absent → 4 bytes)

+ tests/data/000007-002.sig view

binary file changed (absent → 220 bytes)

+ tests/data/000008-012.ring_trust view

binary file changed (absent → 4 bytes)

+ tests/data/000009-002.sig view

binary file changed (absent → 158 bytes)

+ tests/data/000010-012.ring_trust view

binary file changed (absent → 4 bytes)

+ tests/data/000011-002.sig view

binary file changed (absent → 96 bytes)

+ tests/data/000012-012.ring_trust view

binary file changed (absent → 4 bytes)

+ tests/data/000013-014.public_subkey view

binary file changed (absent → 171 bytes)

+ tests/data/000014-002.sig view

binary file changed (absent → 195 bytes)

+ tests/data/000015-012.ring_trust view

binary file changed (absent → 4 bytes)

+ tests/data/000016-006.public_key view

binary file changed (absent → 1201 bytes)

+ tests/data/000017-002.sig view

binary file changed (absent → 123 bytes)

+ tests/data/000018-012.ring_trust view

binary file changed (absent → 4 bytes)

+ tests/data/000019-013.user_id view
@@ -0,0 +1,1 @@+´$Test Key (DSA) <testkey@example.com>
+ tests/data/000020-002.sig view

binary file changed (absent → 130 bytes)

+ tests/data/000021-012.ring_trust view

binary file changed (absent → 4 bytes)

+ tests/data/000022-002.sig view

binary file changed (absent → 186 bytes)

+ tests/data/000023-012.ring_trust view

binary file changed (absent → 4 bytes)

+ tests/data/000024-014.public_subkey view

binary file changed (absent → 608 bytes)

+ tests/data/000025-002.sig view

binary file changed (absent → 105 bytes)

+ tests/data/000026-012.ring_trust view

binary file changed (absent → 4 bytes)

+ tests/data/000027-006.public_key view

binary file changed (absent → 421 bytes)

+ tests/data/000028-002.sig view

binary file changed (absent → 99 bytes)

+ tests/data/000029-012.ring_trust view

binary file changed (absent → 4 bytes)

+ tests/data/000030-013.user_id view
@@ -0,0 +1,1 @@+´+Test Key (DSA sign-only) <test@example.net>
+ tests/data/000031-002.sig view

binary file changed (absent → 132 bytes)

+ tests/data/000032-012.ring_trust view

binary file changed (absent → 4 bytes)

+ tests/data/000033-002.sig view

binary file changed (absent → 96 bytes)

+ tests/data/000034-012.ring_trust view

binary file changed (absent → 4 bytes)

+ tests/data/000035-006.public_key view

binary file changed (absent → 143 bytes)

+ tests/data/000036-013.user_id view
@@ -0,0 +1,1 @@+´.Test Key (RSA sign-only) <testkey@example.net>
+ tests/data/000037-002.sig view

binary file changed (absent → 192 bytes)

+ tests/data/000038-012.ring_trust view

binary file changed (absent → 4 bytes)

+ tests/data/000039-002.sig view

binary file changed (absent → 72 bytes)

+ tests/data/000040-012.ring_trust view

binary file changed (absent → 4 bytes)

+ tests/data/000041-017.attribute view

binary file changed (absent → 1761 bytes)

+ tests/data/000042-002.sig view

binary file changed (absent → 192 bytes)

+ tests/data/000043-012.ring_trust view

binary file changed (absent → 4 bytes)

+ tests/data/000044-014.public_subkey view

binary file changed (absent → 272 bytes)

+ tests/data/000045-002.sig view

binary file changed (absent → 161 bytes)

+ tests/data/000046-012.ring_trust view

binary file changed (absent → 4 bytes)

+ tests/data/000047-005.secret_key view

binary file changed (absent → 610 bytes)

+ tests/data/000048-013.user_id view
@@ -0,0 +1,1 @@+´$Test Key (RSA) <testkey@example.org>
+ tests/data/000049-002.sig view

binary file changed (absent → 220 bytes)

+ tests/data/000050-012.ring_trust view

binary file changed (absent → 4 bytes)

+ tests/data/000051-007.secret_subkey view

binary file changed (absent → 611 bytes)

+ tests/data/000052-002.sig view

binary file changed (absent → 195 bytes)

+ tests/data/000053-012.ring_trust view

binary file changed (absent → 4 bytes)

+ tests/data/000054-005.secret_key view

binary file changed (absent → 1275 bytes)

+ tests/data/000055-002.sig view

binary file changed (absent → 123 bytes)

+ tests/data/000056-012.ring_trust view

binary file changed (absent → 4 bytes)

+ tests/data/000057-013.user_id view
@@ -0,0 +1,1 @@+´$Test Key (DSA) <testkey@example.com>
+ tests/data/000058-002.sig view

binary file changed (absent → 130 bytes)

+ tests/data/000059-012.ring_trust view

binary file changed (absent → 4 bytes)

+ tests/data/000060-007.secret_subkey view

binary file changed (absent → 698 bytes)

+ tests/data/000061-002.sig view

binary file changed (absent → 104 bytes)

+ tests/data/000062-012.ring_trust view

binary file changed (absent → 4 bytes)

+ tests/data/000063-005.secret_key view

binary file changed (absent → 484 bytes)

+ tests/data/000064-002.sig view

binary file changed (absent → 99 bytes)

+ tests/data/000065-012.ring_trust view

binary file changed (absent → 4 bytes)

+ tests/data/000066-013.user_id view
@@ -0,0 +1,1 @@+´+Test Key (DSA sign-only) <test@example.net>
+ tests/data/000067-002.sig view

binary file changed (absent → 106 bytes)

+ tests/data/000068-012.ring_trust view

binary file changed (absent → 4 bytes)

+ tests/data/000069-005.secret_key view

binary file changed (absent → 513 bytes)

+ tests/data/000070-013.user_id view
@@ -0,0 +1,1 @@+´.Test Key (RSA sign-only) <testkey@example.net>
+ tests/data/000071-002.sig view

binary file changed (absent → 192 bytes)

+ tests/data/000072-012.ring_trust view

binary file changed (absent → 4 bytes)

+ tests/data/000073-017.attribute view

binary file changed (absent → 1761 bytes)

+ tests/data/000074-002.sig view

binary file changed (absent → 192 bytes)

+ tests/data/000075-012.ring_trust view

binary file changed (absent → 4 bytes)

+ tests/data/000076-007.secret_subkey view

binary file changed (absent → 961 bytes)

+ tests/data/000077-002.sig view

binary file changed (absent → 161 bytes)

+ tests/data/000078-012.ring_trust view

binary file changed (absent → 4 bytes)

+ tests/data/pubring.gpg view

binary file changed (absent → 7368 bytes)

+ tests/data/secring.gpg view

binary file changed (absent → 8644 bytes)

+ tests/suite.hs view
@@ -0,0 +1,159 @@+{-# LANGUAGE OverloadedStrings #-}++import Test.Framework (defaultMain, testGroup)+import Test.Framework.Providers.HUnit++import Test.HUnit++import Codec.Encryption.OpenPGP.Serialize (getPackets, putPackets)+import qualified Data.ByteString as B+import Data.Serialize.Get (runGet)+import Data.Serialize.Put (runPut)++testSerialization :: FilePath -> Assertion+testSerialization fp = do+    bs <- B.readFile $ "tests/data/" ++ fp+    let firstpass = runGet getPackets bs+    case firstpass of+        Left err -> assertFailure $ "First pass failed on " ++ fp+        Right packs -> do let roundtrip = runPut $ putPackets packs+                          let secondpass = runGet getPackets roundtrip+                          assertEqual ("for " ++ fp) firstpass secondpass++tests = [+   testCase "000001-006.public_key" (testSerialization "000001-006.public_key")+ , testCase "000002-013.user_id" (testSerialization "000002-013.user_id")+ , testCase "000003-002.sig" (testSerialization "000003-002.sig")+ , testCase "000004-012.ring_trust" (testSerialization "000004-012.ring_trust")+ , testCase "000005-002.sig" (testSerialization "000005-002.sig")+ , testCase "000006-012.ring_trust" (testSerialization "000006-012.ring_trust")+ , testCase "000007-002.sig" (testSerialization "000007-002.sig")+ , testCase "000008-012.ring_trust" (testSerialization "000008-012.ring_trust")+ , testCase "000009-002.sig" (testSerialization "000009-002.sig")+ , testCase "000010-012.ring_trust" (testSerialization "000010-012.ring_trust")+ , testCase "000011-002.sig" (testSerialization "000011-002.sig")+ , testCase "000012-012.ring_trust" (testSerialization "000012-012.ring_trust")+ , testCase "000013-014.public_subkey" (testSerialization "000013-014.public_subkey")+ , testCase "000014-002.sig" (testSerialization "000014-002.sig")+ , testCase "000015-012.ring_trust" (testSerialization "000015-012.ring_trust")+ , testCase "000016-006.public_key" (testSerialization "000016-006.public_key")+ , testCase "000017-002.sig" (testSerialization "000017-002.sig")+ , testCase "000018-012.ring_trust" (testSerialization "000018-012.ring_trust")+ , testCase "000019-013.user_id" (testSerialization "000019-013.user_id")+ , testCase "000020-002.sig" (testSerialization "000020-002.sig")+ , testCase "000021-012.ring_trust" (testSerialization "000021-012.ring_trust")+ , testCase "000022-002.sig" (testSerialization "000022-002.sig")+ , testCase "000023-012.ring_trust" (testSerialization "000023-012.ring_trust")+ , testCase "000024-014.public_subkey" (testSerialization "000024-014.public_subkey")+ , testCase "000025-002.sig" (testSerialization "000025-002.sig")+ , testCase "000026-012.ring_trust" (testSerialization "000026-012.ring_trust")+ , testCase "000027-006.public_key" (testSerialization "000027-006.public_key")+ , testCase "000028-002.sig" (testSerialization "000028-002.sig")+ , testCase "000029-012.ring_trust" (testSerialization "000029-012.ring_trust")+ , testCase "000030-013.user_id" (testSerialization "000030-013.user_id")+ , testCase "000031-002.sig" (testSerialization "000031-002.sig")+ , testCase "000032-012.ring_trust" (testSerialization "000032-012.ring_trust")+ , testCase "000033-002.sig" (testSerialization "000033-002.sig")+ , testCase "000034-012.ring_trust" (testSerialization "000034-012.ring_trust")+ , testCase "000035-006.public_key" (testSerialization "000035-006.public_key")+ , testCase "000036-013.user_id" (testSerialization "000036-013.user_id")+ , testCase "000037-002.sig" (testSerialization "000037-002.sig")+ , testCase "000038-012.ring_trust" (testSerialization "000038-012.ring_trust")+ , testCase "000039-002.sig" (testSerialization "000039-002.sig")+ , testCase "000040-012.ring_trust" (testSerialization "000040-012.ring_trust")+ , testCase "000041-017.attribute" (testSerialization "000041-017.attribute")+ , testCase "000042-002.sig" (testSerialization "000042-002.sig")+ , testCase "000043-012.ring_trust" (testSerialization "000043-012.ring_trust")+ , testCase "000044-014.public_subkey" (testSerialization "000044-014.public_subkey")+ , testCase "000045-002.sig" (testSerialization "000045-002.sig")+ , testCase "000046-012.ring_trust" (testSerialization "000046-012.ring_trust")+ , testCase "000047-005.secret_key" (testSerialization "000047-005.secret_key")+ , testCase "000048-013.user_id" (testSerialization "000048-013.user_id")+ , testCase "000049-002.sig" (testSerialization "000049-002.sig")+ , testCase "000050-012.ring_trust" (testSerialization "000050-012.ring_trust")+ , testCase "000051-007.secret_subkey" (testSerialization "000051-007.secret_subkey")+ , testCase "000052-002.sig" (testSerialization "000052-002.sig")+ , testCase "000053-012.ring_trust" (testSerialization "000053-012.ring_trust")+ , testCase "000054-005.secret_key" (testSerialization "000054-005.secret_key")+ , testCase "000055-002.sig" (testSerialization "000055-002.sig")+ , testCase "000056-012.ring_trust" (testSerialization "000056-012.ring_trust")+ , testCase "000057-013.user_id" (testSerialization "000057-013.user_id")+ , testCase "000058-002.sig" (testSerialization "000058-002.sig")+ , testCase "000059-012.ring_trust" (testSerialization "000059-012.ring_trust")+ , testCase "000060-007.secret_subkey" (testSerialization "000060-007.secret_subkey")+ , testCase "000061-002.sig" (testSerialization "000061-002.sig")+ , testCase "000062-012.ring_trust" (testSerialization "000062-012.ring_trust")+ , testCase "000063-005.secret_key" (testSerialization "000063-005.secret_key")+ , testCase "000064-002.sig" (testSerialization "000064-002.sig")+ , testCase "000065-012.ring_trust" (testSerialization "000065-012.ring_trust")+ , testCase "000066-013.user_id" (testSerialization "000066-013.user_id")+ , testCase "000067-002.sig" (testSerialization "000067-002.sig")+ , testCase "000068-012.ring_trust" (testSerialization "000068-012.ring_trust")+ , testCase "000069-005.secret_key" (testSerialization "000069-005.secret_key")+ , testCase "000070-013.user_id" (testSerialization "000070-013.user_id")+ , testCase "000071-002.sig" (testSerialization "000071-002.sig")+ , testCase "000072-012.ring_trust" (testSerialization "000072-012.ring_trust")+ , testCase "000073-017.attribute" (testSerialization "000073-017.attribute")+ , testCase "000074-002.sig" (testSerialization "000074-002.sig")+ , testCase "000075-012.ring_trust" (testSerialization "000075-012.ring_trust")+ , testCase "000076-007.secret_subkey" (testSerialization "000076-007.secret_subkey")+ , testCase "000077-002.sig" (testSerialization "000077-002.sig")+ , testCase "000078-012.ring_trust" (testSerialization "000078-012.ring_trust")+ , testCase "pubring.gpg" (testSerialization "pubring.gpg")+ , testCase "secring.gpg" (testSerialization "secring.gpg")+ ]++-- main = runTestTT tests++-- specs :: Specs+-- specs = describe "Round-trip serialization" [it "000001-006.public_key" (testSerialization "000001-006.public_key")+--   , it "000002-013.user_id" (testSerialization "000002-013.user_id")+--   , it "000003-002.sig" (testSerialization "000003-002.sig")+--   , it "000004-012.ring_trust" (testSerialization "000004-012.ring_trust")+--   , it "000005-014.public_subkey" (testSerialization "000005-014.public_subkey")+--   , it "000006-002.sig" (testSerialization "000006-002.sig")+--   , it "000007-012.ring_trust" (testSerialization "000007-012.ring_trust")+--   , it "000008-006.public_key" (testSerialization "000008-006.public_key")+--   , it "000009-013.user_id" (testSerialization "000009-013.user_id")+--   , it "000010-002.sig" (testSerialization "000010-002.sig")+--   , it "000011-012.ring_trust" (testSerialization "000011-012.ring_trust")+--   , it "000012-014.public_subkey" (testSerialization "000012-014.public_subkey")+--   , it "000013-002.sig" (testSerialization "000013-002.sig")+--   , it "000014-012.ring_trust" (testSerialization "000014-012.ring_trust")+--   , it "000015-006.public_key" (testSerialization "000015-006.public_key")+--   , it "000016-013.user_id" (testSerialization "000016-013.user_id")+--   , it "000017-002.sig" (testSerialization "000017-002.sig")+--   , it "000018-012.ring_trust" (testSerialization "000018-012.ring_trust")+--   , it "000019-006.public_key" (testSerialization "000019-006.public_key")+--   , it "000020-013.user_id" (testSerialization "000020-013.user_id")+--   , it "000021-002.sig" (testSerialization "000021-002.sig")+--   , it "000022-012.ring_trust" (testSerialization "000022-012.ring_trust")+--   , it "000023-005.secret_key" (testSerialization "000023-005.secret_key")+--   , it "000024-013.user_id" (testSerialization "000024-013.user_id")+--   , it "000025-002.sig" (testSerialization "000025-002.sig")+--   , it "000026-012.ring_trust" (testSerialization "000026-012.ring_trust")+--   , it "000027-007.secret_subkey" (testSerialization "000027-007.secret_subkey")+--   , it "000028-002.sig" (testSerialization "000028-002.sig")+--   , it "000029-012.ring_trust" (testSerialization "000029-012.ring_trust")+--   , it "000030-005.secret_key" (testSerialization "000030-005.secret_key")+--   , it "000031-013.user_id" (testSerialization "000031-013.user_id")+--   , it "000032-002.sig" (testSerialization "000032-002.sig")+--   , it "000033-012.ring_trust" (testSerialization "000033-012.ring_trust")+--   , it "000034-007.secret_subkey" (testSerialization "000034-007.secret_subkey")+--   , it "000035-002.sig" (testSerialization "000035-002.sig")+--   , it "000036-012.ring_trust" (testSerialization "000036-012.ring_trust")+--   , it "000037-005.secret_key" (testSerialization "000037-005.secret_key")+--   , it "000038-013.user_id" (testSerialization "000038-013.user_id")+--   , it "000039-002.sig" (testSerialization "000039-002.sig")+--   , it "000040-012.ring_trust" (testSerialization "000040-012.ring_trust")+--   , it "000041-005.secret_key" (testSerialization "000041-005.secret_key")+--   , it "000042-013.user_id" (testSerialization "000042-013.user_id")+--   , it "000043-002.sig" (testSerialization "000043-002.sig")+--   , it "000044-012.ring_trust" (testSerialization "000044-012.ring_trust")+--   , it "pubring.gpg" (testSerialization "pubring.gpg")+--   , it "secring.gpg" (testSerialization "secring.gpg")+--   ]++-- main = hspec specs++main = defaultMain tests