summaryrefslogtreecommitdiff
path: root/Data/OpenPGP
diff options
context:
space:
mode:
authorStephen Paul Weber <singpolyma@singpolyma.net>2011-08-10 19:14:14 -0500
committerStephen Paul Weber <singpolyma@singpolyma.net>2011-08-10 19:14:14 -0500
commit446ba2e70da76d004f955876dba0d060dbe9e0a0 (patch)
tree992a2aad6b988246a804695c6045b4f7427f01cb /Data/OpenPGP
parent18ef79440155b80414423819888f76fb3bf18469 (diff)
Ability to sign a message with RSA
Diffstat (limited to 'Data/OpenPGP')
-rw-r--r--Data/OpenPGP/Crypto.hs49
1 files changed, 48 insertions, 1 deletions
diff --git a/Data/OpenPGP/Crypto.hs b/Data/OpenPGP/Crypto.hs
index fee1d55..d4d08c0 100644
--- a/Data/OpenPGP/Crypto.hs
+++ b/Data/OpenPGP/Crypto.hs
@@ -4,13 +4,15 @@
4-- The recommended way to import this module is: 4-- The recommended way to import this module is:
5-- 5--
6-- > import qualified Data.OpenPGP.Crypto as OpenPGP 6-- > import qualified Data.OpenPGP.Crypto as OpenPGP
7module Data.OpenPGP.Crypto (verify, fingerprint) where 7module Data.OpenPGP.Crypto (sign, verify, fingerprint) where
8 8
9import Data.Word 9import Data.Word
10import Data.List (find)
10import Data.Map ((!)) 11import Data.Map ((!))
11import qualified Data.ByteString.Lazy as LZ 12import qualified Data.ByteString.Lazy as LZ
12 13
13import Data.Binary 14import Data.Binary
15import Codec.Utils (fromOctets)
14import qualified Codec.Encryption.RSA as RSA 16import qualified Codec.Encryption.RSA as RSA
15import qualified Data.Digest.MD5 as MD5 17import qualified Data.Digest.MD5 as MD5
16import qualified Data.Digest.SHA1 as SHA1 18import qualified Data.Digest.SHA1 as SHA1
@@ -91,3 +93,48 @@ verify keys message sigidx =
91 sig = sigs !! sigidx 93 sig = sigs !! sigidx
92 (sigs, (OpenPGP.LiteralDataPacket {OpenPGP.content = dta}):_) = 94 (sigs, (OpenPGP.LiteralDataPacket {OpenPGP.content = dta}):_) =
93 OpenPGP.signatures_and_data message 95 OpenPGP.signatures_and_data message
96
97-- | Sign a message. Only supports RSA keys for now.
98sign :: OpenPGP.Message -- ^ SecretKeys, one of which will be used
99 -> OpenPGP.Message -- ^ Message containing LiteralData to sign
100 -> OpenPGP.HashAlgorithm -- ^ HashAlgorithm to use is signature
101 -> String -- ^ KeyID of key to choose or @[]@ for first
102 -> Integer -- ^ Timestamp to put in signature
103 -> OpenPGP.Message
104sign keys message hsh keyid timestamp =
105 OpenPGP.Message $ (sig' {
106 OpenPGP.signature = OpenPGP.MPI $ toNum $ reverse final,
107 OpenPGP.hash_head = toNum $ take 2 final
108 }):m
109 where
110 -- toNum has explicit param so that it can remain polymorphic
111 toNum l = fromOctets (256::Integer) l
112 final = RSA.decrypt (n, d) encoded
113 encoded = emsa_pkcs1_v1_5_encode dta (length n) hsh
114 (n, d) = (keyfield_as_octets k 'n', keyfield_as_octets k 'd')
115 dta = LZ.unpack $ LZ.append
116 (OpenPGP.content dataP) (OpenPGP.trailer sig')
117 sig' = sig {
118 OpenPGP.trailer = OpenPGP.calculate_signature_trailer sig
119 }
120 sig = OpenPGP.SignaturePacket {
121 OpenPGP.version = 4,
122 OpenPGP.key_algorithm = OpenPGP.RSA,
123 OpenPGP.hash_algorithm = hsh,
124 OpenPGP.signature_type = stype,
125 OpenPGP.hashed_subpackets = [
126 OpenPGP.SignatureCreationTimePacket $ fromIntegral timestamp,
127 OpenPGP.IssuerPacket keyid'
128 ],
129 OpenPGP.unhashed_subpackets = [],
130 OpenPGP.signature = undefined,
131 OpenPGP.trailer = undefined,
132 OpenPGP.hash_head = undefined
133 }
134 keyid' = reverse $ take 16 $ reverse $ fingerprint k
135 stype = if OpenPGP.format dataP == 'b' then 0x00 else 0x01
136 Just k = find_key keys keyid
137 Just dataP = find isLiteralData m
138 OpenPGP.Message m = message
139 isLiteralData (OpenPGP.LiteralDataPacket {}) = True
140 isLiteralData _ = False