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