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 +823/−0
- Codec/Encryption/OpenPGP/Types.hs +520/−0
- LICENSE +19/−0
- Setup.hs +2/−0
- hOpenPGP.cabal +121/−0
- tests/data/000001-006.public_key binary
- tests/data/000002-013.user_id +1/−0
- tests/data/000003-002.sig binary
- tests/data/000004-012.ring_trust binary
- tests/data/000005-002.sig binary
- tests/data/000006-012.ring_trust binary
- tests/data/000007-002.sig binary
- tests/data/000008-012.ring_trust binary
- tests/data/000009-002.sig binary
- tests/data/000010-012.ring_trust binary
- tests/data/000011-002.sig binary
- tests/data/000012-012.ring_trust binary
- tests/data/000013-014.public_subkey binary
- tests/data/000014-002.sig binary
- tests/data/000015-012.ring_trust binary
- tests/data/000016-006.public_key binary
- tests/data/000017-002.sig binary
- tests/data/000018-012.ring_trust binary
- tests/data/000019-013.user_id +1/−0
- tests/data/000020-002.sig binary
- tests/data/000021-012.ring_trust binary
- tests/data/000022-002.sig binary
- tests/data/000023-012.ring_trust binary
- tests/data/000024-014.public_subkey binary
- tests/data/000025-002.sig binary
- tests/data/000026-012.ring_trust binary
- tests/data/000027-006.public_key binary
- tests/data/000028-002.sig binary
- tests/data/000029-012.ring_trust binary
- tests/data/000030-013.user_id +1/−0
- tests/data/000031-002.sig binary
- tests/data/000032-012.ring_trust binary
- tests/data/000033-002.sig binary
- tests/data/000034-012.ring_trust binary
- tests/data/000035-006.public_key binary
- tests/data/000036-013.user_id +1/−0
- tests/data/000037-002.sig binary
- tests/data/000038-012.ring_trust binary
- tests/data/000039-002.sig binary
- tests/data/000040-012.ring_trust binary
- tests/data/000041-017.attribute binary
- tests/data/000042-002.sig binary
- tests/data/000043-012.ring_trust binary
- tests/data/000044-014.public_subkey binary
- tests/data/000045-002.sig binary
- tests/data/000046-012.ring_trust binary
- tests/data/000047-005.secret_key binary
- tests/data/000048-013.user_id +1/−0
- tests/data/000049-002.sig binary
- tests/data/000050-012.ring_trust binary
- tests/data/000051-007.secret_subkey binary
- tests/data/000052-002.sig binary
- tests/data/000053-012.ring_trust binary
- tests/data/000054-005.secret_key binary
- tests/data/000055-002.sig binary
- tests/data/000056-012.ring_trust binary
- tests/data/000057-013.user_id +1/−0
- tests/data/000058-002.sig binary
- tests/data/000059-012.ring_trust binary
- tests/data/000060-007.secret_subkey binary
- tests/data/000061-002.sig binary
- tests/data/000062-012.ring_trust binary
- tests/data/000063-005.secret_key binary
- tests/data/000064-002.sig binary
- tests/data/000065-012.ring_trust binary
- tests/data/000066-013.user_id +1/−0
- tests/data/000067-002.sig binary
- tests/data/000068-012.ring_trust binary
- tests/data/000069-005.secret_key binary
- tests/data/000070-013.user_id +1/−0
- tests/data/000071-002.sig binary
- tests/data/000072-012.ring_trust binary
- tests/data/000073-017.attribute binary
- tests/data/000074-002.sig binary
- tests/data/000075-012.ring_trust binary
- tests/data/000076-007.secret_subkey binary
- tests/data/000077-002.sig binary
- tests/data/000078-012.ring_trust binary
- tests/data/pubring.gpg binary
- tests/data/secring.gpg binary
- tests/suite.hs +159/−0
@@ -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
@@ -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++
@@ -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.
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
@@ -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
binary file changed (absent → 171 bytes)
@@ -0,0 +1,1 @@+´$Test Key (RSA) <testkey@example.org>
binary file changed (absent → 113 bytes)
binary file changed (absent → 4 bytes)
binary file changed (absent → 113 bytes)
binary file changed (absent → 4 bytes)
binary file changed (absent → 220 bytes)
binary file changed (absent → 4 bytes)
binary file changed (absent → 158 bytes)
binary file changed (absent → 4 bytes)
binary file changed (absent → 96 bytes)
binary file changed (absent → 4 bytes)
binary file changed (absent → 171 bytes)
binary file changed (absent → 195 bytes)
binary file changed (absent → 4 bytes)
binary file changed (absent → 1201 bytes)
binary file changed (absent → 123 bytes)
binary file changed (absent → 4 bytes)
@@ -0,0 +1,1 @@+´$Test Key (DSA) <testkey@example.com>
binary file changed (absent → 130 bytes)
binary file changed (absent → 4 bytes)
binary file changed (absent → 186 bytes)
binary file changed (absent → 4 bytes)
binary file changed (absent → 608 bytes)
binary file changed (absent → 105 bytes)
binary file changed (absent → 4 bytes)
binary file changed (absent → 421 bytes)
binary file changed (absent → 99 bytes)
binary file changed (absent → 4 bytes)
@@ -0,0 +1,1 @@+´+Test Key (DSA sign-only) <test@example.net>
binary file changed (absent → 132 bytes)
binary file changed (absent → 4 bytes)
binary file changed (absent → 96 bytes)
binary file changed (absent → 4 bytes)
binary file changed (absent → 143 bytes)
@@ -0,0 +1,1 @@+´.Test Key (RSA sign-only) <testkey@example.net>
binary file changed (absent → 192 bytes)
binary file changed (absent → 4 bytes)
binary file changed (absent → 72 bytes)
binary file changed (absent → 4 bytes)
binary file changed (absent → 1761 bytes)
binary file changed (absent → 192 bytes)
binary file changed (absent → 4 bytes)
binary file changed (absent → 272 bytes)
binary file changed (absent → 161 bytes)
binary file changed (absent → 4 bytes)
binary file changed (absent → 610 bytes)
@@ -0,0 +1,1 @@+´$Test Key (RSA) <testkey@example.org>
binary file changed (absent → 220 bytes)
binary file changed (absent → 4 bytes)
binary file changed (absent → 611 bytes)
binary file changed (absent → 195 bytes)
binary file changed (absent → 4 bytes)
binary file changed (absent → 1275 bytes)
binary file changed (absent → 123 bytes)
binary file changed (absent → 4 bytes)
@@ -0,0 +1,1 @@+´$Test Key (DSA) <testkey@example.com>
binary file changed (absent → 130 bytes)
binary file changed (absent → 4 bytes)
binary file changed (absent → 698 bytes)
binary file changed (absent → 104 bytes)
binary file changed (absent → 4 bytes)
binary file changed (absent → 484 bytes)
binary file changed (absent → 99 bytes)
binary file changed (absent → 4 bytes)
@@ -0,0 +1,1 @@+´+Test Key (DSA sign-only) <test@example.net>
binary file changed (absent → 106 bytes)
binary file changed (absent → 4 bytes)
binary file changed (absent → 513 bytes)
@@ -0,0 +1,1 @@+´.Test Key (RSA sign-only) <testkey@example.net>
binary file changed (absent → 192 bytes)
binary file changed (absent → 4 bytes)
binary file changed (absent → 1761 bytes)
binary file changed (absent → 192 bytes)
binary file changed (absent → 4 bytes)
binary file changed (absent → 961 bytes)
binary file changed (absent → 161 bytes)
binary file changed (absent → 4 bytes)
binary file changed (absent → 7368 bytes)
binary file changed (absent → 8644 bytes)
@@ -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