diff options
Diffstat (limited to 'Data/OpenPGP/Util/Ed25519.hs')
-rw-r--r-- | Data/OpenPGP/Util/Ed25519.hs | 116 |
1 files changed, 84 insertions, 32 deletions
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 | ||