...
1
2 package ecc
3
4 import (
5 "crypto/subtle"
6 "io"
7
8 "github.com/ProtonMail/go-crypto/openpgp/errors"
9 x25519lib "github.com/cloudflare/circl/dh/x25519"
10 )
11
12 type curve25519 struct{}
13
14 func NewCurve25519() *curve25519 {
15 return &curve25519{}
16 }
17
18 func (c *curve25519) GetCurveName() string {
19 return "curve25519"
20 }
21
22
23
24 func (c *curve25519) MarshalBytePoint(point []byte) []byte {
25 return append([]byte{0x40}, point...)
26 }
27
28
29
30 func (c *curve25519) UnmarshalBytePoint(point []byte) []byte {
31 if len(point) != x25519lib.Size+1 {
32 return nil
33 }
34
35
36 return point[1:]
37 }
38
39
40
41
42
43
44
45
46 func (c *curve25519) MarshalByteSecret(secret []byte) []byte {
47 d := make([]byte, x25519lib.Size)
48 copyReversed(d, secret)
49
50
51
52
53
54
55
56
57 d[0] &= 127
58 d[0] |= 64
59 d[31] &= 248
60
61 return d
62 }
63
64
65
66
67
68
69
70 func (c *curve25519) UnmarshalByteSecret(d []byte) []byte {
71 if len(d) > x25519lib.Size {
72 return nil
73 }
74
75
76 secret := make([]byte, x25519lib.Size)
77 copyReversed(secret, d)
78
79 return secret
80 }
81
82
83
84
85
86
87 func (c *curve25519) generateKeyPairBytes(rand io.Reader) (priv, pub x25519lib.Key, err error) {
88 _, err = io.ReadFull(rand, priv[:])
89 if err != nil {
90 return
91 }
92
93 x25519lib.KeyGen(&pub, &priv)
94 return
95 }
96
97 func (c *curve25519) GenerateECDH(rand io.Reader) (point []byte, secret []byte, err error) {
98 priv, pub, err := c.generateKeyPairBytes(rand)
99 if err != nil {
100 return
101 }
102
103 return pub[:], priv[:], nil
104 }
105
106 func (c *genericCurve) MaskSecret(secret []byte) []byte {
107 return secret
108 }
109
110 func (c *curve25519) Encaps(rand io.Reader, point []byte) (ephemeral, sharedSecret []byte, err error) {
111
112
113
114 ephemeralPrivate, ephemeralPublic, err := c.generateKeyPairBytes(rand)
115 if err != nil {
116 return nil, nil, err
117 }
118
119
120
121 var pubKey x25519lib.Key
122 copy(pubKey[:], point)
123
124
125
126
127 var sharedPoint x25519lib.Key
128 x25519lib.Shared(&sharedPoint, &ephemeralPrivate, &pubKey)
129
130 return ephemeralPublic[:], sharedPoint[:], nil
131 }
132
133 func (c *curve25519) Decaps(vsG, secret []byte) (sharedSecret []byte, err error) {
134 var ephemeralPublic, decodedPrivate, sharedPoint x25519lib.Key
135
136
137
138
139
140
141 copy(ephemeralPublic[:], vsG)
142
143
144 copy(decodedPrivate[:], secret)
145
146
147
148
149 x25519lib.Shared(&sharedPoint, &decodedPrivate, &ephemeralPublic)
150
151 return sharedPoint[:], nil
152 }
153
154 func (c *curve25519) ValidateECDH(point []byte, secret []byte) (err error) {
155 var pk, sk x25519lib.Key
156 copy(sk[:], secret)
157 x25519lib.KeyGen(&pk, &sk)
158
159 if subtle.ConstantTimeCompare(point, pk[:]) == 0 {
160 return errors.KeyInvalidError("ecc: invalid curve25519 public point")
161 }
162
163 return nil
164 }
165
166 func copyReversed(out []byte, in []byte) {
167 l := len(in)
168 for i := 0; i < l; i++ {
169 out[i] = in[l-i-1]
170 }
171 }
172
View as plain text