summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Crayne <joe@jerkface.net>2019-11-10 14:27:48 -0500
committerJoe Crayne <joe@jerkface.net>2019-11-10 14:27:48 -0500
commit76bf7e08bccbb1a3a689068016b8a9c29d1e060e (patch)
tree965b4e2d0b0220b2bb839874c58c3ffcfac0ddff
parentd0a13aa249c23d3521cc9654bf450923d849578f (diff)
Ed25519 secret portion (create + sign).
-rw-r--r--Data/OpenPGP.hs1
-rw-r--r--Data/OpenPGP/Internal.hs2
-rw-r--r--Data/OpenPGP/Util/Ed25519.hs116
-rw-r--r--Data/OpenPGP/Util/Gen.hs16
-rw-r--r--Data/OpenPGP/Util/Sign.hs2
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
360secret_key_fields ELGAMAL = ['x'] 360secret_key_fields ELGAMAL = ['x']
361secret_key_fields DSA = ['x'] 361secret_key_fields DSA = ['x']
362secret_key_fields ECDSA = ['d'] 362secret_key_fields ECDSA = ['d']
363secret_key_fields Ed25519 = ['d']
363secret_key_fields alg = error ("Unkown secret fields for "++show alg) -- Nothing in the spec. Maybe empty 364secret_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{-
81getBigNumLE :: BS.ByteString -> Integer 80getBigNumLE :: BS.ByteString -> Integer
82getBigNumLE bytes = unsafeDupablePerformIO $ 81getBigNumLE 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 @@
1module Data.OpenPGP.Util.Ed25519 where 1module Data.OpenPGP.Util.Ed25519 where
2 2
3import Control.Monad
3import Crypto.Error 4import Crypto.Error
4import qualified Crypto.PubKey.Ed25519 as Ed25519 5import qualified Crypto.PubKey.Ed25519 as Ed25519
5import Data.OpenPGP.Internal -- (integerToBS,integerToLE,getBigNumLE) 6import Data.Bits
6import qualified Data.OpenPGP as OpenPGP 7import qualified Data.ByteArray as BA
7import Crypto.ECC.Edwards25519 8import qualified Data.ByteString as BS
9import qualified Data.ByteString.Lazy as BL
8 10
9import qualified Data.ByteArray as BA 11import qualified Data.OpenPGP as OpenPGP
10import Control.Monad 12import Data.OpenPGP (MPI(..))
11import qualified Data.ByteString as BS 13import Data.OpenPGP.Internal
12import qualified Data.ByteString.Lazy as BL
13import Data.List
14import Data.Int
15import Data.Word
16import Data.OpenPGP.Util.Base 14import Data.OpenPGP.Util.Base
15-- import Crypto.ECC.Edwards25519
17 16
18import Text.Printf 17oid_ed25516 = 0x2B06010401DA470F01
19import Numeric
20import Data.Char
21import System.IO
22 18
23import Foreign.Ptr 19zeroExtend :: Int -> BS.ByteString -> BS.ByteString
24import System.IO.Unsafe 20zeroExtend 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
26import Crypto.Cipher.SBox 25zeroPad :: Int -> BS.ByteString -> BS.ByteString
26zeroPad 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
28ed25519Key :: OpenPGP.Packet -> Maybe Ed25519.PublicKey 31ed25519Key :: OpenPGP.Packet -> Maybe Ed25519.PublicKey
29ed25519Key k = case Ed25519.publicKey $ integerToBS $ keyParam 'n' k of 32ed25519Key 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
52ed25519sig :: OpenPGP.Packet -> Maybe Ed25519.Signature
33ed25519sig sig = 53ed25519sig 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
61privateEd25519Key :: OpenPGP.Packet -> Ed25519.SecretKey
62privateEd25519Key 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
43ed25519Verify :: OpenPGP.Packet -> BS.ByteString -> OpenPGP.Packet -> Maybe Bool 66ed25519Verify :: OpenPGP.Packet -> BS.ByteString -> OpenPGP.Packet -> Maybe Bool
44ed25519Verify sig over k = do 67ed25519Verify 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
74ed25519Sign :: OpenPGP.Packet -> OpenPGP.HashAlgorithm -> BS.ByteString -> [Integer]
75ed25519Sign 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
83importSecretEd25519 :: Ed25519.SecretKey -> [(Char,MPI)]
84importSecretEd25519 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
95importPublicEd25519 :: Ed25519.PublicKey -> [(Char,MPI)]
96importPublicEd25519 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
14import qualified Crypto.PubKey.RSA.PKCS15 as Vincent.RSA 14import qualified Crypto.PubKey.RSA.PKCS15 as Vincent.RSA
15import qualified Crypto.PubKey.ECC.ECDSA as Vincent.ECDSA 15import qualified Crypto.PubKey.ECC.ECDSA as Vincent.ECDSA
16#if defined(VERSION_cryptonite) 16#if defined(VERSION_cryptonite)
17import qualified Crypto.PubKey.Ed25519 as Ed25519
18import Data.OpenPGP.Util.Ed25519
17import Control.Arrow (second) 19import Control.Arrow (second)
18import Data.Binary 20import Data.Binary
19#endif 21#endif
@@ -22,7 +24,7 @@ import Data.OpenPGP.Util.Base
22 24
23data GenerateKeyParams = GenRSA Int -- keysize 25data 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
28data DSAParams = DSAParams 30data DSAParams = DSAParams
@@ -32,8 +34,9 @@ data DSAParams = DSAParams
32 deriving (Eq,Ord,Show) 34 deriving (Eq,Ord,Show)
33 35
34genKeyAlg :: GenerateKeyParams -> KeyAlgorithm 36genKeyAlg :: GenerateKeyParams -> KeyAlgorithm
35genKeyAlg (GenRSA _) = RSA 37genKeyAlg (GenRSA _) = RSA
36genKeyAlg (GenDSA _) = DSA 38genKeyAlg (GenDSA _) = DSA
39genKeyAlg (GenEd25519 {}) = Ed25519
37 40
38-- | Generate a secret key pgp packet from system entropy. 41-- | Generate a secret key pgp packet from system entropy.
39generateKey :: GenerateKeyParams -> IO Packet 42generateKey :: 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' )
121generateKey' (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
18import Control.Exception as Exception (IOException(..),catch) 18import Control.Exception as Exception (IOException(..),catch)
19 19
20import Data.OpenPGP.Util.Ed25519
20import Data.OpenPGP.Util.Fingerprint (fingerprint) 21import Data.OpenPGP.Util.Fingerprint (fingerprint)
21import Data.OpenPGP.Util.Gen 22import 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")