1
2
3
4
5 package ecdh
6
7 import (
8 "bytes"
9 "crypto/internal/fips140/edwards25519/field"
10 "crypto/internal/fips140only"
11 "crypto/internal/randutil"
12 "errors"
13 "io"
14 )
15
16 var (
17 x25519PublicKeySize = 32
18 x25519PrivateKeySize = 32
19 x25519SharedSecretSize = 32
20 )
21
22
23
24
25
26
27 func X25519() Curve { return x25519 }
28
29 var x25519 = &x25519Curve{}
30
31 type x25519Curve struct{}
32
33 func (c *x25519Curve) String() string {
34 return "X25519"
35 }
36
37 func (c *x25519Curve) GenerateKey(rand io.Reader) (*PrivateKey, error) {
38 if fips140only.Enabled {
39 return nil, errors.New("crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode")
40 }
41 key := make([]byte, x25519PrivateKeySize)
42 randutil.MaybeReadByte(rand)
43 if _, err := io.ReadFull(rand, key); err != nil {
44 return nil, err
45 }
46 return c.NewPrivateKey(key)
47 }
48
49 func (c *x25519Curve) NewPrivateKey(key []byte) (*PrivateKey, error) {
50 if fips140only.Enabled {
51 return nil, errors.New("crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode")
52 }
53 if len(key) != x25519PrivateKeySize {
54 return nil, errors.New("crypto/ecdh: invalid private key size")
55 }
56 publicKey := make([]byte, x25519PublicKeySize)
57 x25519Basepoint := [32]byte{9}
58 x25519ScalarMult(publicKey, key, x25519Basepoint[:])
59
60
61
62 return &PrivateKey{
63 curve: c,
64 privateKey: bytes.Clone(key),
65 publicKey: &PublicKey{curve: c, publicKey: publicKey},
66 }, nil
67 }
68
69 func (c *x25519Curve) NewPublicKey(key []byte) (*PublicKey, error) {
70 if fips140only.Enabled {
71 return nil, errors.New("crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode")
72 }
73 if len(key) != x25519PublicKeySize {
74 return nil, errors.New("crypto/ecdh: invalid public key")
75 }
76 return &PublicKey{
77 curve: c,
78 publicKey: bytes.Clone(key),
79 }, nil
80 }
81
82 func (c *x25519Curve) ecdh(local *PrivateKey, remote *PublicKey) ([]byte, error) {
83 out := make([]byte, x25519SharedSecretSize)
84 x25519ScalarMult(out, local.privateKey, remote.publicKey)
85 if isZero(out) {
86 return nil, errors.New("crypto/ecdh: bad X25519 remote ECDH input: low order point")
87 }
88 return out, nil
89 }
90
91 func x25519ScalarMult(dst, scalar, point []byte) {
92 var e [32]byte
93
94 copy(e[:], scalar[:])
95 e[0] &= 248
96 e[31] &= 127
97 e[31] |= 64
98
99 var x1, x2, z2, x3, z3, tmp0, tmp1 field.Element
100 x1.SetBytes(point[:])
101 x2.One()
102 x3.Set(&x1)
103 z3.One()
104
105 swap := 0
106 for pos := 254; pos >= 0; pos-- {
107 b := e[pos/8] >> uint(pos&7)
108 b &= 1
109 swap ^= int(b)
110 x2.Swap(&x3, swap)
111 z2.Swap(&z3, swap)
112 swap = int(b)
113
114 tmp0.Subtract(&x3, &z3)
115 tmp1.Subtract(&x2, &z2)
116 x2.Add(&x2, &z2)
117 z2.Add(&x3, &z3)
118 z3.Multiply(&tmp0, &x2)
119 z2.Multiply(&z2, &tmp1)
120 tmp0.Square(&tmp1)
121 tmp1.Square(&x2)
122 x3.Add(&z3, &z2)
123 z2.Subtract(&z3, &z2)
124 x2.Multiply(&tmp1, &tmp0)
125 tmp1.Subtract(&tmp1, &tmp0)
126 z2.Square(&z2)
127
128 z3.Mult32(&tmp1, 121666)
129 x3.Square(&x3)
130 tmp0.Add(&tmp0, &z3)
131 z3.Multiply(&x1, &z2)
132 z2.Multiply(&tmp1, &tmp0)
133 }
134
135 x2.Swap(&x3, swap)
136 z2.Swap(&z3, swap)
137
138 z2.Invert(&z2)
139 x2.Multiply(&x2, &z2)
140 copy(dst[:], x2.Bytes())
141 }
142
143
144 func isZero(x []byte) bool {
145 var acc byte
146 for _, b := range x {
147 acc |= b
148 }
149 return acc == 0
150 }
151
View as plain text