github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/crypto/ecdh/nist.go (about) 1 // Copyright 2022 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package ecdh 6 7 import ( 8 "crypto/internal/boring" 9 "crypto/internal/nistec" 10 "crypto/internal/randutil" 11 "encoding/binary" 12 "errors" 13 "io" 14 "math/bits" 15 ) 16 17 type nistCurve[Point nistPoint[Point]] struct { 18 name string 19 newPoint func() Point 20 scalarOrder []byte 21 } 22 23 // nistPoint is a generic constraint for the nistec Point types. 24 type nistPoint[T any] interface { 25 Bytes() []byte 26 BytesX() ([]byte, error) 27 SetBytes([]byte) (T, error) 28 ScalarMult(T, []byte) (T, error) 29 ScalarBaseMult([]byte) (T, error) 30 } 31 32 func (c *nistCurve[Point]) String() string { 33 return c.name 34 } 35 36 var errInvalidPrivateKey = errors.New("crypto/ecdh: invalid private key") 37 38 func (c *nistCurve[Point]) GenerateKey(rand io.Reader) (*PrivateKey, error) { 39 if boring.Enabled && rand == boring.RandReader { 40 key, bytes, err := boring.GenerateKeyECDH(c.name) 41 if err != nil { 42 return nil, err 43 } 44 return newBoringPrivateKey(c, key, bytes) 45 } 46 47 key := make([]byte, len(c.scalarOrder)) 48 randutil.MaybeReadByte(rand) 49 for { 50 if _, err := io.ReadFull(rand, key); err != nil { 51 return nil, err 52 } 53 54 // Mask off any excess bits if the size of the underlying field is not a 55 // whole number of bytes, which is only the case for P-521. We use a 56 // pointer to the scalarOrder field because comparing generic and 57 // instantiated types is not supported. 58 if &c.scalarOrder[0] == &p521Order[0] { 59 key[0] &= 0b0000_0001 60 } 61 62 // In tests, rand will return all zeros and NewPrivateKey will reject 63 // the zero key as it generates the identity as a public key. This also 64 // makes this function consistent with crypto/elliptic.GenerateKey. 65 key[1] ^= 0x42 66 67 k, err := c.NewPrivateKey(key) 68 if err == errInvalidPrivateKey { 69 continue 70 } 71 return k, err 72 } 73 } 74 75 func (c *nistCurve[Point]) NewPrivateKey(key []byte) (*PrivateKey, error) { 76 if len(key) != len(c.scalarOrder) { 77 return nil, errors.New("crypto/ecdh: invalid private key size") 78 } 79 if isZero(key) || !isLess(key, c.scalarOrder) { 80 return nil, errInvalidPrivateKey 81 } 82 if boring.Enabled { 83 bk, err := boring.NewPrivateKeyECDH(c.name, key) 84 if err != nil { 85 return nil, err 86 } 87 return newBoringPrivateKey(c, bk, key) 88 } 89 k := &PrivateKey{ 90 curve: c, 91 privateKey: append([]byte{}, key...), 92 } 93 return k, nil 94 } 95 96 func newBoringPrivateKey(c Curve, bk *boring.PrivateKeyECDH, privateKey []byte) (*PrivateKey, error) { 97 k := &PrivateKey{ 98 curve: c, 99 boring: bk, 100 privateKey: append([]byte(nil), privateKey...), 101 } 102 return k, nil 103 } 104 105 func (c *nistCurve[Point]) privateKeyToPublicKey(key *PrivateKey) *PublicKey { 106 boring.Unreachable() 107 if key.curve != c { 108 panic("crypto/ecdh: internal error: converting the wrong key type") 109 } 110 p, err := c.newPoint().ScalarBaseMult(key.privateKey) 111 if err != nil { 112 // This is unreachable because the only error condition of 113 // ScalarBaseMult is if the input is not the right size. 114 panic("crypto/ecdh: internal error: nistec ScalarBaseMult failed for a fixed-size input") 115 } 116 publicKey := p.Bytes() 117 if len(publicKey) == 1 { 118 // The encoding of the identity is a single 0x00 byte. This is 119 // unreachable because the only scalar that generates the identity is 120 // zero, which is rejected by NewPrivateKey. 121 panic("crypto/ecdh: internal error: nistec ScalarBaseMult returned the identity") 122 } 123 return &PublicKey{ 124 curve: key.curve, 125 publicKey: publicKey, 126 } 127 } 128 129 // isZero returns whether a is all zeroes in constant time. 130 func isZero(a []byte) bool { 131 var acc byte 132 for _, b := range a { 133 acc |= b 134 } 135 return acc == 0 136 } 137 138 // isLess returns whether a < b, where a and b are big-endian buffers of the 139 // same length and shorter than 72 bytes. 140 func isLess(a, b []byte) bool { 141 if len(a) != len(b) { 142 panic("crypto/ecdh: internal error: mismatched isLess inputs") 143 } 144 145 // Copy the values into a fixed-size preallocated little-endian buffer. 146 // 72 bytes is enough for every scalar in this package, and having a fixed 147 // size lets us avoid heap allocations. 148 if len(a) > 72 { 149 panic("crypto/ecdh: internal error: isLess input too large") 150 } 151 bufA, bufB := make([]byte, 72), make([]byte, 72) 152 for i := range a { 153 bufA[i], bufB[i] = a[len(a)-i-1], b[len(b)-i-1] 154 } 155 156 // Perform a subtraction with borrow. 157 var borrow uint64 158 for i := 0; i < len(bufA); i += 8 { 159 limbA, limbB := binary.LittleEndian.Uint64(bufA[i:]), binary.LittleEndian.Uint64(bufB[i:]) 160 _, borrow = bits.Sub64(limbA, limbB, borrow) 161 } 162 163 // If there is a borrow at the end of the operation, then a < b. 164 return borrow == 1 165 } 166 167 func (c *nistCurve[Point]) NewPublicKey(key []byte) (*PublicKey, error) { 168 // Reject the point at infinity and compressed encodings. 169 if len(key) == 0 || key[0] != 4 { 170 return nil, errors.New("crypto/ecdh: invalid public key") 171 } 172 k := &PublicKey{ 173 curve: c, 174 publicKey: append([]byte{}, key...), 175 } 176 if boring.Enabled { 177 bk, err := boring.NewPublicKeyECDH(c.name, k.publicKey) 178 if err != nil { 179 return nil, err 180 } 181 k.boring = bk 182 } else { 183 // SetBytes also checks that the point is on the curve. 184 if _, err := c.newPoint().SetBytes(key); err != nil { 185 return nil, err 186 } 187 } 188 return k, nil 189 } 190 191 func (c *nistCurve[Point]) ecdh(local *PrivateKey, remote *PublicKey) ([]byte, error) { 192 // Note that this function can't return an error, as NewPublicKey rejects 193 // invalid points and the point at infinity, and NewPrivateKey rejects 194 // invalid scalars and the zero value. BytesX returns an error for the point 195 // at infinity, but in a prime order group such as the NIST curves that can 196 // only be the result of a scalar multiplication if one of the inputs is the 197 // zero scalar or the point at infinity. 198 199 if boring.Enabled { 200 return boring.ECDH(local.boring, remote.boring) 201 } 202 203 boring.Unreachable() 204 p, err := c.newPoint().SetBytes(remote.publicKey) 205 if err != nil { 206 return nil, err 207 } 208 if _, err := p.ScalarMult(p, local.privateKey); err != nil { 209 return nil, err 210 } 211 return p.BytesX() 212 } 213 214 // P256 returns a Curve which implements NIST P-256 (FIPS 186-3, section D.2.3), 215 // also known as secp256r1 or prime256v1. 216 // 217 // Multiple invocations of this function will return the same value, which can 218 // be used for equality checks and switch statements. 219 func P256() Curve { return p256 } 220 221 var p256 = &nistCurve[*nistec.P256Point]{ 222 name: "P-256", 223 newPoint: nistec.NewP256Point, 224 scalarOrder: p256Order, 225 } 226 227 var p256Order = []byte{ 228 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 229 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 230 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17, 0x9e, 0x84, 231 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51} 232 233 // P384 returns a Curve which implements NIST P-384 (FIPS 186-3, section D.2.4), 234 // also known as secp384r1. 235 // 236 // Multiple invocations of this function will return the same value, which can 237 // be used for equality checks and switch statements. 238 func P384() Curve { return p384 } 239 240 var p384 = &nistCurve[*nistec.P384Point]{ 241 name: "P-384", 242 newPoint: nistec.NewP384Point, 243 scalarOrder: p384Order, 244 } 245 246 var p384Order = []byte{ 247 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 248 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 249 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 250 0xc7, 0x63, 0x4d, 0x81, 0xf4, 0x37, 0x2d, 0xdf, 251 0x58, 0x1a, 0x0d, 0xb2, 0x48, 0xb0, 0xa7, 0x7a, 252 0xec, 0xec, 0x19, 0x6a, 0xcc, 0xc5, 0x29, 0x73} 253 254 // P521 returns a Curve which implements NIST P-521 (FIPS 186-3, section D.2.5), 255 // also known as secp521r1. 256 // 257 // Multiple invocations of this function will return the same value, which can 258 // be used for equality checks and switch statements. 259 func P521() Curve { return p521 } 260 261 var p521 = &nistCurve[*nistec.P521Point]{ 262 name: "P-521", 263 newPoint: nistec.NewP521Point, 264 scalarOrder: p521Order, 265 } 266 267 var p521Order = []byte{0x01, 0xff, 268 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 269 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 270 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 271 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfa, 272 0x51, 0x86, 0x87, 0x83, 0xbf, 0x2f, 0x96, 0x6b, 273 0x7f, 0xcc, 0x01, 0x48, 0xf7, 0x09, 0xa5, 0xd0, 274 0x3b, 0xb5, 0xc9, 0xb8, 0x89, 0x9c, 0x47, 0xae, 275 0xbb, 0x6f, 0xb7, 0x1e, 0x91, 0x38, 0x64, 0x09}