Source file src/crypto/ecdh/nist.go

     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  	"bytes"
     9  	"crypto/internal/boring"
    10  	"crypto/internal/fips140/ecdh"
    11  	"crypto/internal/fips140only"
    12  	"errors"
    13  	"io"
    14  )
    15  
    16  type nistCurve struct {
    17  	name          string
    18  	generate      func(io.Reader) (*ecdh.PrivateKey, error)
    19  	newPrivateKey func([]byte) (*ecdh.PrivateKey, error)
    20  	newPublicKey  func(publicKey []byte) (*ecdh.PublicKey, error)
    21  	sharedSecret  func(*ecdh.PrivateKey, *ecdh.PublicKey) (sharedSecret []byte, err error)
    22  }
    23  
    24  func (c *nistCurve) String() string {
    25  	return c.name
    26  }
    27  
    28  func (c *nistCurve) GenerateKey(rand io.Reader) (*PrivateKey, error) {
    29  	if boring.Enabled && rand == boring.RandReader {
    30  		key, bytes, err := boring.GenerateKeyECDH(c.name)
    31  		if err != nil {
    32  			return nil, err
    33  		}
    34  		pub, err := key.PublicKey()
    35  		if err != nil {
    36  			return nil, err
    37  		}
    38  		k := &PrivateKey{
    39  			curve:      c,
    40  			privateKey: bytes,
    41  			publicKey:  &PublicKey{curve: c, publicKey: pub.Bytes(), boring: pub},
    42  			boring:     key,
    43  		}
    44  		return k, nil
    45  	}
    46  
    47  	if fips140only.Enabled && !fips140only.ApprovedRandomReader(rand) {
    48  		return nil, errors.New("crypto/ecdh: only crypto/rand.Reader is allowed in FIPS 140-only mode")
    49  	}
    50  
    51  	privateKey, err := c.generate(rand)
    52  	if err != nil {
    53  		return nil, err
    54  	}
    55  
    56  	k := &PrivateKey{
    57  		curve:      c,
    58  		privateKey: privateKey.Bytes(),
    59  		fips:       privateKey,
    60  		publicKey: &PublicKey{
    61  			curve:     c,
    62  			publicKey: privateKey.PublicKey().Bytes(),
    63  			fips:      privateKey.PublicKey(),
    64  		},
    65  	}
    66  	if boring.Enabled {
    67  		bk, err := boring.NewPrivateKeyECDH(c.name, k.privateKey)
    68  		if err != nil {
    69  			return nil, err
    70  		}
    71  		pub, err := bk.PublicKey()
    72  		if err != nil {
    73  			return nil, err
    74  		}
    75  		k.boring = bk
    76  		k.publicKey.boring = pub
    77  	}
    78  	return k, nil
    79  }
    80  
    81  func (c *nistCurve) NewPrivateKey(key []byte) (*PrivateKey, error) {
    82  	if boring.Enabled {
    83  		bk, err := boring.NewPrivateKeyECDH(c.name, key)
    84  		if err != nil {
    85  			return nil, errors.New("crypto/ecdh: invalid private key")
    86  		}
    87  		pub, err := bk.PublicKey()
    88  		if err != nil {
    89  			return nil, errors.New("crypto/ecdh: invalid private key")
    90  		}
    91  		k := &PrivateKey{
    92  			curve:      c,
    93  			privateKey: bytes.Clone(key),
    94  			publicKey:  &PublicKey{curve: c, publicKey: pub.Bytes(), boring: pub},
    95  			boring:     bk,
    96  		}
    97  		return k, nil
    98  	}
    99  
   100  	fk, err := c.newPrivateKey(key)
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  	k := &PrivateKey{
   105  		curve:      c,
   106  		privateKey: bytes.Clone(key),
   107  		fips:       fk,
   108  		publicKey: &PublicKey{
   109  			curve:     c,
   110  			publicKey: fk.PublicKey().Bytes(),
   111  			fips:      fk.PublicKey(),
   112  		},
   113  	}
   114  	return k, nil
   115  }
   116  
   117  func (c *nistCurve) NewPublicKey(key []byte) (*PublicKey, error) {
   118  	// Reject the point at infinity and compressed encodings.
   119  	// Note that boring.NewPublicKeyECDH would accept them.
   120  	if len(key) == 0 || key[0] != 4 {
   121  		return nil, errors.New("crypto/ecdh: invalid public key")
   122  	}
   123  	k := &PublicKey{
   124  		curve:     c,
   125  		publicKey: bytes.Clone(key),
   126  	}
   127  	if boring.Enabled {
   128  		bk, err := boring.NewPublicKeyECDH(c.name, k.publicKey)
   129  		if err != nil {
   130  			return nil, errors.New("crypto/ecdh: invalid public key")
   131  		}
   132  		k.boring = bk
   133  	} else {
   134  		fk, err := c.newPublicKey(key)
   135  		if err != nil {
   136  			return nil, err
   137  		}
   138  		k.fips = fk
   139  	}
   140  	return k, nil
   141  }
   142  
   143  func (c *nistCurve) ecdh(local *PrivateKey, remote *PublicKey) ([]byte, error) {
   144  	// Note that this function can't return an error, as NewPublicKey rejects
   145  	// invalid points and the point at infinity, and NewPrivateKey rejects
   146  	// invalid scalars and the zero value. BytesX returns an error for the point
   147  	// at infinity, but in a prime order group such as the NIST curves that can
   148  	// only be the result of a scalar multiplication if one of the inputs is the
   149  	// zero scalar or the point at infinity.
   150  
   151  	if boring.Enabled {
   152  		return boring.ECDH(local.boring, remote.boring)
   153  	}
   154  	return c.sharedSecret(local.fips, remote.fips)
   155  }
   156  
   157  // P256 returns a [Curve] which implements NIST P-256 (FIPS 186-3, section D.2.3),
   158  // also known as secp256r1 or prime256v1.
   159  //
   160  // Multiple invocations of this function will return the same value, which can
   161  // be used for equality checks and switch statements.
   162  func P256() Curve { return p256 }
   163  
   164  var p256 = &nistCurve{
   165  	name: "P-256",
   166  	generate: func(r io.Reader) (*ecdh.PrivateKey, error) {
   167  		return ecdh.GenerateKey(ecdh.P256(), r)
   168  	},
   169  	newPrivateKey: func(b []byte) (*ecdh.PrivateKey, error) {
   170  		return ecdh.NewPrivateKey(ecdh.P256(), b)
   171  	},
   172  	newPublicKey: func(publicKey []byte) (*ecdh.PublicKey, error) {
   173  		return ecdh.NewPublicKey(ecdh.P256(), publicKey)
   174  	},
   175  	sharedSecret: func(priv *ecdh.PrivateKey, pub *ecdh.PublicKey) (sharedSecret []byte, err error) {
   176  		return ecdh.ECDH(ecdh.P256(), priv, pub)
   177  	},
   178  }
   179  
   180  // P384 returns a [Curve] which implements NIST P-384 (FIPS 186-3, section D.2.4),
   181  // also known as secp384r1.
   182  //
   183  // Multiple invocations of this function will return the same value, which can
   184  // be used for equality checks and switch statements.
   185  func P384() Curve { return p384 }
   186  
   187  var p384 = &nistCurve{
   188  	name: "P-384",
   189  	generate: func(r io.Reader) (*ecdh.PrivateKey, error) {
   190  		return ecdh.GenerateKey(ecdh.P384(), r)
   191  	},
   192  	newPrivateKey: func(b []byte) (*ecdh.PrivateKey, error) {
   193  		return ecdh.NewPrivateKey(ecdh.P384(), b)
   194  	},
   195  	newPublicKey: func(publicKey []byte) (*ecdh.PublicKey, error) {
   196  		return ecdh.NewPublicKey(ecdh.P384(), publicKey)
   197  	},
   198  	sharedSecret: func(priv *ecdh.PrivateKey, pub *ecdh.PublicKey) (sharedSecret []byte, err error) {
   199  		return ecdh.ECDH(ecdh.P384(), priv, pub)
   200  	},
   201  }
   202  
   203  // P521 returns a [Curve] which implements NIST P-521 (FIPS 186-3, section D.2.5),
   204  // also known as secp521r1.
   205  //
   206  // Multiple invocations of this function will return the same value, which can
   207  // be used for equality checks and switch statements.
   208  func P521() Curve { return p521 }
   209  
   210  var p521 = &nistCurve{
   211  	name: "P-521",
   212  	generate: func(r io.Reader) (*ecdh.PrivateKey, error) {
   213  		return ecdh.GenerateKey(ecdh.P521(), r)
   214  	},
   215  	newPrivateKey: func(b []byte) (*ecdh.PrivateKey, error) {
   216  		return ecdh.NewPrivateKey(ecdh.P521(), b)
   217  	},
   218  	newPublicKey: func(publicKey []byte) (*ecdh.PublicKey, error) {
   219  		return ecdh.NewPublicKey(ecdh.P521(), publicKey)
   220  	},
   221  	sharedSecret: func(priv *ecdh.PrivateKey, pub *ecdh.PublicKey) (sharedSecret []byte, err error) {
   222  		return ecdh.ECDH(ecdh.P521(), priv, pub)
   223  	},
   224  }
   225  

View as plain text