summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Crayne <joe@jerkface.net>2020-05-16 08:32:17 -0400
committerJoe Crayne <joe@jerkface.net>2020-05-19 11:58:22 -0400
commitff5c89ee76c707228afc66afac573c6fd0efffa3 (patch)
tree93b3ab9bcfe674582895eea8c0ce6b9eff88f558
parent8fdfd0fc119519041683bc74e9d7a35231728ae3 (diff)
Refactor toward draft-ietf-openpgp-rfc4880bis-09.
-rw-r--r--Data/OpenPGP.hs7
-rw-r--r--Data/OpenPGP/Internal.hs86
-rw-r--r--Data/OpenPGP/Util/Base.hs3
-rw-r--r--Data/OpenPGP/Util/Cv25519.hs13
-rw-r--r--Data/OpenPGP/Util/Decrypt.hs4
-rw-r--r--Data/OpenPGP/Util/DecryptSecretKey.hs25
-rw-r--r--Data/OpenPGP/Util/Fingerprint.hs10
-rw-r--r--Data/OpenPGP/Util/Sign.hs2
-rw-r--r--Data/OpenPGP/Util/Verify.hs4
9 files changed, 89 insertions, 65 deletions
diff --git a/Data/OpenPGP.hs b/Data/OpenPGP.hs
index 4133f38..f05f83e 100644
--- a/Data/OpenPGP.hs
+++ b/Data/OpenPGP.hs
@@ -129,9 +129,6 @@ compress algo = toStrictBS . lazyCompress algo . toLazyBS
129decompress :: CompressionAlgorithm -> B.ByteString -> B.ByteString 129decompress :: CompressionAlgorithm -> B.ByteString -> B.ByteString
130decompress algo = toStrictBS . lazyDecompress algo . toLazyBS 130decompress algo = toStrictBS . lazyDecompress algo . toLazyBS
131 131
132toStrictBS :: LZ.ByteString -> B.ByteString
133toStrictBS = B.concat . LZ.toChunks
134
135toLazyBS :: B.ByteString -> LZ.ByteString 132toLazyBS :: B.ByteString -> LZ.ByteString
136toLazyBS = LZ.fromChunks . (:[]) 133toLazyBS = LZ.fromChunks . (:[])
137 134
@@ -194,10 +191,6 @@ pad l s = replicate (l - length s) '0' ++ s
194padBS :: Int -> B.ByteString -> B.ByteString 191padBS :: Int -> B.ByteString -> B.ByteString
195padBS l s = B.replicate (fromIntegral l - B.length s) 0 `B.append` s 192padBS l s = B.replicate (fromIntegral l - B.length s) 0 `B.append` s
196 193
197checksum :: B.ByteString -> Word16
198checksum = fromIntegral .
199 B.foldl (\c i -> (c + fromIntegral i) `mod` 65536) (0::Integer)
200
201data Packet = 194data Packet =
202 AsymmetricSessionKeyPacket { 195 AsymmetricSessionKeyPacket {
203 version :: Word8, 196 version :: Word8,
diff --git a/Data/OpenPGP/Internal.hs b/Data/OpenPGP/Internal.hs
index a4cdc10..a62923a 100644
--- a/Data/OpenPGP/Internal.hs
+++ b/Data/OpenPGP/Internal.hs
@@ -1,17 +1,47 @@
1{-# LANGUAGE BangPatterns, MagicHash #-} 1{-# LANGUAGE BangPatterns #-}
2{-# LANGUAGE CPP #-}
3{-# LANGUAGE MagicHash #-}
2module Data.OpenPGP.Internal where 4module Data.OpenPGP.Internal where
3 5
4import Data.Bits 6import Data.Bits
5import qualified Data.ByteString as BS 7import qualified Data.ByteString as BS
6import qualified Data.ByteString.Internal as BS 8import qualified Data.ByteString.Internal as BS
7import Data.Word 9import qualified Data.ByteString.Lazy as BL
8import Foreign.ForeignPtr 10import Data.Char
9import Foreign.Ptr 11import Data.Int
10import Foreign.Storable 12import Data.Word
11import GHC.Exts 13import Foreign.ForeignPtr
12import GHC.Integer.GMP.Internals 14import Foreign.Ptr
13import System.Endian 15import Foreign.Storable
14import System.IO.Unsafe 16import GHC.Exts
17import GHC.Integer.GMP.Internals
18import System.Endian
19import System.IO.Unsafe
20import Numeric (showHex)
21
22#if defined(VERSION_cryptonite)
23import qualified Data.ByteArray as Bytes
24import Crypto.Hash.Algorithms
25import Crypto.Hash
26import Crypto.Error
27#else
28import qualified Data.Byteable as Vincent
29import Crypto.Hash.SHA1 as SHA1
30#endif
31
32#ifdef CEREAL
33import qualified Data.ByteString as B
34import qualified Data.ByteString.UTF8 as B (fromString, toString)
35import Data.Serialize
36#define BINARY_CLASS Serialize
37#else
38import Data.Binary
39import Data.Binary.Get
40import Data.Binary.Put
41import qualified Data.ByteString.Lazy as B
42import qualified Data.ByteString.Lazy.UTF8 as B (fromString, toString)
43#define BINARY_CLASS Binary
44#endif
15 45
16 46
17 47
@@ -91,3 +121,35 @@ integerToLE i = BS.unsafeCreate (I# (word2Int# (sizeInBaseInteger i 256#))) $ \p
91 let Ptr addr = ptr 121 let Ptr addr = ptr
92 cnt <- exportIntegerToAddr i addr 0# 122 cnt <- exportIntegerToAddr i addr 0#
93 return () 123 return ()
124
125toStrictBS :: B.ByteString -> BS.ByteString
126toStrictBS = BS.concat . B.toChunks
127
128checksum :: B.ByteString -> Word16
129checksum = fromIntegral .
130 B.foldl (\c i -> (c + fromIntegral i) `mod` 65536) (0::Integer)
131
132
133checksumForKey :: Word8 {- s2k_usage byte -} -> (Int64, B.ByteString -> BS.ByteString)
134checksumForKey 254 = (20, sha1 . toStrictBS)
135 where
136#if defined(VERSION_cryptonite)
137 sha1 x = Bytes.convert (hash x :: Digest SHA1)
138#else
139 sha1 = SHA1.hash
140#endif
141checksumForKey _ = (2, toStrictBS . encode . checksum)
142 -- Words16s are written as 2 bytes in big-endian (network) order
143
144hexString :: [Word8] -> String
145hexString = foldr (pad `oo` showHex) ""
146 where
147 pad s | odd $ length s = '0':s
148 | otherwise = s
149
150 oo :: (b -> c) -> (a -> a1 -> b) -> a -> a1 -> c
151 oo = (.) . (.)
152
153hexify :: BS.ByteString -> String
154hexify = map toUpper . hexString . BS.unpack
155
diff --git a/Data/OpenPGP/Util/Base.hs b/Data/OpenPGP/Util/Base.hs
index b43427c..431c12c 100644
--- a/Data/OpenPGP/Util/Base.hs
+++ b/Data/OpenPGP/Util/Base.hs
@@ -76,9 +76,6 @@ ecdsaKey k = Vincent.ECDSA.PublicKey curve (Vincent.ECDSA.Point x y)
76 curve = curveFromOID (keyParam 'c' k) 76 curve = curveFromOID (keyParam 'c' k)
77 77
78 78
79toStrictBS :: LZ.ByteString -> BS.ByteString
80toStrictBS = BS.concat . LZ.toChunks
81
82toLazyBS :: BS.ByteString -> LZ.ByteString 79toLazyBS :: BS.ByteString -> LZ.ByteString
83toLazyBS = LZ.fromChunks . (:[]) 80toLazyBS = LZ.fromChunks . (:[])
84 81
diff --git a/Data/OpenPGP/Util/Cv25519.hs b/Data/OpenPGP/Util/Cv25519.hs
index abf1ba6..bc1cacb 100644
--- a/Data/OpenPGP/Util/Cv25519.hs
+++ b/Data/OpenPGP/Util/Cv25519.hs
@@ -67,19 +67,6 @@ privateCv25519Key k@SecretKeyPacket { key_algorithm = ECC, symmetric_algorithm =
67 CryptoPassed cv25519sec -> Just cv25519sec 67 CryptoPassed cv25519sec -> Just cv25519sec
68 CryptoFailed err -> Nothing 68 CryptoFailed err -> Nothing
69 69
70hexify = map toUpper . hexString . BS.unpack
71
72
73
74hexString :: [Word8] -> String
75hexString = foldr (pad `oo` showHex) ""
76 where
77 pad s | odd $ length s = '0':s
78 | otherwise = s
79
80 oo :: (b -> c) -> (a -> a1 -> b) -> a -> a1 -> c
81 oo = (.) . (.)
82
83cv25519Key :: [(Char,MPI)] -> Maybe Cv25519.PublicKey 70cv25519Key :: [(Char,MPI)] -> Maybe Cv25519.PublicKey
84cv25519Key k = do 71cv25519Key k = do
85 MPI flag <- lookup 'f' k 72 MPI flag <- lookup 'f' k
diff --git a/Data/OpenPGP/Util/Decrypt.hs b/Data/OpenPGP/Util/Decrypt.hs
index 84bead5..637d754 100644
--- a/Data/OpenPGP/Util/Decrypt.hs
+++ b/Data/OpenPGP/Util/Decrypt.hs
@@ -14,7 +14,7 @@ import Data.OpenPGP.Util.Base
14 14
15-- decryption codec for withS2K 15-- decryption codec for withS2K
16simpleUnCFB :: (Vincent.BlockCipher k) => k -> Vincent.IV k -> LZ.ByteString -> LZ.ByteString 16simpleUnCFB :: (Vincent.BlockCipher k) => k -> Vincent.IV k -> LZ.ByteString -> LZ.ByteString
17simpleUnCFB k iv = padThenUnpad k (toLazyBS . Vincent.cfbDecrypt k iv . toStrictBS) 17simpleUnCFB k iv = padThenUnpad k (toLazyBS . Vincent.cfbDecrypt k iv . LZ.toStrict)
18 18
19withS2K' :: OpenPGP.SymmetricAlgorithm -> Maybe OpenPGP.S2K -> LZ.ByteString 19withS2K' :: OpenPGP.SymmetricAlgorithm -> Maybe OpenPGP.S2K -> LZ.ByteString
20 -> (forall b. Vincent.BlockCipher b => b -> x) -> x 20 -> (forall b. Vincent.BlockCipher b => b -> x) -> x
@@ -29,7 +29,7 @@ string2key ms2k s = cipher
29 where 29 where
30#if defined(VERSION_cryptonite) 30#if defined(VERSION_cryptonite)
31 CryptoPassed cipher = Vincent.cipherInit k 31 CryptoPassed cipher = Vincent.cipherInit k
32 k = toStrictBS $ LZ.take ksize $ maybe s (\s2k -> OpenPGP.string2key hashBySymbol s2k s) ms2k 32 k = LZ.toStrict $ LZ.take ksize $ maybe s (\s2k -> OpenPGP.string2key hashBySymbol s2k s) ms2k
33#else 33#else
34 cipher = Vincent.cipherInit k 34 cipher = Vincent.cipherInit k
35 Right k = Vincent.makeKey $ toStrictBS $ 35 Right k = Vincent.makeKey $ toStrictBS $
diff --git a/Data/OpenPGP/Util/DecryptSecretKey.hs b/Data/OpenPGP/Util/DecryptSecretKey.hs
index 57dd8c3..9f9e42a 100644
--- a/Data/OpenPGP/Util/DecryptSecretKey.hs
+++ b/Data/OpenPGP/Util/DecryptSecretKey.hs
@@ -4,10 +4,11 @@
4module Data.OpenPGP.Util.DecryptSecretKey where 4module Data.OpenPGP.Util.DecryptSecretKey where
5 5
6import qualified Data.OpenPGP as OpenPGP 6import qualified Data.OpenPGP as OpenPGP
7import Data.OpenPGP.Internal (decode_s2k_count) 7import Data.OpenPGP.Internal (decode_s2k_count,checksumForKey)
8import qualified Data.ByteString as BS 8import qualified Data.ByteString as BS
9import qualified Data.ByteString.Lazy as LZ 9import qualified Data.ByteString.Lazy as LZ
10import Data.Word (Word16) 10import Data.Word
11import Data.Int
11import Data.Maybe 12import Data.Maybe
12import Control.Monad (foldM) 13import Control.Monad (foldM)
13import Data.Binary (get,Binary,Get,encode,put) 14import Data.Binary (get,Binary,Get,encode,put)
@@ -53,7 +54,7 @@ data Enciphered =
53withIV :: forall k. (Vincent.BlockCipher k) => (Vincent.IV k -> LZ.ByteString -> LZ.ByteString) -> Enciphered -> LZ.ByteString 54withIV :: forall k. (Vincent.BlockCipher k) => (Vincent.IV k -> LZ.ByteString -> LZ.ByteString) -> Enciphered -> LZ.ByteString
54withIV f (EncipheredWithIV s) = f iv bs 55withIV f (EncipheredWithIV s) = f iv bs
55 where 56 where
56 Just iv = Vincent.makeIV (toStrictBS ivbs) 57 Just iv = Vincent.makeIV (LZ.toStrict ivbs)
57 (ivbs,bs) = LZ.splitAt (fromIntegral ivlen) s 58 (ivbs,bs) = LZ.splitAt (fromIntegral ivlen) s
58#if defined(VERSION_cryptonite) 59#if defined(VERSION_cryptonite)
59 ivlen = Bytes.length (Vincent.nullIV :: Vincent.IV k) 60 ivlen = Bytes.length (Vincent.nullIV :: Vincent.IV k)
@@ -64,6 +65,7 @@ withIV f (EncipheredWithIV s) = f iv bs
64#endif 65#endif
65withIV f (EncipheredZeroIV s) = f Vincent.nullIV s 66withIV f (EncipheredZeroIV s) = f Vincent.nullIV s
66 67
68
67decryptSecretKey :: 69decryptSecretKey ::
68 BS.ByteString -- ^ Passphrase 70 BS.ByteString -- ^ Passphrase
69 -> OpenPGP.Packet -- ^ Encrypted SecretKeyPacket 71 -> OpenPGP.Packet -- ^ Encrypted SecretKeyPacket
@@ -74,7 +76,7 @@ decryptSecretKey pass k@(OpenPGP.SecretKeyPacket {
74 OpenPGP.version = 4, OpenPGP.key_algorithm = kalgo, 76 OpenPGP.version = 4, OpenPGP.key_algorithm = kalgo,
75 OpenPGP.s2k = s2k, OpenPGP.symmetric_algorithm = salgo, 77 OpenPGP.s2k = s2k, OpenPGP.symmetric_algorithm = salgo,
76 OpenPGP.key = existing, OpenPGP.encrypted_data = encd 78 OpenPGP.key = existing, OpenPGP.encrypted_data = encd
77 }) | chkF material == toStrictBS chk = 79 }) | chkF material == LZ.toStrict chk =
78 fmap (\m -> k { 80 fmap (\m -> k {
79 OpenPGP.s2k_useage = 0, 81 OpenPGP.s2k_useage = 0,
80 OpenPGP.symmetric_algorithm = OpenPGP.Unencrypted, 82 OpenPGP.symmetric_algorithm = OpenPGP.Unencrypted,
@@ -87,18 +89,9 @@ decryptSecretKey pass k@(OpenPGP.SecretKeyPacket {
87 (foldM (\m f -> do {mpi <- get; return $ (f,mpi):m}) existing 89 (foldM (\m f -> do {mpi <- get; return $ (f,mpi):m}) existing
88 (OpenPGP.secret_key_fields kalgo)) material 90 (OpenPGP.secret_key_fields kalgo)) material
89 (material, chk) = LZ.splitAt (LZ.length decd - chkSize) decd 91 (material, chk) = LZ.splitAt (LZ.length decd - chkSize) decd
90 (chkSize, chkF) 92 (chkSize, chkF) = checksumForKey (OpenPGP.s2k_useage k)
91 | OpenPGP.s2k_useage k == 254 = (20, sha1 . toStrictBS)
92 | otherwise = (2, toStrictBS . encode . checksum . toStrictBS)
93 -- Words16s are written as 2 bytes in big-endian (network) order
94 decd = withS2K simpleUnCFB salgo (Just s2k) (toLazyBS pass) (EncipheredWithIV encd) 93 decd = withS2K simpleUnCFB salgo (Just s2k) (toLazyBS pass) (EncipheredWithIV encd)
95 94
96#if defined(VERSION_cryptonite)
97 sha1 x = Bytes.convert (hash x :: Digest SHA1)
98#else
99 sha1 = SHA1.hash
100#endif
101
102decryptSecretKey _ _ = Nothing 95decryptSecretKey _ _ = Nothing
103 96
104checksum :: BS.ByteString -> Word16 97checksum :: BS.ByteString -> Word16
@@ -133,7 +126,7 @@ withS2K codec OpenPGP.CAST5 s2k s = withIV $ codec (string2key s2k s :: Thoma
133withS2K codec algo _ _ = error $ "Unsupported symmetric algorithm : " ++ show algo ++ " in Data.OpenPGP.CryptoAPI.withS2K" 126withS2K codec algo _ _ = error $ "Unsupported symmetric algorithm : " ++ show algo ++ " in Data.OpenPGP.CryptoAPI.withS2K"
134 127
135simpleCFB :: forall k g. (Vincent.BlockCipher k, RG g) => g -> k -> LZ.ByteString -> (LZ.ByteString, g) 128simpleCFB :: forall k g. (Vincent.BlockCipher k, RG g) => g -> k -> LZ.ByteString -> (LZ.ByteString, g)
136simpleCFB g k bs = ( padThenUnpad k (LZ.fromChunks . (ivbs:) . (:[]) . Vincent.cfbEncrypt k iv . toStrictBS) bs 129simpleCFB g k bs = ( padThenUnpad k (LZ.fromChunks . (ivbs:) . (:[]) . Vincent.cfbEncrypt k iv . LZ.toStrict) bs
137 , g' ) 130 , g' )
138 where 131 where
139 Just iv = Vincent.makeIV ivbs 132 Just iv = Vincent.makeIV ivbs
@@ -180,7 +173,7 @@ encryptSecretKey passphrase s2k salgo plain = do
180 -- two-octet checksum is required. 173 -- two-octet checksum is required.
181 s2k_usage_octet = 255 174 s2k_usage_octet = 255
182 -- chkSize = 2 175 -- chkSize = 2
183 chkF = toStrictBS . encode . checksum . toStrictBS 176 chkF = LZ.toStrict . encode . checksum . LZ.toStrict
184 177
185 178
186 -- k = string2key s2k passphrase -- OpenPGP.string2key hashBySymbol s2k passphrase 179 -- k = string2key s2k passphrase -- OpenPGP.string2key hashBySymbol s2k passphrase
diff --git a/Data/OpenPGP/Util/Fingerprint.hs b/Data/OpenPGP/Util/Fingerprint.hs
index cda25f6..955748d 100644
--- a/Data/OpenPGP/Util/Fingerprint.hs
+++ b/Data/OpenPGP/Util/Fingerprint.hs
@@ -2,6 +2,7 @@
2module Data.OpenPGP.Util.Fingerprint (fingerprint,fingerprintv,Fingerprint(..),hex) where 2module Data.OpenPGP.Util.Fingerprint (fingerprint,fingerprintv,Fingerprint(..),hex) where
3 3
4import qualified Data.OpenPGP as OpenPGP 4import qualified Data.OpenPGP as OpenPGP
5import Data.OpenPGP.Internal
5import qualified Data.ByteString as BS 6import qualified Data.ByteString as BS
6import qualified Data.ByteString.Lazy as LZ 7import qualified Data.ByteString.Lazy as LZ
7import Data.Char (toUpper) 8import Data.Char (toUpper)
@@ -28,15 +29,6 @@ instance Show Fingerprint where
28 29
29hex :: Fingerprint -> String 30hex :: Fingerprint -> String
30hex (Fingerprint bs) = hexify bs 31hex (Fingerprint bs) = hexify bs
31 where
32 hexify = map toUpper . hexString . BS.unpack
33
34 hexString :: [Word8] -> String
35 hexString = foldr (pad `oo` showHex) ""
36 where
37 pad s | odd $ length s = '0':s
38 | otherwise = s
39
40 32
41-- | Generate a key fingerprint from a PublicKeyPacket or SecretKeyPacket 33-- | Generate a key fingerprint from a PublicKeyPacket or SecretKeyPacket
42-- <http://tools.ietf.org/html/rfc4880#section-12.2> 34-- <http://tools.ietf.org/html/rfc4880#section-12.2>
diff --git a/Data/OpenPGP/Util/Sign.hs b/Data/OpenPGP/Util/Sign.hs
index b9c6435..a074dcb 100644
--- a/Data/OpenPGP/Util/Sign.hs
+++ b/Data/OpenPGP/Util/Sign.hs
@@ -113,7 +113,7 @@ unsafeSign keys over hsh keyid timestamp g = (over {OpenPGP.signatures_over = [s
113 (Right rsaFinal,_) = Vincent.RSA.signSafer g desc (privateRSAkey k) dta 113 (Right rsaFinal,_) = Vincent.RSA.signSafer g desc (privateRSAkey k) dta
114#endif 114#endif
115 dsaTruncate (Vincent.DSA.PrivateKey (Vincent.DSA.Params _ _ q) _) = BS.take (integerBytesize q) 115 dsaTruncate (Vincent.DSA.PrivateKey (Vincent.DSA.Params _ _ q) _) = BS.take (integerBytesize q)
116 dta = toStrictBS $ encode over `LZ.append` OpenPGP.trailer sig 116 dta = LZ.toStrict $ encode over `LZ.append` OpenPGP.trailer sig
117 sig = findSigOrDefault (listToMaybe $ OpenPGP.signatures_over over) 117 sig = findSigOrDefault (listToMaybe $ OpenPGP.signatures_over over)
118 -- padding = emsa_pkcs1_v1_5_hash_padding hsh 118 -- padding = emsa_pkcs1_v1_5_hash_padding hsh
119 desc = hashAlgoDesc hsh 119 desc = hashAlgoDesc hsh
diff --git a/Data/OpenPGP/Util/Verify.hs b/Data/OpenPGP/Util/Verify.hs
index 66db2ab..52e9005 100644
--- a/Data/OpenPGP/Util/Verify.hs
+++ b/Data/OpenPGP/Util/Verify.hs
@@ -46,7 +46,7 @@ verify keys over =
46 over {OpenPGP.signatures_over = mapMaybe (uncurry $ verifyOne keys) sigs} 46 over {OpenPGP.signatures_over = mapMaybe (uncurry $ verifyOne keys) sigs}
47 where 47 where
48 sigs :: [(OpenPGP.Packet,BS.ByteString)] 48 sigs :: [(OpenPGP.Packet,BS.ByteString)]
49 sigs = map (\s -> (s, toStrictBS $ encode over `LZ.append` OpenPGP.trailer s)) 49 sigs = map (\s -> (s, LZ.toStrict $ encode over `LZ.append` OpenPGP.trailer s))
50 (OpenPGP.signatures_over over) 50 (OpenPGP.signatures_over over)
51 51
52verifyOne :: OpenPGP.Message -> OpenPGP.Packet -> BS.ByteString -> Maybe OpenPGP.Packet 52verifyOne :: OpenPGP.Message -> OpenPGP.Packet -> BS.ByteString -> Maybe OpenPGP.Packet
@@ -93,7 +93,7 @@ verifyOne keys sig over = fmap (const sig) $ maybeKey >>= verification >>= guard
93#else 93#else
94 rsaVerify k = Just $ Vincent.RSA.verify desc (rsaKey k) over rsaSig 94 rsaVerify k = Just $ Vincent.RSA.verify desc (rsaKey k) over rsaSig
95#endif 95#endif
96 [rsaSig] = map (toStrictBS . LZ.drop 2 . encode) (OpenPGP.signature sig) 96 [rsaSig] = map (LZ.toStrict . LZ.drop 2 . encode) (OpenPGP.signature sig)
97 dsaSig = let [OpenPGP.MPI r, OpenPGP.MPI s] = OpenPGP.signature sig in 97 dsaSig = let [OpenPGP.MPI r, OpenPGP.MPI s] = OpenPGP.signature sig in
98 Vincent.DSA.Signature r s 98 Vincent.DSA.Signature r s
99 ecdsaSig = let [OpenPGP.MPI r, OpenPGP.MPI s] = OpenPGP.signature sig in 99 ecdsaSig = let [OpenPGP.MPI r, OpenPGP.MPI s] = OpenPGP.signature sig in