summaryrefslogtreecommitdiff
path: root/Data/OpenPGP/Util/Ed25519.hs
diff options
context:
space:
mode:
Diffstat (limited to 'Data/OpenPGP/Util/Ed25519.hs')
-rw-r--r--Data/OpenPGP/Util/Ed25519.hs116
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 @@
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