Source file src/crypto/ed25519/ed25519.go

     1  // Copyright 2016 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 ed25519 implements the Ed25519 signature algorithm. See
     6  // https://ed25519.cr.yp.to/.
     7  //
     8  // These functions are also compatible with the “Ed25519” function defined in
     9  // RFC 8032. However, unlike RFC 8032's formulation, this package's private key
    10  // representation includes a public key suffix to make multiple signing
    11  // operations with the same key more efficient. This package refers to the RFC
    12  // 8032 private key as the “seed”.
    13  //
    14  // Operations involving private keys are implemented using constant-time
    15  // algorithms.
    16  package ed25519
    17  
    18  import (
    19  	"crypto"
    20  	"crypto/internal/fips140/ed25519"
    21  	"crypto/internal/fips140cache"
    22  	"crypto/internal/fips140only"
    23  	"crypto/internal/rand"
    24  	cryptorand "crypto/rand"
    25  	"crypto/subtle"
    26  	"errors"
    27  	"internal/godebug"
    28  	"io"
    29  	"strconv"
    30  )
    31  
    32  const (
    33  	// PublicKeySize is the size, in bytes, of public keys as used in this package.
    34  	PublicKeySize = 32
    35  	// PrivateKeySize is the size, in bytes, of private keys as used in this package.
    36  	PrivateKeySize = 64
    37  	// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
    38  	SignatureSize = 64
    39  	// SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032.
    40  	SeedSize = 32
    41  )
    42  
    43  // PublicKey is the type of Ed25519 public keys.
    44  type PublicKey []byte
    45  
    46  // Any methods implemented on PublicKey might need to also be implemented on
    47  // PrivateKey, as the latter embeds the former and will expose its methods.
    48  
    49  // Equal reports whether pub and x have the same value.
    50  func (pub PublicKey) Equal(x crypto.PublicKey) bool {
    51  	xx, ok := x.(PublicKey)
    52  	if !ok {
    53  		return false
    54  	}
    55  	return subtle.ConstantTimeCompare(pub, xx) == 1
    56  }
    57  
    58  // PrivateKey is the type of Ed25519 private keys. It implements [crypto.Signer].
    59  type PrivateKey []byte
    60  
    61  // Public returns the [PublicKey] corresponding to priv.
    62  func (priv PrivateKey) Public() crypto.PublicKey {
    63  	publicKey := make([]byte, PublicKeySize)
    64  	copy(publicKey, priv[32:])
    65  	return PublicKey(publicKey)
    66  }
    67  
    68  // Equal reports whether priv and x have the same value.
    69  func (priv PrivateKey) Equal(x crypto.PrivateKey) bool {
    70  	xx, ok := x.(PrivateKey)
    71  	if !ok {
    72  		return false
    73  	}
    74  	return subtle.ConstantTimeCompare(priv, xx) == 1
    75  }
    76  
    77  // Seed returns the private key seed corresponding to priv. It is provided for
    78  // interoperability with RFC 8032. RFC 8032's private keys correspond to seeds
    79  // in this package.
    80  func (priv PrivateKey) Seed() []byte {
    81  	return append(make([]byte, 0, SeedSize), priv[:SeedSize]...)
    82  }
    83  
    84  // privateKeyCache uses a pointer to the first byte of underlying storage as a
    85  // key, because [PrivateKey] is a slice header passed around by value.
    86  var privateKeyCache fips140cache.Cache[byte, ed25519.PrivateKey]
    87  
    88  // Sign signs the given message with priv. rand is ignored and can be nil.
    89  //
    90  // If opts.HashFunc() is [crypto.SHA512], the pre-hashed variant Ed25519ph is used
    91  // and message is expected to be a SHA-512 hash, otherwise opts.HashFunc() must
    92  // be [crypto.Hash](0) and the message must not be hashed, as Ed25519 performs two
    93  // passes over messages to be signed.
    94  //
    95  // A value of type [Options] can be used as opts, or crypto.Hash(0) or
    96  // crypto.SHA512 directly to select plain Ed25519 or Ed25519ph, respectively.
    97  func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) {
    98  	k, err := privateKeyCache.Get(&priv[0], func() (*ed25519.PrivateKey, error) {
    99  		return ed25519.NewPrivateKey(priv)
   100  	}, func(k *ed25519.PrivateKey) bool {
   101  		return subtle.ConstantTimeCompare(priv, k.Bytes()) == 1
   102  	})
   103  	if err != nil {
   104  		return nil, err
   105  	}
   106  	hash := opts.HashFunc()
   107  	context := ""
   108  	if opts, ok := opts.(*Options); ok {
   109  		context = opts.Context
   110  	}
   111  	switch {
   112  	case hash == crypto.SHA512: // Ed25519ph
   113  		return ed25519.SignPH(k, message, context)
   114  	case hash == crypto.Hash(0) && context != "": // Ed25519ctx
   115  		if fips140only.Enforced() {
   116  			return nil, errors.New("crypto/ed25519: use of Ed25519ctx is not allowed in FIPS 140-only mode")
   117  		}
   118  		return ed25519.SignCtx(k, message, context)
   119  	case hash == crypto.Hash(0): // Ed25519
   120  		return ed25519.Sign(k, message), nil
   121  	default:
   122  		return nil, errors.New("ed25519: expected opts.HashFunc() zero (unhashed message, for standard Ed25519) or SHA-512 (for Ed25519ph)")
   123  	}
   124  }
   125  
   126  // Options can be used with [PrivateKey.Sign] or [VerifyWithOptions]
   127  // to select Ed25519 variants.
   128  type Options struct {
   129  	// Hash can be zero for regular Ed25519, or crypto.SHA512 for Ed25519ph.
   130  	Hash crypto.Hash
   131  
   132  	// Context, if not empty, selects Ed25519ctx or provides the context string
   133  	// for Ed25519ph. It can be at most 255 bytes in length.
   134  	Context string
   135  }
   136  
   137  // HashFunc returns o.Hash.
   138  func (o *Options) HashFunc() crypto.Hash { return o.Hash }
   139  
   140  var cryptocustomrand = godebug.New("cryptocustomrand")
   141  
   142  // GenerateKey generates a public/private key pair using entropy from random.
   143  //
   144  // If random is nil, a secure random source is used. (Before Go 1.26, a custom
   145  // [crypto/rand.Reader] was used if set by the application. That behavior can be
   146  // restored with GODEBUG=cryptocustomrand=1. This setting will be removed in a
   147  // future Go release. Instead, use [testing/cryptotest.SetGlobalRandom].)
   148  //
   149  // The output of this function is deterministic, and equivalent to reading
   150  // [SeedSize] bytes from random, and passing them to [NewKeyFromSeed].
   151  func GenerateKey(random io.Reader) (PublicKey, PrivateKey, error) {
   152  	if random == nil {
   153  		if cryptocustomrand.Value() == "1" {
   154  			random = cryptorand.Reader
   155  			if !rand.IsDefaultReader(random) {
   156  				cryptocustomrand.IncNonDefault()
   157  			}
   158  		} else {
   159  			random = rand.Reader
   160  		}
   161  	}
   162  
   163  	seed := make([]byte, SeedSize)
   164  	if _, err := io.ReadFull(random, seed); err != nil {
   165  		return nil, nil, err
   166  	}
   167  
   168  	privateKey := NewKeyFromSeed(seed)
   169  	publicKey := privateKey.Public().(PublicKey)
   170  	return publicKey, privateKey, nil
   171  }
   172  
   173  // NewKeyFromSeed calculates a private key from a seed. It will panic if
   174  // len(seed) is not [SeedSize]. This function is provided for interoperability
   175  // with RFC 8032. RFC 8032's private keys correspond to seeds in this
   176  // package.
   177  func NewKeyFromSeed(seed []byte) PrivateKey {
   178  	// Outline the function body so that the returned key can be stack-allocated.
   179  	privateKey := make([]byte, PrivateKeySize)
   180  	newKeyFromSeed(privateKey, seed)
   181  	return privateKey
   182  }
   183  
   184  func newKeyFromSeed(privateKey, seed []byte) {
   185  	k, err := ed25519.NewPrivateKeyFromSeed(seed)
   186  	if err != nil {
   187  		// NewPrivateKeyFromSeed only returns an error if the seed length is incorrect.
   188  		panic("ed25519: bad seed length: " + strconv.Itoa(len(seed)))
   189  	}
   190  	copy(privateKey, k.Bytes())
   191  }
   192  
   193  // Sign signs the message with privateKey and returns a signature. It will
   194  // panic if len(privateKey) is not [PrivateKeySize].
   195  func Sign(privateKey PrivateKey, message []byte) []byte {
   196  	// Outline the function body so that the returned signature can be
   197  	// stack-allocated.
   198  	signature := make([]byte, SignatureSize)
   199  	sign(signature, privateKey, message)
   200  	return signature
   201  }
   202  
   203  func sign(signature []byte, privateKey PrivateKey, message []byte) {
   204  	k, err := privateKeyCache.Get(&privateKey[0], func() (*ed25519.PrivateKey, error) {
   205  		return ed25519.NewPrivateKey(privateKey)
   206  	}, func(k *ed25519.PrivateKey) bool {
   207  		return subtle.ConstantTimeCompare(privateKey, k.Bytes()) == 1
   208  	})
   209  	if err != nil {
   210  		panic("ed25519: bad private key: " + err.Error())
   211  	}
   212  	sig := ed25519.Sign(k, message)
   213  	copy(signature, sig)
   214  }
   215  
   216  // Verify reports whether sig is a valid signature of message by publicKey. It
   217  // will panic if len(publicKey) is not [PublicKeySize].
   218  //
   219  // The inputs are not considered confidential, and may leak through timing side
   220  // channels, or if an attacker has control of part of the inputs.
   221  func Verify(publicKey PublicKey, message, sig []byte) bool {
   222  	return VerifyWithOptions(publicKey, message, sig, &Options{Hash: crypto.Hash(0)}) == nil
   223  }
   224  
   225  // VerifyWithOptions reports whether sig is a valid signature of message by
   226  // publicKey. A valid signature is indicated by returning a nil error. It will
   227  // panic if len(publicKey) is not [PublicKeySize].
   228  //
   229  // If opts.Hash is [crypto.SHA512], the pre-hashed variant Ed25519ph is used and
   230  // message is expected to be a SHA-512 hash, otherwise opts.Hash must be
   231  // [crypto.Hash](0) and the message must not be hashed, as Ed25519 performs two
   232  // passes over messages to be signed.
   233  //
   234  // The inputs are not considered confidential, and may leak through timing side
   235  // channels, or if an attacker has control of part of the inputs.
   236  func VerifyWithOptions(publicKey PublicKey, message, sig []byte, opts *Options) error {
   237  	if l := len(publicKey); l != PublicKeySize {
   238  		panic("ed25519: bad public key length: " + strconv.Itoa(l))
   239  	}
   240  	k, err := ed25519.NewPublicKey(publicKey)
   241  	if err != nil {
   242  		return err
   243  	}
   244  	switch {
   245  	case opts.Hash == crypto.SHA512: // Ed25519ph
   246  		return ed25519.VerifyPH(k, message, sig, opts.Context)
   247  	case opts.Hash == crypto.Hash(0) && opts.Context != "": // Ed25519ctx
   248  		if fips140only.Enforced() {
   249  			return errors.New("crypto/ed25519: use of Ed25519ctx is not allowed in FIPS 140-only mode")
   250  		}
   251  		return ed25519.VerifyCtx(k, message, sig, opts.Context)
   252  	case opts.Hash == crypto.Hash(0): // Ed25519
   253  		return ed25519.Verify(k, message, sig)
   254  	default:
   255  		return errors.New("ed25519: expected opts.Hash zero (unhashed message, for standard Ed25519) or SHA-512 (for Ed25519ph)")
   256  	}
   257  }
   258  

View as plain text