diff options
Diffstat (limited to 'Data')
-rw-r--r-- | Data/OpenPGP.hs | 1 | ||||
-rw-r--r-- | Data/OpenPGP/Internal.hs | 2 | ||||
-rw-r--r-- | Data/OpenPGP/Util/Ed25519.hs | 116 | ||||
-rw-r--r-- | Data/OpenPGP/Util/Gen.hs | 16 | ||||
-rw-r--r-- | Data/OpenPGP/Util/Sign.hs | 2 |
5 files changed, 100 insertions, 37 deletions
diff --git a/Data/OpenPGP.hs b/Data/OpenPGP.hs index 3fc4311..45ca27e 100644 --- a/Data/OpenPGP.hs +++ b/Data/OpenPGP.hs | |||
@@ -360,6 +360,7 @@ secret_key_fields RSA_S = secret_key_fields RSA | |||
360 | secret_key_fields ELGAMAL = ['x'] | 360 | secret_key_fields ELGAMAL = ['x'] |
361 | secret_key_fields DSA = ['x'] | 361 | secret_key_fields DSA = ['x'] |
362 | secret_key_fields ECDSA = ['d'] | 362 | secret_key_fields ECDSA = ['d'] |
363 | secret_key_fields Ed25519 = ['d'] | ||
363 | secret_key_fields alg = error ("Unkown secret fields for "++show alg) -- Nothing in the spec. Maybe empty | 364 | secret_key_fields alg = error ("Unkown secret fields for "++show alg) -- Nothing in the spec. Maybe empty |
364 | 365 | ||
365 | (!) :: (HasCallStack, Show k, Eq k) => [(k,v)] -> k -> v | 366 | (!) :: (HasCallStack, Show k, Eq k) => [(k,v)] -> k -> v |
diff --git a/Data/OpenPGP/Internal.hs b/Data/OpenPGP/Internal.hs index f9a8803..a4cdc10 100644 --- a/Data/OpenPGP/Internal.hs +++ b/Data/OpenPGP/Internal.hs | |||
@@ -77,7 +77,6 @@ integerToBS i = BS.unsafeCreate (I# (word2Int# (sizeInBaseInteger i 256#))) $ \p | |||
77 | cnt <- exportIntegerToAddr i addr 1# -- 1# for big-endian (use 0# for little-endian) | 77 | cnt <- exportIntegerToAddr i addr 1# -- 1# for big-endian (use 0# for little-endian) |
78 | return () | 78 | return () |
79 | 79 | ||
80 | {- | ||
81 | getBigNumLE :: BS.ByteString -> Integer | 80 | getBigNumLE :: BS.ByteString -> Integer |
82 | getBigNumLE bytes = unsafeDupablePerformIO $ | 81 | getBigNumLE bytes = unsafeDupablePerformIO $ |
83 | let (fptr,offset,len) = BS.toForeignPtr bytes | 82 | let (fptr,offset,len) = BS.toForeignPtr bytes |
@@ -92,4 +91,3 @@ integerToLE i = BS.unsafeCreate (I# (word2Int# (sizeInBaseInteger i 256#))) $ \p | |||
92 | let Ptr addr = ptr | 91 | let Ptr addr = ptr |
93 | cnt <- exportIntegerToAddr i addr 0# | 92 | cnt <- exportIntegerToAddr i addr 0# |
94 | return () | 93 | return () |
95 | -} | ||
diff --git a/Data/OpenPGP/Util/Ed25519.hs b/Data/OpenPGP/Util/Ed25519.hs index ed277c8..7504e7e 100644 --- a/Data/OpenPGP/Util/Ed25519.hs +++ b/Data/OpenPGP/Util/Ed25519.hs | |||
@@ -1,51 +1,103 @@ | |||
1 | module Data.OpenPGP.Util.Ed25519 where | 1 | module Data.OpenPGP.Util.Ed25519 where |
2 | 2 | ||
3 | import Control.Monad | ||
3 | import Crypto.Error | 4 | import Crypto.Error |
4 | import qualified Crypto.PubKey.Ed25519 as Ed25519 | 5 | import qualified Crypto.PubKey.Ed25519 as Ed25519 |
5 | import Data.OpenPGP.Internal -- (integerToBS,integerToLE,getBigNumLE) | 6 | import Data.Bits |
6 | import qualified Data.OpenPGP as OpenPGP | 7 | import qualified Data.ByteArray as BA |
7 | import Crypto.ECC.Edwards25519 | 8 | import qualified Data.ByteString as BS |
9 | import qualified Data.ByteString.Lazy as BL | ||
8 | 10 | ||
9 | import qualified Data.ByteArray as BA | 11 | import qualified Data.OpenPGP as OpenPGP |
10 | import Control.Monad | 12 | import Data.OpenPGP (MPI(..)) |
11 | import qualified Data.ByteString as BS | 13 | import Data.OpenPGP.Internal |
12 | import qualified Data.ByteString.Lazy as BL | ||
13 | import Data.List | ||
14 | import Data.Int | ||
15 | import Data.Word | ||
16 | import Data.OpenPGP.Util.Base | 14 | import Data.OpenPGP.Util.Base |
15 | -- import Crypto.ECC.Edwards25519 | ||
17 | 16 | ||
18 | import Text.Printf | 17 | oid_ed25516 = 0x2B06010401DA470F01 |
19 | import Numeric | ||
20 | import Data.Char | ||
21 | import System.IO | ||
22 | 18 | ||
23 | import Foreign.Ptr | 19 | zeroExtend :: Int -> BS.ByteString -> BS.ByteString |
24 | import System.IO.Unsafe | 20 | zeroExtend n bs = case compare (BS.length bs) n of |
21 | GT -> BS.take n bs | ||
22 | EQ -> bs | ||
23 | LT -> bs <> BS.replicate (n - BS.length bs) 0 | ||
25 | 24 | ||
26 | import Crypto.Cipher.SBox | 25 | zeroPad :: Int -> BS.ByteString -> BS.ByteString |
26 | zeroPad n bs = case compare (BS.length bs) n of | ||
27 | GT -> BS.take n bs | ||
28 | EQ -> bs | ||
29 | LT -> BS.replicate (n - BS.length bs) 0 <> bs | ||
27 | 30 | ||
28 | ed25519Key :: OpenPGP.Packet -> Maybe Ed25519.PublicKey | 31 | ed25519Key :: OpenPGP.Packet -> Maybe Ed25519.PublicKey |
29 | ed25519Key k = case Ed25519.publicKey $ integerToBS $ keyParam 'n' k of | 32 | ed25519Key k = |
30 | CryptoPassed ed25519 -> Just ed25519 | 33 | let n = case keyParam 'f' k of |
31 | CryptoFailed err -> Nothing | 34 | 0x40 -> zeroPad 32 $ integerToBS $ keyParam 'n' k |
35 | _ -> | ||
36 | -- From Bernstein's "High-speed high-security signatures" | ||
37 | -- | ||
38 | -- An element (x, y) ∈ E is encoded as a b-bit string (x, y), namely the (b − | ||
39 | -- 1)- bit encoding of y followed by a sign bit; the sign bit is 1 iff x is | ||
40 | -- negative. This encoding immediately determines y, and it determines x via | ||
41 | -- the equation x = ± √(y² − 1)/(dy² + 1). | ||
42 | let y = keyParam 'y' k | ||
43 | x = keyParam 'x' k | ||
44 | ybs = zeroExtend 32 $ integerToLE y | ||
45 | lb = BS.last ybs | ||
46 | in if x < 0 then BS.take 31 ybs `BS.snoc` (lb .|. 1) | ||
47 | else BS.take 31 ybs `BS.snoc` (lb .&. 0xFE) | ||
48 | in case Ed25519.publicKey n of | ||
49 | CryptoPassed ed25519 -> Just ed25519 | ||
50 | CryptoFailed _ -> Nothing | ||
32 | 51 | ||
52 | ed25519sig :: OpenPGP.Packet -> Maybe Ed25519.Signature | ||
33 | ed25519sig sig = | 53 | ed25519sig sig = |
34 | let [OpenPGP.MPI r,OpenPGP.MPI s] = OpenPGP.signature sig | 54 | let [MPI r,MPI s] = OpenPGP.signature sig |
35 | -- rbs = BS.pack $ take 32 $ rbytes r ++ repeat 0 | 55 | rbs = zeroPad 32 $ integerToBS r |
36 | -- sbs = BS.pack $ take 32 $ rbytes s ++ repeat 0 | 56 | sbs = zeroPad 32 $ integerToBS s |
37 | rbs = let r' = integerToBS r in BS.replicate (32 - BS.length r') 0 <> r' | ||
38 | sbs = let s' = integerToBS s in BS.replicate (32 - BS.length s') 0 <> s' | ||
39 | in case Ed25519.signature (rbs <> sbs) of | 57 | in case Ed25519.signature (rbs <> sbs) of |
40 | CryptoPassed sig -> Just sig | 58 | CryptoPassed sig25519 -> Just sig25519 |
41 | CryptoFailed err -> Nothing | 59 | CryptoFailed _ -> Nothing |
60 | |||
61 | privateEd25519Key :: OpenPGP.Packet -> Ed25519.SecretKey | ||
62 | privateEd25519Key k = case Ed25519.secretKey $ zeroExtend 32 $ integerToLE (keyParam 'd' k) of | ||
63 | CryptoPassed ed25519sec -> ed25519sec | ||
64 | CryptoFailed err -> error $ "Ed25519.secretKey: " ++ show err | ||
42 | 65 | ||
43 | ed25519Verify :: OpenPGP.Packet -> BS.ByteString -> OpenPGP.Packet -> Maybe Bool | 66 | ed25519Verify :: OpenPGP.Packet -> BS.ByteString -> OpenPGP.Packet -> Maybe Bool |
44 | ed25519Verify sig over k = do | 67 | ed25519Verify sig over k = do |
45 | let hashbs = hashBySymbol (OpenPGP.hash_algorithm sig) $ BL.fromChunks [over] | 68 | let hashbs = hashBySymbol (OpenPGP.hash_algorithm sig) $ BL.fromChunks [over] |
46 | guard $ 0x2B06010401DA470F01 == keyParam 'c' k -- Only Ed25519 curve. | 69 | guard $ oid_ed25516 == keyParam 'c' k -- Only Ed25519 curve. |
47 | k' <- ed25519Key k -- SecretKeyPacket ??? | 70 | ek <- ed25519Key k |
48 | sig' <- ed25519sig sig | 71 | esig <- ed25519sig sig |
49 | let result = Ed25519.verify k' hashbs sig' | 72 | Just $ Ed25519.verify ek hashbs esig |
50 | Just result | 73 | |
74 | ed25519Sign :: OpenPGP.Packet -> OpenPGP.HashAlgorithm -> BS.ByteString -> [Integer] | ||
75 | ed25519Sign k hsh dta = [ getBigNum rbs, getBigNum sbs ] | ||
76 | where | ||
77 | hashbs = hashBySymbol hsh $ BL.fromChunks [dta] | ||
78 | sec = privateEd25519Key k | ||
79 | Just pub = ed25519Key k | ||
80 | sig = Ed25519.sign sec pub hashbs | ||
81 | (rbs,sbs) = BS.splitAt 32 $ BA.convert sig | ||
82 | |||
83 | importSecretEd25519 :: Ed25519.SecretKey -> [(Char,MPI)] | ||
84 | importSecretEd25519 k = | ||
85 | [ ('c', MPI oid_ed25516) | ||
86 | , ('l', MPI 128) | ||
87 | , ('n', MPI pub) | ||
88 | , ('f', MPI 0x40) | ||
89 | , ('d', MPI sec) | ||
90 | ] | ||
91 | where | ||
92 | pub = getBigNum $ BA.convert $ Ed25519.toPublic k | ||
93 | sec = getBigNumLE $ BA.convert k | ||
51 | 94 | ||
95 | importPublicEd25519 :: Ed25519.PublicKey -> [(Char,MPI)] | ||
96 | importPublicEd25519 k = | ||
97 | [ ('c', MPI oid_ed25516) | ||
98 | , ('l', MPI 128) | ||
99 | , ('n', MPI pub) | ||
100 | , ('f', MPI 0x40) | ||
101 | ] | ||
102 | where | ||
103 | pub = getBigNum $ BA.convert k | ||
diff --git a/Data/OpenPGP/Util/Gen.hs b/Data/OpenPGP/Util/Gen.hs index c5d0159..ca3c684 100644 --- a/Data/OpenPGP/Util/Gen.hs +++ b/Data/OpenPGP/Util/Gen.hs | |||
@@ -14,6 +14,8 @@ import qualified Crypto.PubKey.RSA as Vincent.RSA | |||
14 | import qualified Crypto.PubKey.RSA.PKCS15 as Vincent.RSA | 14 | import qualified Crypto.PubKey.RSA.PKCS15 as Vincent.RSA |
15 | import qualified Crypto.PubKey.ECC.ECDSA as Vincent.ECDSA | 15 | import qualified Crypto.PubKey.ECC.ECDSA as Vincent.ECDSA |
16 | #if defined(VERSION_cryptonite) | 16 | #if defined(VERSION_cryptonite) |
17 | import qualified Crypto.PubKey.Ed25519 as Ed25519 | ||
18 | import Data.OpenPGP.Util.Ed25519 | ||
17 | import Control.Arrow (second) | 19 | import Control.Arrow (second) |
18 | import Data.Binary | 20 | import Data.Binary |
19 | #endif | 21 | #endif |
@@ -22,7 +24,7 @@ import Data.OpenPGP.Util.Base | |||
22 | 24 | ||
23 | data GenerateKeyParams = GenRSA Int -- keysize | 25 | data GenerateKeyParams = GenRSA Int -- keysize |
24 | | GenDSA (Maybe DSAParams) | 26 | | GenDSA (Maybe DSAParams) |
25 | 27 | | GenEd25519 | |
26 | deriving (Eq,Ord,Show) | 28 | deriving (Eq,Ord,Show) |
27 | 29 | ||
28 | data DSAParams = DSAParams | 30 | data DSAParams = DSAParams |
@@ -32,8 +34,9 @@ data DSAParams = DSAParams | |||
32 | deriving (Eq,Ord,Show) | 34 | deriving (Eq,Ord,Show) |
33 | 35 | ||
34 | genKeyAlg :: GenerateKeyParams -> KeyAlgorithm | 36 | genKeyAlg :: GenerateKeyParams -> KeyAlgorithm |
35 | genKeyAlg (GenRSA _) = RSA | 37 | genKeyAlg (GenRSA _) = RSA |
36 | genKeyAlg (GenDSA _) = DSA | 38 | genKeyAlg (GenDSA _) = DSA |
39 | genKeyAlg (GenEd25519 {}) = Ed25519 | ||
37 | 40 | ||
38 | -- | Generate a secret key pgp packet from system entropy. | 41 | -- | Generate a secret key pgp packet from system entropy. |
39 | generateKey :: GenerateKeyParams -> IO Packet | 42 | generateKey :: GenerateKeyParams -> IO Packet |
@@ -115,6 +118,13 @@ generateKey' (GenDSA mbparams) g = | |||
115 | vincent (DSAParams p g q) = Vincent.DSA.Params p g q | 118 | vincent (DSAParams p g q) = Vincent.DSA.Params p g q |
116 | (priv,g') = withDRG g $ Vincent.DSA.generatePrivate dsa_params | 119 | (priv,g') = withDRG g $ Vincent.DSA.generatePrivate dsa_params |
117 | in ( dsaFields (Vincent.DSA.PrivateKey dsa_params priv), g' ) | 120 | in ( dsaFields (Vincent.DSA.PrivateKey dsa_params priv), g' ) |
121 | generateKey' (GenEd25519 {}) g = withDRG g $ do | ||
122 | k <- Ed25519.generateSecretKey | ||
123 | return $ importSecretEd25519 k | ||
124 | -- file:///usr/share/doc/libghc-cryptonite-doc/html/Crypto-PubKey-Ed25519.html#v:generateSecretKey | ||
125 | -- generateSecretKey :: MonadRandom m => m SecretKey | ||
126 | -- n = public key used to verify signatures. | ||
127 | -- public_key_fields Ed25519 = ['c','l','x', 'y', 'n', 'f'] | ||
118 | 128 | ||
119 | #endif | 129 | #endif |
120 | 130 | ||
diff --git a/Data/OpenPGP/Util/Sign.hs b/Data/OpenPGP/Util/Sign.hs index d96c3a7..085d545 100644 --- a/Data/OpenPGP/Util/Sign.hs +++ b/Data/OpenPGP/Util/Sign.hs | |||
@@ -17,6 +17,7 @@ import Data.Time.Clock.POSIX | |||
17 | #endif | 17 | #endif |
18 | import Control.Exception as Exception (IOException(..),catch) | 18 | import Control.Exception as Exception (IOException(..),catch) |
19 | 19 | ||
20 | import Data.OpenPGP.Util.Ed25519 | ||
20 | import Data.OpenPGP.Util.Fingerprint (fingerprint) | 21 | import Data.OpenPGP.Util.Fingerprint (fingerprint) |
21 | import Data.OpenPGP.Util.Gen | 22 | import Data.OpenPGP.Util.Gen |
22 | 23 | ||
@@ -69,6 +70,7 @@ unsafeSign keys over hsh keyid timestamp g = (over {OpenPGP.signatures_over = [s | |||
69 | (final, g') = case OpenPGP.key_algorithm sig of | 70 | (final, g') = case OpenPGP.key_algorithm sig of |
70 | OpenPGP.DSA -> ([dsaR, dsaS], dsaG) | 71 | OpenPGP.DSA -> ([dsaR, dsaS], dsaG) |
71 | OpenPGP.ECDSA -> ([ecdsaR,ecdsaS],ecdsaG) | 72 | OpenPGP.ECDSA -> ([ecdsaR,ecdsaS],ecdsaG) |
73 | OpenPGP.Ed25519 -> (ed25519Sign k hsh dta, g) | ||
72 | kalgo | kalgo `elem` [OpenPGP.RSA,OpenPGP.RSA_S] -> ([toNum rsaFinal], g) | 74 | kalgo | kalgo `elem` [OpenPGP.RSA,OpenPGP.RSA_S] -> ([toNum rsaFinal], g) |
73 | | otherwise -> | 75 | | otherwise -> |
74 | error ("Unsupported key algorithm " ++ show kalgo ++ " in sign") | 76 | error ("Unsupported key algorithm " ++ show kalgo ++ " in sign") |