summaryrefslogtreecommitdiff
path: root/Data/OpenPGP
diff options
context:
space:
mode:
authorStephen Paul Weber <singpolyma@singpolyma.net>2011-08-12 21:03:43 -0500
committerStephen Paul Weber <singpolyma@singpolyma.net>2011-08-12 21:04:40 -0500
commit1cc474786194555bec47dd5c061c1bcc5d992952 (patch)
tree6b4c838a4abad603c208183a17b9df89772cca3c /Data/OpenPGP
parent531dc4a28554ceaaa495aa02374b559721aa6a9a (diff)
Refactor sign to handle keys
Also, now if you pass in a message with a signature packet we'll just use that one instead of making a default one. Return value is now just the new/filled-in signature packet, update example accordingly.
Diffstat (limited to 'Data/OpenPGP')
-rw-r--r--Data/OpenPGP/Crypto.hs77
1 files changed, 55 insertions, 22 deletions
diff --git a/Data/OpenPGP/Crypto.hs b/Data/OpenPGP/Crypto.hs
index d4d08c0..15c0d63 100644
--- a/Data/OpenPGP/Crypto.hs
+++ b/Data/OpenPGP/Crypto.hs
@@ -10,6 +10,7 @@ import Data.Word
10import Data.List (find) 10import Data.List (find)
11import Data.Map ((!)) 11import Data.Map ((!))
12import qualified Data.ByteString.Lazy as LZ 12import qualified Data.ByteString.Lazy as LZ
13import qualified Data.ByteString.Lazy.UTF8 as LZ (fromString)
13 14
14import Data.Binary 15import Data.Binary
15import Codec.Utils (fromOctets) 16import Codec.Utils (fromOctets)
@@ -77,7 +78,7 @@ emsa_pkcs1_v1_5_encode m emLen algo =
77 78
78-- | Verify a message signature. Only supports RSA keys for now. 79-- | Verify a message signature. Only supports RSA keys for now.
79verify :: OpenPGP.Message -- ^ Keys that may have made the signature 80verify :: OpenPGP.Message -- ^ Keys that may have made the signature
80 -> OpenPGP.Message -- ^ Message containing data and signature packet 81 -> OpenPGP.Message -- ^ Message containing data or key to sign, and optional signature packet
81 -> Int -- ^ Index of signature to verify (0th, 1st, etc) 82 -> Int -- ^ Index of signature to verify (0th, 1st, etc)
82 -> Bool 83 -> Bool
83verify keys message sigidx = 84verify keys message sigidx =
@@ -94,47 +95,79 @@ verify keys message sigidx =
94 (sigs, (OpenPGP.LiteralDataPacket {OpenPGP.content = dta}):_) = 95 (sigs, (OpenPGP.LiteralDataPacket {OpenPGP.content = dta}):_) =
95 OpenPGP.signatures_and_data message 96 OpenPGP.signatures_and_data message
96 97
97-- | Sign a message. Only supports RSA keys for now. 98-- | Sign data or key/userID pair. Only supports RSA keys for now.
98sign :: OpenPGP.Message -- ^ SecretKeys, one of which will be used 99sign :: OpenPGP.Message -- ^ SecretKeys, one of which will be used
99 -> OpenPGP.Message -- ^ Message containing LiteralData to sign 100 -> OpenPGP.Message -- ^ Message containing LiteralData to sign
100 -> OpenPGP.HashAlgorithm -- ^ HashAlgorithm to use is signature 101 -> OpenPGP.HashAlgorithm -- ^ HashAlgorithm to use is signature
101 -> String -- ^ KeyID of key to choose or @[]@ for first 102 -> String -- ^ KeyID of key to choose or @[]@ for first
102 -> Integer -- ^ Timestamp to put in signature 103 -> Integer -- ^ Timestamp for signature (unless sig supplied)
103 -> OpenPGP.Message 104 -> OpenPGP.Packet
104sign keys message hsh keyid timestamp = 105sign keys message hsh keyid timestamp =
105 OpenPGP.Message $ (sig' { 106 sig {
106 OpenPGP.signature = OpenPGP.MPI $ toNum $ reverse final, 107 OpenPGP.signature = OpenPGP.MPI $ toNum final,
107 OpenPGP.hash_head = toNum $ take 2 final 108 OpenPGP.hash_head = toNum $ take 2 final
108 }):m 109 }
109 where 110 where
110 -- toNum has explicit param so that it can remain polymorphic 111 -- toNum has explicit param so that it can remain polymorphic
111 toNum l = fromOctets (256::Integer) l 112 toNum l = fromOctets (256::Integer) l
112 final = RSA.decrypt (n, d) encoded 113 final = dropWhile (==0) $ RSA.decrypt (n, d) encoded
113 encoded = emsa_pkcs1_v1_5_encode dta (length n) hsh 114 encoded = emsa_pkcs1_v1_5_encode dta (length n) hsh
114 (n, d) = (keyfield_as_octets k 'n', keyfield_as_octets k 'd') 115 (n, d) = (keyfield_as_octets k 'n', keyfield_as_octets k 'd')
115 dta = LZ.unpack $ LZ.append 116 dta = LZ.unpack $ case signOver of {
116 (OpenPGP.content dataP) (OpenPGP.trailer sig') 117 OpenPGP.LiteralDataPacket {OpenPGP.content = c} -> c;
117 sig' = sig { 118 _ -> LZ.concat $ OpenPGP.fingerprint_material signOver ++ [
118 OpenPGP.trailer = OpenPGP.calculate_signature_trailer sig 119 LZ.singleton 0xB4,
119 } 120 encode (fromIntegral (length firstUserID) :: Word32),
120 sig = OpenPGP.SignaturePacket { 121 LZ.fromString firstUserID
121 OpenPGP.version = 4, 122 ]
123 } `LZ.append` OpenPGP.trailer sig
124 -- Always force key and hash algorithm
125 sig = let s = (findSigOrDefault (find isSignature m)) {
122 OpenPGP.key_algorithm = OpenPGP.RSA, 126 OpenPGP.key_algorithm = OpenPGP.RSA,
123 OpenPGP.hash_algorithm = hsh, 127 OpenPGP.hash_algorithm = hsh
124 OpenPGP.signature_type = stype, 128 } in s { OpenPGP.trailer = OpenPGP.calculate_signature_trailer s }
129
130 -- Either a SignaturePacket was found, or we need to make one
131 findSigOrDefault (Just s) = s
132 findSigOrDefault Nothing = OpenPGP.SignaturePacket {
133 OpenPGP.version = 4,
134 OpenPGP.key_algorithm = undefined,
135 OpenPGP.hash_algorithm = undefined,
136 OpenPGP.signature_type = defaultStype,
125 OpenPGP.hashed_subpackets = [ 137 OpenPGP.hashed_subpackets = [
138 -- Do we really need to pass in timestamp just for the default?
126 OpenPGP.SignatureCreationTimePacket $ fromIntegral timestamp, 139 OpenPGP.SignatureCreationTimePacket $ fromIntegral timestamp,
127 OpenPGP.IssuerPacket keyid' 140 OpenPGP.IssuerPacket keyid'
128 ], 141 ] ++ (case signOver of
142 OpenPGP.LiteralDataPacket {} -> []
143 _ -> [] -- TODO: OpenPGP.KeyFlagsPacket [0x01, 0x02]
144 ),
129 OpenPGP.unhashed_subpackets = [], 145 OpenPGP.unhashed_subpackets = [],
130 OpenPGP.signature = undefined, 146 OpenPGP.signature = undefined,
131 OpenPGP.trailer = undefined, 147 OpenPGP.trailer = undefined,
132 OpenPGP.hash_head = undefined 148 OpenPGP.hash_head = undefined
133 } 149 }
150
134 keyid' = reverse $ take 16 $ reverse $ fingerprint k 151 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 152 Just k = find_key keys keyid
137 Just dataP = find isLiteralData m 153
154 Just (OpenPGP.UserIDPacket firstUserID) = find isUserID m
155
156 defaultStype = case signOver of
157 OpenPGP.LiteralDataPacket {OpenPGP.format = f} ->
158 if f == 'b' then 0x00 else 0x01
159 _ -> 0x13
160
161 Just signOver = find isSignable m
138 OpenPGP.Message m = message 162 OpenPGP.Message m = message
139 isLiteralData (OpenPGP.LiteralDataPacket {}) = True 163
140 isLiteralData _ = False 164 isSignable (OpenPGP.LiteralDataPacket {}) = True
165 isSignable (OpenPGP.PublicKeyPacket {}) = True
166 isSignable (OpenPGP.SecretKeyPacket {}) = True
167 isSignable _ = False
168
169 isSignature (OpenPGP.SignaturePacket {}) = True
170 isSignature _ = False
171
172 isUserID (OpenPGP.UserIDPacket {}) = True
173 isUserID _ = False