summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Paul Weber <singpolyma@singpolyma.net>2012-04-25 17:19:07 -0500
committerStephen Paul Weber <singpolyma@singpolyma.net>2012-04-25 17:19:07 -0500
commit6b743222684f2b8151dfbdef42f0dc890e590c41 (patch)
tree77b5ae031d2b863f03399ba9a5b56ba4478d2ab2
parent7b3232778f284dd4dd3a6f3287bcbe1fbe10b010 (diff)
Split OpenPGP.Crypto out into a seperate package
-rw-r--r--Data/OpenPGP/Crypto.hs183
-rw-r--r--Makefile23
-rw-r--r--README8
-rw-r--r--debian/control27
-rw-r--r--examples/keygen.hs43
-rw-r--r--examples/sign.hs23
-rw-r--r--examples/verify.hs14
-rw-r--r--openpgp.cabal22
-rw-r--r--tests/data/encryption-sym-aes256.gpg1
-rw-r--r--tests/data/encryption-sym-cast5.gpgbin72 -> 0 bytes
-rw-r--r--tests/data/encryption.gpgbin860 -> 0 bytes
-rw-r--r--tests/data/msg1.asc7
-rw-r--r--tests/suite.hs57
13 files changed, 28 insertions, 380 deletions
diff --git a/Data/OpenPGP/Crypto.hs b/Data/OpenPGP/Crypto.hs
deleted file mode 100644
index 54fb81e..0000000
--- a/Data/OpenPGP/Crypto.hs
+++ /dev/null
@@ -1,183 +0,0 @@
1-- | This is a wrapper around <http://hackage.haskell.org/package/Crypto>
2-- that currently does fingerprint generation and signature verification.
3--
4-- The recommended way to import this module is:
5--
6-- > import qualified Data.OpenPGP.Crypto as OpenPGP
7module Data.OpenPGP.Crypto (sign, verify, fingerprint) where
8
9import Numeric
10import Data.Word
11import Data.Char
12import Data.List (find)
13import Data.Map ((!))
14import qualified Data.ByteString.Lazy as LZ
15import qualified Data.ByteString.Lazy.UTF8 as LZ (fromString)
16
17import Data.Binary
18import Codec.Utils (fromOctets)
19import qualified Codec.Encryption.RSA as RSA
20import qualified Data.Digest.MD5 as MD5
21import qualified Data.Digest.SHA1 as SHA1
22import qualified Data.Digest.SHA256 as SHA256
23import qualified Data.Digest.SHA384 as SHA384
24import qualified Data.Digest.SHA512 as SHA512
25
26import qualified Data.OpenPGP as OpenPGP
27
28-- | Generate a key fingerprint from a PublicKeyPacket or SecretKeyPacket
29-- <http://tools.ietf.org/html/rfc4880#section-12.2>
30fingerprint :: OpenPGP.Packet -> String
31fingerprint p
32 | OpenPGP.version p == 4 =
33 map toUpper $ (`showHex` "") $ SHA1.toInteger $ SHA1.hash $
34 LZ.unpack (LZ.concat (OpenPGP.fingerprint_material p))
35 | OpenPGP.version p `elem` [2, 3] =
36 map toUpper $ foldr (pad `oo` showHex) "" $
37 MD5.hash $ LZ.unpack (LZ.concat (OpenPGP.fingerprint_material p))
38 | otherwise = error "Unsupported Packet version or type in fingerprint"
39 where
40 oo = (.) . (.)
41 pad s | odd $ length s = '0':s
42 | otherwise = s
43
44find_key :: OpenPGP.Message -> String -> Maybe OpenPGP.Packet
45find_key (OpenPGP.Message (x@(OpenPGP.PublicKeyPacket {}):xs)) keyid =
46 find_key_ x xs keyid
47find_key (OpenPGP.Message (x@(OpenPGP.SecretKeyPacket {}):xs)) keyid =
48 find_key_ x xs keyid
49find_key (OpenPGP.Message (_:xs)) keyid =
50 find_key (OpenPGP.Message xs) keyid
51find_key _ _ = Nothing
52
53find_key_ :: OpenPGP.Packet -> [OpenPGP.Packet] -> String -> Maybe OpenPGP.Packet
54find_key_ x xs keyid
55 | thisid == keyid = Just x
56 | otherwise = find_key (OpenPGP.Message xs) keyid
57 where
58 thisid = reverse $ take (length keyid) (reverse (fingerprint x))
59
60keyfield_as_octets :: OpenPGP.Packet -> Char -> [Word8]
61keyfield_as_octets k f =
62 LZ.unpack $ LZ.drop 2 (encode (k' ! f))
63 where k' = OpenPGP.key k
64
65-- http://tools.ietf.org/html/rfc3447#page-43
66emsa_pkcs1_v1_5_hash_padding :: OpenPGP.HashAlgorithm -> [Word8]
67emsa_pkcs1_v1_5_hash_padding OpenPGP.MD5 = [0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10]
68emsa_pkcs1_v1_5_hash_padding OpenPGP.SHA1 = [0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14]
69emsa_pkcs1_v1_5_hash_padding OpenPGP.SHA256 = [0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20]
70emsa_pkcs1_v1_5_hash_padding OpenPGP.SHA384 = [0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30]
71emsa_pkcs1_v1_5_hash_padding OpenPGP.SHA512 = [0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40]
72emsa_pkcs1_v1_5_hash_padding _ =
73 error "Unsupported HashAlgorithm in emsa_pkcs1_v1_5_hash_padding."
74
75hash :: OpenPGP.HashAlgorithm -> [Word8] -> [Word8]
76hash OpenPGP.MD5 = MD5.hash
77hash OpenPGP.SHA1 = drop 2 . LZ.unpack . encode . OpenPGP.MPI . SHA1.toInteger . SHA1.hash
78hash OpenPGP.SHA256 = SHA256.hash
79hash OpenPGP.SHA384 = SHA384.hash
80hash OpenPGP.SHA512 = SHA512.hash
81hash _ = error "Unsupported HashAlgorithm in hash."
82
83emsa_pkcs1_v1_5_encode :: [Word8] -> Int -> OpenPGP.HashAlgorithm -> [Word8]
84emsa_pkcs1_v1_5_encode m emLen algo =
85 [0, 1] ++ replicate (emLen - length t - 3) 0xff ++ [0] ++ t
86 where t = emsa_pkcs1_v1_5_hash_padding algo ++ hash algo m
87
88-- | Verify a message signature. Only supports RSA keys for now.
89verify :: OpenPGP.Message -- ^ Keys that may have made the signature
90 -> OpenPGP.Message -- ^ LiteralData message to verify
91 -> Int -- ^ Index of signature to verify (0th, 1st, etc)
92 -> Bool
93verify keys message sigidx =
94 encoded == RSA.encrypt (n, e) raw_sig
95 where
96 raw_sig = LZ.unpack $ LZ.drop 2 $ encode (OpenPGP.signature sig)
97 encoded = emsa_pkcs1_v1_5_encode signature_over
98 (length n) (OpenPGP.hash_algorithm sig)
99 signature_over = LZ.unpack $ dta `LZ.append` OpenPGP.trailer sig
100 (n, e) = (keyfield_as_octets k 'n', keyfield_as_octets k 'e')
101 Just k = find_key keys issuer
102 Just issuer = OpenPGP.signature_issuer sig
103 sig = sigs !! sigidx
104 (sigs, (OpenPGP.LiteralDataPacket {OpenPGP.content = dta}):_) =
105 OpenPGP.signatures_and_data message
106
107-- | Sign data or key/userID pair. Only supports RSA keys for now.
108sign :: OpenPGP.Message -- ^ SecretKeys, one of which will be used
109 -> OpenPGP.Message -- ^ Message containing data or key to sign, and optional signature packet
110 -> OpenPGP.HashAlgorithm -- ^ HashAlgorithm to use in signature
111 -> String -- ^ KeyID of key to choose or @[]@ for first
112 -> Integer -- ^ Timestamp for signature (unless sig supplied)
113 -> OpenPGP.Packet
114sign keys message hsh keyid timestamp =
115 -- WARNING: this style of update is unsafe on most fields
116 -- it is safe on signature and hash_head, though
117 sig {
118 OpenPGP.signature = OpenPGP.MPI $ toNum final,
119 OpenPGP.hash_head = toNum $ take 2 final
120 }
121 where
122 -- toNum has explicit param so that it can remain polymorphic
123 toNum l = fromOctets (256::Integer) l
124 final = dropWhile (==0) $ RSA.decrypt (n, d) encoded
125 encoded = emsa_pkcs1_v1_5_encode dta (length n) hsh
126 (n, d) = (keyfield_as_octets k 'n', keyfield_as_octets k 'd')
127 dta = LZ.unpack $ case signOver of {
128 OpenPGP.LiteralDataPacket {OpenPGP.content = c} -> c;
129 _ -> LZ.concat $ OpenPGP.fingerprint_material signOver ++ [
130 LZ.singleton 0xB4,
131 encode (fromIntegral (length firstUserID) :: Word32),
132 LZ.fromString firstUserID
133 ]
134 } `LZ.append` OpenPGP.trailer sig
135 sig = findSigOrDefault (find OpenPGP.isSignaturePacket m)
136
137 -- Either a SignaturePacket was found, or we need to make one
138 findSigOrDefault (Just s) = OpenPGP.signaturePacket
139 (OpenPGP.version s)
140 (OpenPGP.signature_type s)
141 OpenPGP.RSA -- force key and hash algorithm
142 hsh
143 (OpenPGP.hashed_subpackets s)
144 (OpenPGP.unhashed_subpackets s)
145 (OpenPGP.hash_head s)
146 (OpenPGP.signature s)
147 findSigOrDefault Nothing = OpenPGP.signaturePacket
148 4
149 defaultStype
150 OpenPGP.RSA
151 hsh
152 ([
153 -- Do we really need to pass in timestamp just for the default?
154 OpenPGP.SignatureCreationTimePacket $ fromIntegral timestamp,
155 OpenPGP.IssuerPacket keyid'
156 ] ++ (case signOver of
157 OpenPGP.LiteralDataPacket {} -> []
158 _ -> [] -- TODO: OpenPGP.KeyFlagsPacket [0x01, 0x02]
159 ))
160 []
161 undefined
162 undefined
163
164 keyid' = reverse $ take 16 $ reverse $ fingerprint k
165 Just k = find_key keys keyid
166
167 Just (OpenPGP.UserIDPacket firstUserID) = find isUserID m
168
169 defaultStype = case signOver of
170 OpenPGP.LiteralDataPacket {OpenPGP.format = f} ->
171 if f == 'b' then 0x00 else 0x01
172 _ -> 0x13
173
174 Just signOver = find isSignable m
175 OpenPGP.Message m = message
176
177 isSignable (OpenPGP.LiteralDataPacket {}) = True
178 isSignable (OpenPGP.PublicKeyPacket {}) = True
179 isSignable (OpenPGP.SecretKeyPacket {}) = True
180 isSignable _ = False
181
182 isUserID (OpenPGP.UserIDPacket {}) = True
183 isUserID _ = False
diff --git a/Makefile b/Makefile
index 10f66fa..85dc9db 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@ VERSION=0.3
4 4
5.PHONY: all clean doc install debian test 5.PHONY: all clean doc install debian test
6 6
7all: sign verify keygen test report.html doc dist/build/libHSopenpgp-$(VERSION).a dist/openpgp-$(VERSION).tar.gz 7all: test report.html doc dist/build/libHSopenpgp-$(VERSION).a dist/openpgp-$(VERSION).tar.gz
8 8
9install: dist/build/libHSopenpgp-$(VERSION).a 9install: dist/build/libHSopenpgp-$(VERSION).a
10 cabal install 10 cabal install
@@ -14,20 +14,11 @@ debian: debian/control
14test: tests/suite 14test: tests/suite
15 tests/suite 15 tests/suite
16 16
17sign: examples/sign.hs Data/*.hs Data/OpenPGP/*.hs 17tests/suite: tests/suite.hs Data/OpenPGP.hs
18 ghc --make $(GHCFLAGS) -o $@ $^ 18 ghc --make $(GHCFLAGS) -o $@ $^
19 19
20verify: examples/verify.hs Data/*.hs Data/OpenPGP/*.hs 20report.html: Data/OpenPGP.hs tests/suite.hs
21 ghc --make $(GHCFLAGS) -o $@ $^ 21 -hlint $(HLINTFLAGS) --report $^
22
23keygen: examples/keygen.hs Data/*.hs Data/OpenPGP/*.hs
24 ghc --make $(GHCFLAGS) -o $@ $^
25
26tests/suite: tests/suite.hs Data/*.hs Data/OpenPGP/*.hs
27 ghc --make $(GHCFLAGS) -o $@ $^
28
29report.html: examples/*.hs Data/*.hs Data/OpenPGP/*.hs tests/*.hs
30 -hlint $(HLINTFLAGS) --report Data examples
31 22
32doc: dist/doc/html/openpgp/index.html README 23doc: dist/doc/html/openpgp/index.html README
33 24
@@ -37,7 +28,7 @@ README: openpgp.cabal
37 -printf ',s/ //g\n,s/^.$$//g\nw\nq\n' | ed $@ 28 -printf ',s/ //g\n,s/^.$$//g\nw\nq\n' | ed $@
38 $(RM) .$@ 29 $(RM) .$@
39 30
40dist/doc/html/openpgp/index.html: dist/setup-config Data/OpenPGP.hs Data/OpenPGP/Crypto.hs 31dist/doc/html/openpgp/index.html: dist/setup-config Data/OpenPGP.hs
41 cabal haddock --hyperlink-source 32 cabal haddock --hyperlink-source
42 33
43dist/setup-config: openpgp.cabal 34dist/setup-config: openpgp.cabal
@@ -51,9 +42,9 @@ clean:
51debian/control: openpgp.cabal 42debian/control: openpgp.cabal
52 cabal-debian --update-debianization 43 cabal-debian --update-debianization
53 44
54dist/build/libHSopenpgp-$(VERSION).a: openpgp.cabal dist/setup-config Data/OpenPGP.hs Data/OpenPGP/Crypto.hs 45dist/build/libHSopenpgp-$(VERSION).a: openpgp.cabal dist/setup-config Data/OpenPGP.hs
55 cabal build --ghc-options="$(GHCFLAGS)" 46 cabal build --ghc-options="$(GHCFLAGS)"
56 47
57dist/openpgp-$(VERSION).tar.gz: openpgp.cabal dist/setup-config Data/OpenPGP.hs Data/OpenPGP/Crypto.hs README 48dist/openpgp-$(VERSION).tar.gz: openpgp.cabal dist/setup-config Data/OpenPGP.hs README
58 cabal check 49 cabal check
59 cabal sdist 50 cabal sdist
diff --git a/README b/README
index b5d1332..0bed65f 100644
--- a/README
+++ b/README
@@ -7,12 +7,8 @@ It defines types to represent OpenPGP messages as a series of packets
7and then defines instances of Data.Binary for each to facilitate 7and then defines instances of Data.Binary for each to facilitate
8encoding/decoding. 8encoding/decoding.
9 9
10There is also a wrapper around <http://hackage.haskell.org/package/Crypto> 10For performing cryptography, see <http://hackage.haskell.org/openpgp-Crypto>
11that currently does fingerprint generation, signature generation, and
12signature verification (for RSA keys only).
13 11
14It is intended that you use qualified imports with this library. If importing 12It is intended that you use qualified imports with this library.
15both modules, something like this will do:
16 13
17> import qualified Data.OpenPGP as OpenPGP 14> import qualified Data.OpenPGP as OpenPGP
18> import qualified Data.OpenPGP.Crypto as OpenPGP
diff --git a/debian/control b/debian/control
index a4b9165..679e316 100644
--- a/debian/control
+++ b/debian/control
@@ -7,8 +7,6 @@ Build-Depends: debhelper (>= 7.0),
7 cdbs, 7 cdbs,
8 ghc, 8 ghc,
9 ghc-prof, 9 ghc-prof,
10 libghc-crypto-dev,
11 libghc-crypto-prof,
12 libghc-binary-dev, 10 libghc-binary-dev,
13 libghc-binary-prof, 11 libghc-binary-prof,
14 libghc-bzlib-dev, 12 libghc-bzlib-dev,
@@ -18,7 +16,6 @@ Build-Depends: debhelper (>= 7.0),
18 libghc-zlib-dev, 16 libghc-zlib-dev,
19 libghc-zlib-prof 17 libghc-zlib-prof
20Build-Depends-Indep: ghc-doc, 18Build-Depends-Indep: ghc-doc,
21 libghc-crypto-doc,
22 libghc-binary-doc, 19 libghc-binary-doc,
23 libghc-bzlib-doc, 20 libghc-bzlib-doc,
24 libghc-utf8-string-doc, 21 libghc-utf8-string-doc,
@@ -44,15 +41,11 @@ Description: Implementation of the OpenPGP message format
44 and then defines instances of Data.Binary for each to facilitate 41 and then defines instances of Data.Binary for each to facilitate
45 encoding/decoding. 42 encoding/decoding.
46 . 43 .
47 There is also a wrapper around <http://hackage.haskell.org/package/Crypto> 44 For performing cryptography, see <http://hackage.haskell.org/openpgp-Crypto>
48 that currently does fingerprint generation, signature generation, and
49 signature verification (for RSA keys only).
50 . 45 .
51 It is intended that you use qualified imports with this library. If importing 46 It is intended that you use qualified imports with this library.
52 both modules, something like this will do:
53 . 47 .
54 > import qualified Data.OpenPGP as OpenPGP 48 > import qualified Data.OpenPGP as OpenPGP
55 > import qualified Data.OpenPGP.Crypto as OpenPGP
56 . 49 .
57 Author: Stephen Paul Weber <singpolyma@singpolyma.net> 50 Author: Stephen Paul Weber <singpolyma@singpolyma.net>
58 Upstream-Maintainer: Stephen Paul Weber <singpolyma@singpolyma.net> 51 Upstream-Maintainer: Stephen Paul Weber <singpolyma@singpolyma.net>
@@ -76,15 +69,11 @@ Description: Implementation of the OpenPGP message format
76 and then defines instances of Data.Binary for each to facilitate 69 and then defines instances of Data.Binary for each to facilitate
77 encoding/decoding. 70 encoding/decoding.
78 . 71 .
79 There is also a wrapper around <http://hackage.haskell.org/package/Crypto> 72 For performing cryptography, see <http://hackage.haskell.org/openpgp-Crypto>
80 that currently does fingerprint generation, signature generation, and
81 signature verification (for RSA keys only).
82 . 73 .
83 It is intended that you use qualified imports with this library. If importing 74 It is intended that you use qualified imports with this library.
84 both modules, something like this will do:
85 . 75 .
86 > import qualified Data.OpenPGP as OpenPGP 76 > import qualified Data.OpenPGP as OpenPGP
87 > import qualified Data.OpenPGP.Crypto as OpenPGP
88 . 77 .
89 Author: Stephen Paul Weber <singpolyma@singpolyma.net> 78 Author: Stephen Paul Weber <singpolyma@singpolyma.net>
90 Upstream-Maintainer: Stephen Paul Weber <singpolyma@singpolyma.net> 79 Upstream-Maintainer: Stephen Paul Weber <singpolyma@singpolyma.net>
@@ -108,15 +97,11 @@ Description: Implementation of the OpenPGP message format
108 and then defines instances of Data.Binary for each to facilitate 97 and then defines instances of Data.Binary for each to facilitate
109 encoding/decoding. 98 encoding/decoding.
110 . 99 .
111 There is also a wrapper around <http://hackage.haskell.org/package/Crypto> 100 For performing cryptography, see <http://hackage.haskell.org/openpgp-Crypto>
112 that currently does fingerprint generation, signature generation, and
113 signature verification (for RSA keys only).
114 . 101 .
115 It is intended that you use qualified imports with this library. If importing 102 It is intended that you use qualified imports with this library.
116 both modules, something like this will do:
117 . 103 .
118 > import qualified Data.OpenPGP as OpenPGP 104 > import qualified Data.OpenPGP as OpenPGP
119 > import qualified Data.OpenPGP.Crypto as OpenPGP
120 . 105 .
121 Author: Stephen Paul Weber <singpolyma@singpolyma.net> 106 Author: Stephen Paul Weber <singpolyma@singpolyma.net>
122 Upstream-Maintainer: Stephen Paul Weber <singpolyma@singpolyma.net> 107 Upstream-Maintainer: Stephen Paul Weber <singpolyma@singpolyma.net>
diff --git a/examples/keygen.hs b/examples/keygen.hs
deleted file mode 100644
index 65c3e33..0000000
--- a/examples/keygen.hs
+++ /dev/null
@@ -1,43 +0,0 @@
1import System.Time (getClockTime, ClockTime(..))
2import qualified Data.Map as Map
3import qualified Data.ByteString.Lazy as LZ
4
5import Data.Binary
6import OpenSSL.RSA
7import Control.Arrow (second)
8import Codec.Encryption.RSA.NumberTheory (extEuclGcd)
9
10import qualified Data.OpenPGP as OpenPGP
11import qualified Data.OpenPGP.Crypto as OpenPGP
12
13main :: IO ()
14main = do
15 time <- getClockTime
16 let TOD t _ = time
17
18 nkey <- generateRSAKey' 1042 65537
19
20 let secretKey = OpenPGP.SecretKeyPacket {
21 OpenPGP.version = 4,
22 OpenPGP.timestamp = fromIntegral t,
23 OpenPGP.key_algorithm = OpenPGP.RSA,
24 OpenPGP.key = Map.fromList $ map (second OpenPGP.MPI)
25 [('n', rsaN nkey), ('e', rsaE nkey),
26 ('d', rsaD nkey), ('p', rsaP nkey), ('q', rsaQ nkey),
27 ('u', fst $ extEuclGcd (rsaP nkey) (rsaQ nkey))],
28 OpenPGP.s2k_useage = 0,
29 OpenPGP.symmetric_type = undefined,
30 OpenPGP.s2k_type = undefined,
31 OpenPGP.s2k_hash_algorithm = undefined,
32 OpenPGP.s2k_salt = undefined,
33 OpenPGP.s2k_count = undefined,
34 OpenPGP.encrypted_data = undefined,
35 OpenPGP.private_hash = undefined }
36
37 let userID = OpenPGP.UserIDPacket "Test <test@example.com>"
38 let message = OpenPGP.Message[ secretKey, userID ]
39
40 let message' = OpenPGP.Message [ secretKey, userID,
41 OpenPGP.sign message message OpenPGP.SHA256 [] (fromIntegral t)]
42
43 LZ.putStr $ encode message'
diff --git a/examples/sign.hs b/examples/sign.hs
deleted file mode 100644
index e8bea1a..0000000
--- a/examples/sign.hs
+++ /dev/null
@@ -1,23 +0,0 @@
1import System (getArgs)
2import System.Time (getClockTime, ClockTime(..))
3
4import Data.Binary
5
6import qualified Data.OpenPGP as OpenPGP
7import qualified Data.OpenPGP.Crypto as OpenPGP
8import qualified Data.ByteString.Lazy as LZ
9import qualified Data.ByteString.Lazy.UTF8 as LZ
10
11main :: IO ()
12main = do
13 argv <- getArgs
14 time <- getClockTime
15 let TOD t _ = time
16 keys <- decodeFile (argv !! 0)
17 let dataPacket = OpenPGP.LiteralDataPacket 'u' "t.txt"
18 (fromIntegral t) (LZ.fromString "This is a message.")
19 let message = OpenPGP.Message [
20 OpenPGP.sign keys (OpenPGP.Message [dataPacket])
21 OpenPGP.SHA256 [] (fromIntegral t),
22 dataPacket]
23 LZ.putStr $ encode message
diff --git a/examples/verify.hs b/examples/verify.hs
deleted file mode 100644
index b123bd1..0000000
--- a/examples/verify.hs
+++ /dev/null
@@ -1,14 +0,0 @@
1import System (getArgs)
2
3import Data.Binary
4
5import qualified Data.OpenPGP as OpenPGP ()
6import qualified Data.OpenPGP.Crypto as OpenPGP
7
8main :: IO ()
9main = do
10 argv <- getArgs
11 keys <- decodeFile (argv !! 0)
12 message <- decodeFile (argv !! 1)
13 -- Just verify first signature
14 print $ OpenPGP.verify keys message 0
diff --git a/openpgp.cabal b/openpgp.cabal
index 0a40b94..3f3d592 100644
--- a/openpgp.cabal
+++ b/openpgp.cabal
@@ -23,15 +23,11 @@ description:
23 and then defines instances of Data.Binary for each to facilitate 23 and then defines instances of Data.Binary for each to facilitate
24 encoding/decoding. 24 encoding/decoding.
25 . 25 .
26 There is also a wrapper around <http://hackage.haskell.org/package/Crypto> 26 For performing cryptography, see <http://hackage.haskell.org/openpgp-Crypto>
27 that currently does fingerprint generation, signature generation, and
28 signature verification (for RSA keys only).
29 . 27 .
30 It is intended that you use qualified imports with this library. If importing 28 It is intended that you use qualified imports with this library.
31 both modules, something like this will do:
32 . 29 .
33 > import qualified Data.OpenPGP as OpenPGP 30 > import qualified Data.OpenPGP as OpenPGP
34 > import qualified Data.OpenPGP.Crypto as OpenPGP
35 31
36extra-source-files: 32extra-source-files:
37 README, 33 README,
@@ -114,19 +110,19 @@ extra-source-files:
114 tests/data/000076-007.secret_subkey, 110 tests/data/000076-007.secret_subkey,
115 tests/data/000077-002.sig, 111 tests/data/000077-002.sig,
116 tests/data/000078-012.ring_trust, 112 tests/data/000078-012.ring_trust,
113 tests/data/compressedsig-bzip2.gpg,
114 tests/data/compressedsig.gpg,
115 tests/data/compressedsig-zlib.gpg,
116 tests/data/onepass_sig,
117 tests/data/pubring.gpg, 117 tests/data/pubring.gpg,
118 tests/data/secring.gpg, 118 tests/data/secring.gpg,
119 tests/data/compressedsig.gpg,
120 tests/data/msg1.asc,
121 tests/data/uncompressed-ops-rsa.gpg,
122 tests/data/uncompressed-ops-dsa.gpg, 119 tests/data/uncompressed-ops-dsa.gpg,
123 tests/data/uncompressed-ops-dsa-sha384.txt.gpg, 120 tests/data/uncompressed-ops-dsa-sha384.txt.gpg,
124 tests/data/encryption.gpg 121 tests/data/uncompressed-ops-rsa.gpg
125 122
126library 123library
127 exposed-modules: 124 exposed-modules:
128 Data.OpenPGP 125 Data.OpenPGP
129 Data.OpenPGP.Crypto
130 126
131 build-depends: 127 build-depends:
132 base == 4.*, 128 base == 4.*,
@@ -135,8 +131,7 @@ library
135 utf8-string, 131 utf8-string,
136 binary, 132 binary,
137 zlib, 133 zlib,
138 bzlib, 134 bzlib
139 Crypto
140 135
141test-suite tests 136test-suite tests
142 type: exitcode-stdio-1.0 137 type: exitcode-stdio-1.0
@@ -150,7 +145,6 @@ test-suite tests
150 binary, 145 binary,
151 zlib, 146 zlib,
152 bzlib, 147 bzlib,
153 Crypto,
154 HUnit, 148 HUnit,
155 QuickCheck >= 2.4.1.1, 149 QuickCheck >= 2.4.1.1,
156 test-framework, 150 test-framework,
diff --git a/tests/data/encryption-sym-aes256.gpg b/tests/data/encryption-sym-aes256.gpg
deleted file mode 100644
index 264ae11..0000000
--- a/tests/data/encryption-sym-aes256.gpg
+++ /dev/null
@@ -1 +0,0 @@
1  '6*W`VLEQjNp(Y3N*?!M**ۈ; hL2+!x̄&&\J{q<16.-D ޿ \ No newline at end of file
diff --git a/tests/data/encryption-sym-cast5.gpg b/tests/data/encryption-sym-cast5.gpg
deleted file mode 100644
index 2c552ac..0000000
--- a/tests/data/encryption-sym-cast5.gpg
+++ /dev/null
Binary files differ
diff --git a/tests/data/encryption.gpg b/tests/data/encryption.gpg
deleted file mode 100644
index 9781572..0000000
--- a/tests/data/encryption.gpg
+++ /dev/null
Binary files differ
diff --git a/tests/data/msg1.asc b/tests/data/msg1.asc
deleted file mode 100644
index 832d3bb..0000000
--- a/tests/data/msg1.asc
+++ /dev/null
@@ -1,7 +0,0 @@
1-----BEGIN PGP MESSAGE-----
2Version: OpenPrivacy 0.99
3
4yDgBO22WxBHv7O8X7O/jygAEzol56iUKiXmV+XmpCtmpqQUKiQrFqclFqUDBovzS
5vBSFjNSiVHsuAA==
6=njUN
7-----END PGP MESSAGE-----
diff --git a/tests/suite.hs b/tests/suite.hs
index 7ea5e57..ad7a8f2 100644
--- a/tests/suite.hs
+++ b/tests/suite.hs
@@ -7,9 +7,7 @@ import Test.HUnit hiding (Test)
7import Data.Word 7import Data.Word
8import Data.Binary 8import Data.Binary
9import qualified Data.OpenPGP as OpenPGP 9import qualified Data.OpenPGP as OpenPGP
10import qualified Data.OpenPGP.Crypto as OpenPGP
11import qualified Data.ByteString.Lazy as LZ 10import qualified Data.ByteString.Lazy as LZ
12import qualified Data.ByteString.Lazy.UTF8 as LZ (fromString)
13 11
14instance Arbitrary OpenPGP.HashAlgorithm where 12instance Arbitrary OpenPGP.HashAlgorithm where
15 arbitrary = elements [OpenPGP.MD5, OpenPGP.SHA1, OpenPGP.SHA256, OpenPGP.SHA384, OpenPGP.SHA512] 13 arbitrary = elements [OpenPGP.MD5, OpenPGP.SHA1, OpenPGP.SHA256, OpenPGP.SHA384, OpenPGP.SHA512]
@@ -18,8 +16,8 @@ testSerialization :: FilePath -> Assertion
18testSerialization fp = do 16testSerialization fp = do
19 bs <- LZ.readFile $ "tests/data/" ++ fp 17 bs <- LZ.readFile $ "tests/data/" ++ fp
20 nullShield "First" (decode bs) (\firstpass -> 18 nullShield "First" (decode bs) (\firstpass ->
21 nullShield "Second" (decode $ encode firstpass) (\secondpass -> 19 nullShield "Second" (decode $ encode firstpass) (
22 assertEqual ("for " ++ fp) firstpass secondpass 20 assertEqual ("for " ++ fp) firstpass
23 ) 21 )
24 ) 22 )
25 where 23 where
@@ -27,38 +25,12 @@ testSerialization fp = do
27 assertFailure $ pass ++ " pass of " ++ fp ++ " decoded to nothing." 25 assertFailure $ pass ++ " pass of " ++ fp ++ " decoded to nothing."
28 nullShield _ m f = f m 26 nullShield _ m f = f m
29 27
30testFingerprint :: FilePath -> String -> Assertion
31testFingerprint fp kf = do
32 bs <- LZ.readFile $ "tests/data/" ++ fp
33 let (OpenPGP.Message [packet]) = decode bs
34 assertEqual ("for " ++ fp) kf (OpenPGP.fingerprint packet)
35
36testVerifyMessage :: FilePath -> FilePath -> Assertion
37testVerifyMessage keyring message = do
38 keys <- fmap decode $ LZ.readFile $ "tests/data/" ++ keyring
39 m <- fmap decode $ LZ.readFile $ "tests/data/" ++ message
40 let verification = OpenPGP.verify keys m 0
41 assertEqual (keyring ++ " for " ++ message) True verification
42
43prop_sign_and_verify :: OpenPGP.Message -> String -> OpenPGP.HashAlgorithm -> String -> String -> Bool
44prop_sign_and_verify secring kid halgo filename msg =
45 let
46 m = OpenPGP.LiteralDataPacket {
47 OpenPGP.format = 'u',
48 OpenPGP.filename = filename,
49 OpenPGP.timestamp = 12341234,
50 OpenPGP.content = LZ.fromString msg
51 }
52 sig = OpenPGP.sign secring (OpenPGP.Message [m]) halgo kid 12341234
53 in
54 OpenPGP.verify secring (OpenPGP.Message [m,sig]) 0
55
56prop_s2k_count :: Word8 -> Bool 28prop_s2k_count :: Word8 -> Bool
57prop_s2k_count c = 29prop_s2k_count c =
58 c == OpenPGP.encode_s2k_count (OpenPGP.decode_s2k_count c) 30 c == OpenPGP.encode_s2k_count (OpenPGP.decode_s2k_count c)
59 31
60tests :: OpenPGP.Message -> [Test] 32tests :: [Test]
61tests secring = 33tests =
62 [ 34 [
63 testGroup "Serialization" [ 35 testGroup "Serialization" [
64 testCase "000001-006.public_key" (testSerialization "000001-006.public_key"), 36 testCase "000001-006.public_key" (testSerialization "000001-006.public_key"),
@@ -148,29 +120,10 @@ tests secring =
148 testCase "uncompressed-ops-dsa.gpg" (testSerialization "uncompressed-ops-dsa.gpg"), 120 testCase "uncompressed-ops-dsa.gpg" (testSerialization "uncompressed-ops-dsa.gpg"),
149 testCase "uncompressed-ops-rsa.gpg" (testSerialization "uncompressed-ops-rsa.gpg") 121 testCase "uncompressed-ops-rsa.gpg" (testSerialization "uncompressed-ops-rsa.gpg")
150 ], 122 ],
151 testGroup "Fingerprint" [
152 testCase "000001-006.public_key" (testFingerprint "000001-006.public_key" "421F28FEAAD222F856C8FFD5D4D54EA16F87040E"),
153 testCase "000016-006.public_key" (testFingerprint "000016-006.public_key" "AF95E4D7BAC521EE9740BED75E9F1523413262DC"),
154 testCase "000027-006.public_key" (testFingerprint "000027-006.public_key" "1EB20B2F5A5CC3BEAFD6E5CB7732CF988A63EA86"),
155 testCase "000035-006.public_key" (testFingerprint "000035-006.public_key" "CB7933459F59C70DF1C3FBEEDEDC3ECF689AF56D")
156 ],
157 testGroup "Message verification" [
158 --testCase "uncompressed-ops-dsa" (testVerifyMessage "pubring.gpg" "uncompressed-ops-dsa.gpg"),
159 --testCase "uncompressed-ops-dsa-sha384" (testVerifyMessage "pubring.gpg" "uncompressed-ops-dsa-sha384.txt.gpg"),
160 testCase "uncompressed-ops-rsa" (testVerifyMessage "pubring.gpg" "uncompressed-ops-rsa.gpg"),
161 testCase "compressedsig" (testVerifyMessage "pubring.gpg" "compressedsig.gpg"),
162 testCase "compressedsig-zlib" (testVerifyMessage "pubring.gpg" "compressedsig-zlib.gpg"),
163 testCase "compressedsig-bzip2" (testVerifyMessage "pubring.gpg" "compressedsig-bzip2.gpg")
164 ],
165 testGroup "Signing" [
166 testProperty "Crypto signatures verify" (prop_sign_and_verify secring "FEF8AFA0F661C3EE")
167 ],
168 testGroup "S2K count" [ 123 testGroup "S2K count" [
169 testProperty "S2K count encode reverses decode" prop_s2k_count 124 testProperty "S2K count encode reverses decode" prop_s2k_count
170 ] 125 ]
171 ] 126 ]
172 127
173main :: IO () 128main :: IO ()
174main = do 129main = defaultMain tests
175 secring <- fmap decode $ LZ.readFile "tests/data/secring.gpg"
176 defaultMain (tests secring)