1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
module Data.OpenPGP.Util.Ed25519 where
import Control.Monad
import Crypto.Error
import qualified Crypto.PubKey.Ed25519 as Ed25519
import Data.Bits
import qualified Data.ByteArray as BA
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BL
import qualified Data.OpenPGP as OpenPGP
import Data.OpenPGP (MPI(..))
import Data.OpenPGP.Internal
import Data.OpenPGP.Util.Base
-- import Crypto.ECC.Edwards25519
oid_ed25516 = 0x2B06010401DA470F01
zeroExtend :: Int -> BS.ByteString -> BS.ByteString
zeroExtend n bs = case compare (BS.length bs) n of
GT -> BS.take n bs
EQ -> bs
LT -> bs <> BS.replicate (n - BS.length bs) 0
zeroPad :: Int -> BS.ByteString -> BS.ByteString
zeroPad n bs = case compare (BS.length bs) n of
GT -> BS.take n bs
EQ -> bs
LT -> BS.replicate (n - BS.length bs) 0 <> bs
ed25519Key :: OpenPGP.Packet -> Maybe Ed25519.PublicKey
ed25519Key k =
let n = case keyParam 'f' k of
0x40 -> zeroPad 32 $ integerToBS $ keyParam 'n' k
_ ->
-- From Bernstein's "High-speed high-security signatures"
--
-- An element (x, y) ∈ E is encoded as a b-bit string (x, y), namely the (b −
-- 1)- bit encoding of y followed by a sign bit; the sign bit is 1 iff x is
-- negative. This encoding immediately determines y, and it determines x via
-- the equation x = ± √(y² − 1)/(dy² + 1).
let y = keyParam 'y' k
x = keyParam 'x' k
ybs = zeroExtend 32 $ integerToLE y
lb = BS.last ybs
in if x < 0 then BS.take 31 ybs `BS.snoc` (lb .|. 0x80)
else BS.take 31 ybs `BS.snoc` (lb .&. 0x7F)
in case Ed25519.publicKey n of
CryptoPassed ed25519 -> Just ed25519
CryptoFailed _ -> Nothing
ed25519sig :: OpenPGP.Packet -> Maybe Ed25519.Signature
ed25519sig sig =
let [MPI r,MPI s] = OpenPGP.signature sig
rbs = zeroPad 32 $ integerToBS r
sbs = zeroPad 32 $ integerToBS s
in case Ed25519.signature (rbs <> sbs) of
CryptoPassed sig25519 -> Just sig25519
CryptoFailed _ -> Nothing
privateEd25519Key :: OpenPGP.Packet -> Ed25519.SecretKey
privateEd25519Key k = case Ed25519.secretKey $ zeroExtend 32 $ integerToLE (keyParam 'd' k) of
CryptoPassed ed25519sec -> ed25519sec
CryptoFailed err -> error $ "Ed25519.secretKey: " ++ show err
ed25519Verify :: OpenPGP.Packet -> BS.ByteString -> OpenPGP.Packet -> Maybe Bool
ed25519Verify sig over k = do
let hashbs = hashBySymbol (OpenPGP.hash_algorithm sig) $ BL.fromChunks [over]
guard $ oid_ed25516 == keyParam 'c' k -- Only Ed25519 curve.
ek <- ed25519Key k
esig <- ed25519sig sig
Just $ Ed25519.verify ek hashbs esig
ed25519Sign :: OpenPGP.Packet -> OpenPGP.HashAlgorithm -> BS.ByteString -> [Integer]
ed25519Sign k hsh dta = [ getBigNum rbs, getBigNum sbs ]
where
hashbs = hashBySymbol hsh $ BL.fromChunks [dta]
sec = privateEd25519Key k
Just pub = ed25519Key k
sig = Ed25519.sign sec pub hashbs
(rbs,sbs) = BS.splitAt 32 $ BA.convert sig
importSecretEd25519 :: Ed25519.SecretKey -> [(Char,MPI)]
importSecretEd25519 k =
[ ('c', MPI oid_ed25516)
, ('l', MPI 128)
, ('n', MPI pub)
, ('f', MPI 0x40)
, ('d', MPI sec)
]
where
pub = getBigNum $ BA.convert $ Ed25519.toPublic k
sec = getBigNumLE $ BA.convert k
importPublicEd25519 :: Ed25519.PublicKey -> [(Char,MPI)]
importPublicEd25519 k =
[ ('c', MPI oid_ed25516)
, ('l', MPI 128)
, ('n', MPI pub)
, ('f', MPI 0x40)
]
where
pub = getBigNum $ BA.convert k
|