diff options
author | Clint Adams <clint@softwarefreedom.org> | 2012-04-26 16:29:50 -0400 |
---|---|---|
committer | Clint Adams <clint@softwarefreedom.org> | 2012-04-26 16:29:50 -0400 |
commit | 716dd382221343e5da5daf1a9a8ac40304a7d74b (patch) | |
tree | 0a2b7bed56f9ec6564d4a9e918ab4e8fd53c0dc5 /Codec | |
parent | d17ea2bb11255f7e6ae9069d3b58e8f06d5946a5 (diff) |
Codec for "Cleartext Signatures"
Diffstat (limited to 'Codec')
-rw-r--r-- | Codec/Encryption/OpenPGP/ASCIIArmor/Decode.hs | 32 | ||||
-rw-r--r-- | Codec/Encryption/OpenPGP/ASCIIArmor/Encode.hs | 10 | ||||
-rw-r--r-- | Codec/Encryption/OpenPGP/ASCIIArmor/Types.hs | 2 | ||||
-rw-r--r-- | Codec/Encryption/OpenPGP/ASCIIArmor/Utils.hs | 17 |
4 files changed, 56 insertions, 5 deletions
diff --git a/Codec/Encryption/OpenPGP/ASCIIArmor/Decode.hs b/Codec/Encryption/OpenPGP/ASCIIArmor/Decode.hs index 0376abc..b0033a8 100644 --- a/Codec/Encryption/OpenPGP/ASCIIArmor/Decode.hs +++ b/Codec/Encryption/OpenPGP/ASCIIArmor/Decode.hs | |||
@@ -10,7 +10,8 @@ module Codec.Encryption.OpenPGP.ASCIIArmor.Decode ( | |||
10 | ) where | 10 | ) where |
11 | 11 | ||
12 | import Codec.Encryption.OpenPGP.ASCIIArmor.Types | 12 | import Codec.Encryption.OpenPGP.ASCIIArmor.Types |
13 | import Control.Applicative (many, (<|>), (<$>), Alternative, (*>)) | 13 | import Codec.Encryption.OpenPGP.ASCIIArmor.Utils |
14 | import Control.Applicative (many, (<|>), (<$>), Alternative, (<*), (<*>), (*>), optional) | ||
14 | import Data.Attoparsec.ByteString (Parser, many1, string, inClass, notInClass, satisfy, word8, (<?>), parse, IResult(..)) | 15 | import Data.Attoparsec.ByteString (Parser, many1, string, inClass, notInClass, satisfy, word8, (<?>), parse, IResult(..)) |
15 | import Data.Attoparsec.ByteString.Char8 (isDigit_w8, anyChar) | 16 | import Data.Attoparsec.ByteString.Char8 (isDigit_w8, anyChar) |
16 | import Data.Attoparsec.Combinator (manyTill) | 17 | import Data.Attoparsec.Combinator (manyTill) |
@@ -37,8 +38,21 @@ parseArmors :: Parser [Armor] | |||
37 | parseArmors = many parseArmor | 38 | parseArmors = many parseArmor |
38 | 39 | ||
39 | parseArmor :: Parser Armor | 40 | parseArmor :: Parser Armor |
40 | parseArmor = do | 41 | parseArmor = prefixed (clearsigned <|> armor) <?> "armor" |
41 | atype <- prefixed beginLine <?> "begin line" | 42 | |
43 | clearsigned :: Parser Armor | ||
44 | clearsigned = do | ||
45 | string "-----BEGIN PGP SIGNED MESSAGE-----" <?> "clearsign header" | ||
46 | lineEnding <?> "line ending" | ||
47 | headers <- armorHeaders <?> "clearsign headers" | ||
48 | blankishLine <?> "blank line" | ||
49 | cleartext <- dashEscapedCleartext | ||
50 | sig <- armor | ||
51 | return $ ClearSigned headers cleartext sig | ||
52 | |||
53 | armor :: Parser Armor | ||
54 | armor = do | ||
55 | atype <- beginLine <?> "begin line" | ||
42 | headers <- armorHeaders <?> "headers" | 56 | headers <- armorHeaders <?> "headers" |
43 | blankishLine <?> "blank line" | 57 | blankishLine <?> "blank line" |
44 | payload <- base64Data <?> "base64 data" | 58 | payload <- base64Data <?> "base64 data" |
@@ -84,7 +98,7 @@ armorHeader = do | |||
84 | w8sToString = BC8.unpack . B.pack | 98 | w8sToString = BC8.unpack . B.pack |
85 | 99 | ||
86 | blankishLine :: Parser ByteString | 100 | blankishLine :: Parser ByteString |
87 | blankishLine = many (satisfy (inClass " \t")) >> lineEnding | 101 | blankishLine = many (satisfy (inClass " \t")) *> lineEnding |
88 | 102 | ||
89 | endLine :: ArmorType -> Parser ByteString | 103 | endLine :: ArmorType -> Parser ByteString |
90 | endLine atype = do | 104 | endLine atype = do |
@@ -138,3 +152,13 @@ d24 = do | |||
138 | 152 | ||
139 | prefixed :: Parser a -> Parser a | 153 | prefixed :: Parser a -> Parser a |
140 | prefixed end = end <|> anyChar *> prefixed end | 154 | prefixed end = end <|> anyChar *> prefixed end |
155 | |||
156 | dashEscapedCleartext :: Parser ByteString | ||
157 | dashEscapedCleartext = do | ||
158 | ls <- many1 ((deLine <|> unescapedLine) <* lineEnding) | ||
159 | return $ crlfUnlines ls | ||
160 | where | ||
161 | deLine :: Parser ByteString | ||
162 | deLine = B.pack <$> (string "- " *> many (satisfy (notInClass "\n\r"))) | ||
163 | unescapedLine :: Parser ByteString | ||
164 | unescapedLine = maybe B.empty B.pack <$> optional ((:) <$> satisfy (notInClass "-\n\r") <*> many (satisfy (notInClass "\n\r"))) | ||
diff --git a/Codec/Encryption/OpenPGP/ASCIIArmor/Encode.hs b/Codec/Encryption/OpenPGP/ASCIIArmor/Encode.hs index 28bb3e6..00d9dd3 100644 --- a/Codec/Encryption/OpenPGP/ASCIIArmor/Encode.hs +++ b/Codec/Encryption/OpenPGP/ASCIIArmor/Encode.hs | |||
@@ -22,6 +22,7 @@ encode = B.concat . map armor | |||
22 | 22 | ||
23 | armor :: Armor -> ByteString | 23 | armor :: Armor -> ByteString |
24 | armor (Armor atype ahs bs) = beginLine atype `B.append` armorHeaders ahs `B.append` blankLine `B.append` armorData bs `B.append` armorChecksum bs `B.append` endLine atype | 24 | armor (Armor atype ahs bs) = beginLine atype `B.append` armorHeaders ahs `B.append` blankLine `B.append` armorData bs `B.append` armorChecksum bs `B.append` endLine atype |
25 | armor (ClearSigned chs ctxt csig) = BC8.pack "-----BEGIN PGP SIGNED MESSAGE-----\n" `B.append` armorHeaders chs `B.append` blankLine `B.append` dashEscape ctxt `B.append` armor csig | ||
25 | 26 | ||
26 | blankLine :: ByteString | 27 | blankLine :: ByteString |
27 | blankLine = BC8.singleton '\n' | 28 | blankLine = BC8.singleton '\n' |
@@ -57,3 +58,12 @@ wordWrap lw bs | |||
57 | 58 | ||
58 | armorChecksum :: ByteString -> ByteString | 59 | armorChecksum :: ByteString -> ByteString |
59 | armorChecksum = BC8.cons '=' . armorData . B.tail . runPut . putWord32be . crc24 | 60 | armorChecksum = BC8.cons '=' . armorData . B.tail . runPut . putWord32be . crc24 |
61 | |||
62 | dashEscape :: ByteString -> ByteString | ||
63 | dashEscape = BC8.unlines . map escapeLine . BC8.lines | ||
64 | where | ||
65 | escapeLine :: ByteString -> ByteString | ||
66 | escapeLine l | ||
67 | | BC8.singleton '-' `B.isPrefixOf` l = BC8.pack "- " `B.append` l | ||
68 | | BC8.pack "From " `B.isPrefixOf` l = BC8.pack "- " `B.append` l | ||
69 | | otherwise = l | ||
diff --git a/Codec/Encryption/OpenPGP/ASCIIArmor/Types.hs b/Codec/Encryption/OpenPGP/ASCIIArmor/Types.hs index 46416c1..88a03ce 100644 --- a/Codec/Encryption/OpenPGP/ASCIIArmor/Types.hs +++ b/Codec/Encryption/OpenPGP/ASCIIArmor/Types.hs | |||
@@ -11,7 +11,7 @@ module Codec.Encryption.OpenPGP.ASCIIArmor.Types ( | |||
11 | import Data.ByteString (ByteString) | 11 | import Data.ByteString (ByteString) |
12 | 12 | ||
13 | data Armor = Armor ArmorType [(String, String)] ByteString | 13 | data Armor = Armor ArmorType [(String, String)] ByteString |
14 | | ClearSigned [(String, String)] String Armor | 14 | | ClearSigned [(String, String)] ByteString Armor |
15 | deriving (Show, Eq) | 15 | deriving (Show, Eq) |
16 | 16 | ||
17 | data ArmorType = ArmorMessage | 17 | data ArmorType = ArmorMessage |
diff --git a/Codec/Encryption/OpenPGP/ASCIIArmor/Utils.hs b/Codec/Encryption/OpenPGP/ASCIIArmor/Utils.hs new file mode 100644 index 0000000..014c8aa --- /dev/null +++ b/Codec/Encryption/OpenPGP/ASCIIArmor/Utils.hs | |||
@@ -0,0 +1,17 @@ | |||
1 | -- ASCIIArmor/Utils.hs: OpenPGP (RFC4880) ASCII armor implementation | ||
2 | -- Copyright Ⓒ 2012 Clint Adams | ||
3 | -- This software is released under the terms of the ISC license. | ||
4 | -- (See the LICENSE file). | ||
5 | |||
6 | module Codec.Encryption.OpenPGP.ASCIIArmor.Utils ( | ||
7 | crlfUnlines | ||
8 | ) where | ||
9 | |||
10 | import Data.ByteString (ByteString) | ||
11 | import qualified Data.ByteString as B | ||
12 | import qualified Data.ByteString.Char8 as BC8 | ||
13 | import Data.List (intersperse) | ||
14 | |||
15 | crlfUnlines :: [ByteString] -> ByteString | ||
16 | crlfUnlines [] = B.empty | ||
17 | crlfUnlines ss = B.concat $ intersperse (BC8.pack "\r\n") ss | ||