summaryrefslogtreecommitdiff
path: root/Data/OpenPGP
diff options
context:
space:
mode:
authorStephen Paul Weber <singpolyma@singpolyma.net>2011-08-08 21:47:10 -0500
committerStephen Paul Weber <singpolyma@singpolyma.net>2011-08-08 21:55:19 -0500
commitaa8529550515d2a1a59adff2fc5dbd4235b92f18 (patch)
tree410163c8b8972f64a9fb838b8d0e89ef0c975661 /Data/OpenPGP
parentcf528d91c534e71cf9fed06620ccd3d2fe3197b7 (diff)
Move into Data hierarchy
Diffstat (limited to 'Data/OpenPGP')
-rw-r--r--Data/OpenPGP/Crypto.hs82
1 files changed, 82 insertions, 0 deletions
diff --git a/Data/OpenPGP/Crypto.hs b/Data/OpenPGP/Crypto.hs
new file mode 100644
index 0000000..e2151fc
--- /dev/null
+++ b/Data/OpenPGP/Crypto.hs
@@ -0,0 +1,82 @@
1module Data.OpenPGP.Crypto (verify, fingerprint) where
2
3import Data.Word
4import Data.Map ((!))
5import qualified Data.ByteString.Lazy as LZ
6
7import Data.Binary
8import qualified Codec.Encryption.RSA as RSA
9import qualified Data.Digest.MD5 as MD5
10import qualified Data.Digest.SHA1 as SHA1
11import qualified Data.Digest.SHA256 as SHA256
12import qualified Data.Digest.SHA384 as SHA384
13import qualified Data.Digest.SHA512 as SHA512
14
15import qualified Data.OpenPGP as OpenPGP
16import qualified Data.BaseConvert as BaseConvert
17
18-- http://tools.ietf.org/html/rfc4880#section-12.2
19fingerprint :: OpenPGP.Packet -> String
20fingerprint p | OpenPGP.version p == 4 =
21 BaseConvert.toString 16 $ SHA1.toInteger $ SHA1.hash $
22 LZ.unpack (LZ.concat (OpenPGP.fingerprint_material p))
23fingerprint p | OpenPGP.version p `elem` [2, 3] =
24 concatMap (BaseConvert.toString 16) $
25 MD5.hash $ LZ.unpack (LZ.concat (OpenPGP.fingerprint_material p))
26fingerprint _ = error "Unsupported Packet version or type in fingerprint."
27
28find_key :: OpenPGP.Message -> String -> Maybe OpenPGP.Packet
29find_key (OpenPGP.Message (x@(OpenPGP.PublicKeyPacket {}):xs)) keyid =
30 find_key_ x xs keyid
31find_key (OpenPGP.Message (x@(OpenPGP.SecretKeyPacket {}):xs)) keyid =
32 find_key_ x xs keyid
33find_key _ _ = Nothing
34
35find_key_ :: OpenPGP.Packet -> [OpenPGP.Packet] -> String -> Maybe OpenPGP.Packet
36find_key_ x xs keyid =
37 if thisid == keyid then Just x else find_key (OpenPGP.Message xs) keyid
38 where thisid = reverse $
39 take (length keyid) (reverse (fingerprint x))
40
41keyfield_as_octets :: OpenPGP.Packet -> Char -> [Word8]
42keyfield_as_octets k f =
43 LZ.unpack $ LZ.drop 2 (encode (k' ! f))
44 where k' = OpenPGP.key k
45
46-- http://tools.ietf.org/html/rfc3447#page-43
47emsa_pkcs1_v1_5_hash_padding :: OpenPGP.HashAlgorithm -> [Word8]
48emsa_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]
49emsa_pkcs1_v1_5_hash_padding OpenPGP.SHA1 = [0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14]
50emsa_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]
51emsa_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]
52emsa_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]
53emsa_pkcs1_v1_5_hash_padding _ =
54 error "Unsupported HashAlgorithm in emsa_pkcs1_v1_5_hash_padding."
55
56hash :: OpenPGP.HashAlgorithm -> [Word8] -> [Word8]
57hash OpenPGP.MD5 = MD5.hash
58hash OpenPGP.SHA1 = reverse . drop 2 . LZ.unpack . encode . OpenPGP.MPI . SHA1.toInteger . SHA1.hash
59hash OpenPGP.SHA256 = SHA256.hash
60hash OpenPGP.SHA384 = SHA384.hash
61hash OpenPGP.SHA512 = SHA512.hash
62hash _ = error "Unsupported HashAlgorithm in hash."
63
64emsa_pkcs1_v1_5_encode :: [Word8] -> Int -> OpenPGP.HashAlgorithm -> [Word8]
65emsa_pkcs1_v1_5_encode m emLen algo =
66 [0, 1] ++ replicate (emLen - length t - 3) 0xff ++ [0] ++ t
67 where t = emsa_pkcs1_v1_5_hash_padding algo ++ hash algo m
68
69verify :: OpenPGP.Message -> OpenPGP.Message -> Int -> Bool
70verify keys packet sigidx =
71 encoded == RSA.encrypt (n, e) raw_sig
72 where
73 raw_sig = LZ.unpack $ LZ.drop 2 $ encode (OpenPGP.signature sig)
74 encoded = emsa_pkcs1_v1_5_encode signature_over
75 (length n) (OpenPGP.hash_algorithm sig)
76 signature_over = LZ.unpack $ dta `LZ.append` OpenPGP.trailer sig
77 (n, e) = (keyfield_as_octets k 'n', keyfield_as_octets k 'e')
78 Just k = find_key keys issuer
79 Just issuer = OpenPGP.signature_issuer sig
80 sig = sigs !! sigidx
81 (sigs, (OpenPGP.LiteralDataPacket {OpenPGP.content = dta}):_) =
82 OpenPGP.signatures_and_data packet