diff options
author | Stephen Paul Weber <singpolyma@singpolyma.net> | 2012-04-25 17:19:07 -0500 |
---|---|---|
committer | Stephen Paul Weber <singpolyma@singpolyma.net> | 2012-04-25 17:19:07 -0500 |
commit | 6b743222684f2b8151dfbdef42f0dc890e590c41 (patch) | |
tree | 77b5ae031d2b863f03399ba9a5b56ba4478d2ab2 | |
parent | 7b3232778f284dd4dd3a6f3287bcbe1fbe10b010 (diff) |
Split OpenPGP.Crypto out into a seperate package
-rw-r--r-- | Data/OpenPGP/Crypto.hs | 183 | ||||
-rw-r--r-- | Makefile | 23 | ||||
-rw-r--r-- | README | 8 | ||||
-rw-r--r-- | debian/control | 27 | ||||
-rw-r--r-- | examples/keygen.hs | 43 | ||||
-rw-r--r-- | examples/sign.hs | 23 | ||||
-rw-r--r-- | examples/verify.hs | 14 | ||||
-rw-r--r-- | openpgp.cabal | 22 | ||||
-rw-r--r-- | tests/data/encryption-sym-aes256.gpg | 1 | ||||
-rw-r--r-- | tests/data/encryption-sym-cast5.gpg | bin | 72 -> 0 bytes | |||
-rw-r--r-- | tests/data/encryption.gpg | bin | 860 -> 0 bytes | |||
-rw-r--r-- | tests/data/msg1.asc | 7 | ||||
-rw-r--r-- | tests/suite.hs | 57 |
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 | ||
7 | module Data.OpenPGP.Crypto (sign, verify, fingerprint) where | ||
8 | |||
9 | import Numeric | ||
10 | import Data.Word | ||
11 | import Data.Char | ||
12 | import Data.List (find) | ||
13 | import Data.Map ((!)) | ||
14 | import qualified Data.ByteString.Lazy as LZ | ||
15 | import qualified Data.ByteString.Lazy.UTF8 as LZ (fromString) | ||
16 | |||
17 | import Data.Binary | ||
18 | import Codec.Utils (fromOctets) | ||
19 | import qualified Codec.Encryption.RSA as RSA | ||
20 | import qualified Data.Digest.MD5 as MD5 | ||
21 | import qualified Data.Digest.SHA1 as SHA1 | ||
22 | import qualified Data.Digest.SHA256 as SHA256 | ||
23 | import qualified Data.Digest.SHA384 as SHA384 | ||
24 | import qualified Data.Digest.SHA512 as SHA512 | ||
25 | |||
26 | import 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> | ||
30 | fingerprint :: OpenPGP.Packet -> String | ||
31 | fingerprint 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 | |||
44 | find_key :: OpenPGP.Message -> String -> Maybe OpenPGP.Packet | ||
45 | find_key (OpenPGP.Message (x@(OpenPGP.PublicKeyPacket {}):xs)) keyid = | ||
46 | find_key_ x xs keyid | ||
47 | find_key (OpenPGP.Message (x@(OpenPGP.SecretKeyPacket {}):xs)) keyid = | ||
48 | find_key_ x xs keyid | ||
49 | find_key (OpenPGP.Message (_:xs)) keyid = | ||
50 | find_key (OpenPGP.Message xs) keyid | ||
51 | find_key _ _ = Nothing | ||
52 | |||
53 | find_key_ :: OpenPGP.Packet -> [OpenPGP.Packet] -> String -> Maybe OpenPGP.Packet | ||
54 | find_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 | |||
60 | keyfield_as_octets :: OpenPGP.Packet -> Char -> [Word8] | ||
61 | keyfield_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 | ||
66 | emsa_pkcs1_v1_5_hash_padding :: OpenPGP.HashAlgorithm -> [Word8] | ||
67 | emsa_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] | ||
68 | emsa_pkcs1_v1_5_hash_padding OpenPGP.SHA1 = [0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14] | ||
69 | emsa_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] | ||
70 | emsa_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] | ||
71 | emsa_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] | ||
72 | emsa_pkcs1_v1_5_hash_padding _ = | ||
73 | error "Unsupported HashAlgorithm in emsa_pkcs1_v1_5_hash_padding." | ||
74 | |||
75 | hash :: OpenPGP.HashAlgorithm -> [Word8] -> [Word8] | ||
76 | hash OpenPGP.MD5 = MD5.hash | ||
77 | hash OpenPGP.SHA1 = drop 2 . LZ.unpack . encode . OpenPGP.MPI . SHA1.toInteger . SHA1.hash | ||
78 | hash OpenPGP.SHA256 = SHA256.hash | ||
79 | hash OpenPGP.SHA384 = SHA384.hash | ||
80 | hash OpenPGP.SHA512 = SHA512.hash | ||
81 | hash _ = error "Unsupported HashAlgorithm in hash." | ||
82 | |||
83 | emsa_pkcs1_v1_5_encode :: [Word8] -> Int -> OpenPGP.HashAlgorithm -> [Word8] | ||
84 | emsa_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. | ||
89 | verify :: 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 | ||
93 | verify 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. | ||
108 | sign :: 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 | ||
114 | sign 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 | ||
@@ -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 | ||
7 | all: sign verify keygen test report.html doc dist/build/libHSopenpgp-$(VERSION).a dist/openpgp-$(VERSION).tar.gz | 7 | all: test report.html doc dist/build/libHSopenpgp-$(VERSION).a dist/openpgp-$(VERSION).tar.gz |
8 | 8 | ||
9 | install: dist/build/libHSopenpgp-$(VERSION).a | 9 | install: dist/build/libHSopenpgp-$(VERSION).a |
10 | cabal install | 10 | cabal install |
@@ -14,20 +14,11 @@ debian: debian/control | |||
14 | test: tests/suite | 14 | test: tests/suite |
15 | tests/suite | 15 | tests/suite |
16 | 16 | ||
17 | sign: examples/sign.hs Data/*.hs Data/OpenPGP/*.hs | 17 | tests/suite: tests/suite.hs Data/OpenPGP.hs |
18 | ghc --make $(GHCFLAGS) -o $@ $^ | 18 | ghc --make $(GHCFLAGS) -o $@ $^ |
19 | 19 | ||
20 | verify: examples/verify.hs Data/*.hs Data/OpenPGP/*.hs | 20 | report.html: Data/OpenPGP.hs tests/suite.hs |
21 | ghc --make $(GHCFLAGS) -o $@ $^ | 21 | -hlint $(HLINTFLAGS) --report $^ |
22 | |||
23 | keygen: examples/keygen.hs Data/*.hs Data/OpenPGP/*.hs | ||
24 | ghc --make $(GHCFLAGS) -o $@ $^ | ||
25 | |||
26 | tests/suite: tests/suite.hs Data/*.hs Data/OpenPGP/*.hs | ||
27 | ghc --make $(GHCFLAGS) -o $@ $^ | ||
28 | |||
29 | report.html: examples/*.hs Data/*.hs Data/OpenPGP/*.hs tests/*.hs | ||
30 | -hlint $(HLINTFLAGS) --report Data examples | ||
31 | 22 | ||
32 | doc: dist/doc/html/openpgp/index.html README | 23 | doc: 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 | ||
40 | dist/doc/html/openpgp/index.html: dist/setup-config Data/OpenPGP.hs Data/OpenPGP/Crypto.hs | 31 | dist/doc/html/openpgp/index.html: dist/setup-config Data/OpenPGP.hs |
41 | cabal haddock --hyperlink-source | 32 | cabal haddock --hyperlink-source |
42 | 33 | ||
43 | dist/setup-config: openpgp.cabal | 34 | dist/setup-config: openpgp.cabal |
@@ -51,9 +42,9 @@ clean: | |||
51 | debian/control: openpgp.cabal | 42 | debian/control: openpgp.cabal |
52 | cabal-debian --update-debianization | 43 | cabal-debian --update-debianization |
53 | 44 | ||
54 | dist/build/libHSopenpgp-$(VERSION).a: openpgp.cabal dist/setup-config Data/OpenPGP.hs Data/OpenPGP/Crypto.hs | 45 | dist/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 | ||
57 | dist/openpgp-$(VERSION).tar.gz: openpgp.cabal dist/setup-config Data/OpenPGP.hs Data/OpenPGP/Crypto.hs README | 48 | dist/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 |
@@ -7,12 +7,8 @@ It defines types to represent OpenPGP messages as a series of packets | |||
7 | and then defines instances of Data.Binary for each to facilitate | 7 | and then defines instances of Data.Binary for each to facilitate |
8 | encoding/decoding. | 8 | encoding/decoding. |
9 | 9 | ||
10 | There is also a wrapper around <http://hackage.haskell.org/package/Crypto> | 10 | For performing cryptography, see <http://hackage.haskell.org/openpgp-Crypto> |
11 | that currently does fingerprint generation, signature generation, and | ||
12 | signature verification (for RSA keys only). | ||
13 | 11 | ||
14 | It is intended that you use qualified imports with this library. If importing | 12 | It is intended that you use qualified imports with this library. |
15 | both 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 |
20 | Build-Depends-Indep: ghc-doc, | 18 | Build-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 @@ | |||
1 | import System.Time (getClockTime, ClockTime(..)) | ||
2 | import qualified Data.Map as Map | ||
3 | import qualified Data.ByteString.Lazy as LZ | ||
4 | |||
5 | import Data.Binary | ||
6 | import OpenSSL.RSA | ||
7 | import Control.Arrow (second) | ||
8 | import Codec.Encryption.RSA.NumberTheory (extEuclGcd) | ||
9 | |||
10 | import qualified Data.OpenPGP as OpenPGP | ||
11 | import qualified Data.OpenPGP.Crypto as OpenPGP | ||
12 | |||
13 | main :: IO () | ||
14 | main = 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 @@ | |||
1 | import System (getArgs) | ||
2 | import System.Time (getClockTime, ClockTime(..)) | ||
3 | |||
4 | import Data.Binary | ||
5 | |||
6 | import qualified Data.OpenPGP as OpenPGP | ||
7 | import qualified Data.OpenPGP.Crypto as OpenPGP | ||
8 | import qualified Data.ByteString.Lazy as LZ | ||
9 | import qualified Data.ByteString.Lazy.UTF8 as LZ | ||
10 | |||
11 | main :: IO () | ||
12 | main = 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 @@ | |||
1 | import System (getArgs) | ||
2 | |||
3 | import Data.Binary | ||
4 | |||
5 | import qualified Data.OpenPGP as OpenPGP () | ||
6 | import qualified Data.OpenPGP.Crypto as OpenPGP | ||
7 | |||
8 | main :: IO () | ||
9 | main = 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 | ||
36 | extra-source-files: | 32 | extra-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 | ||
126 | library | 123 | library |
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 | ||
141 | test-suite tests | 136 | test-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----- | ||
2 | Version: OpenPrivacy 0.99 | ||
3 | |||
4 | yDgBO22WxBHv7O8X7O/jygAEzol56iUKiXmV+XmpCtmpqQUKiQrFqclFqUDBovzS | ||
5 | vBSFjNSiVHsuAA== | ||
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) | |||
7 | import Data.Word | 7 | import Data.Word |
8 | import Data.Binary | 8 | import Data.Binary |
9 | import qualified Data.OpenPGP as OpenPGP | 9 | import qualified Data.OpenPGP as OpenPGP |
10 | import qualified Data.OpenPGP.Crypto as OpenPGP | ||
11 | import qualified Data.ByteString.Lazy as LZ | 10 | import qualified Data.ByteString.Lazy as LZ |
12 | import qualified Data.ByteString.Lazy.UTF8 as LZ (fromString) | ||
13 | 11 | ||
14 | instance Arbitrary OpenPGP.HashAlgorithm where | 12 | instance 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 | |||
18 | testSerialization fp = do | 16 | testSerialization 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 | ||
30 | testFingerprint :: FilePath -> String -> Assertion | ||
31 | testFingerprint 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 | |||
36 | testVerifyMessage :: FilePath -> FilePath -> Assertion | ||
37 | testVerifyMessage 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 | |||
43 | prop_sign_and_verify :: OpenPGP.Message -> String -> OpenPGP.HashAlgorithm -> String -> String -> Bool | ||
44 | prop_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 | |||
56 | prop_s2k_count :: Word8 -> Bool | 28 | prop_s2k_count :: Word8 -> Bool |
57 | prop_s2k_count c = | 29 | prop_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 | ||
60 | tests :: OpenPGP.Message -> [Test] | 32 | tests :: [Test] |
61 | tests secring = | 33 | tests = |
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 | ||
173 | main :: IO () | 128 | main :: IO () |
174 | main = do | 129 | main = defaultMain tests |
175 | secring <- fmap decode $ LZ.readFile "tests/data/secring.gpg" | ||
176 | defaultMain (tests secring) | ||