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

View as plain text