...

Source file src/crypto/ed25519/ed25519.go

Documentation: crypto/ed25519

     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  	if fips140only.Enforced() && !fips140only.ApprovedRandomReader(random) {
   164  		return nil, nil, errors.New("crypto/ed25519: only crypto/rand.Reader is allowed in FIPS 140-only mode")
   165  	}
   166  
   167  	if rand.IsDefaultReader(random) {
   168  		privateKey, err := ed25519.GenerateKey()
   169  		if err != nil {
   170  			return nil, nil, err
   171  		}
   172  		publicKey := PublicKey(privateKey.PublicKey())
   173  		return publicKey, PrivateKey(privateKey.Bytes()), nil
   174  	}
   175  
   176  	seed := make([]byte, SeedSize)
   177  	if _, err := io.ReadFull(random, seed); err != nil {
   178  		return nil, nil, err
   179  	}
   180  
   181  	privateKey := NewKeyFromSeed(seed)
   182  	publicKey := privateKey.Public().(PublicKey)
   183  	return publicKey, privateKey, nil
   184  }
   185  
   186  // NewKeyFromSeed calculates a private key from a seed. It will panic if
   187  // len(seed) is not [SeedSize]. This function is provided for interoperability
   188  // with RFC 8032. RFC 8032's private keys correspond to seeds in this
   189  // package.
   190  func NewKeyFromSeed(seed []byte) PrivateKey {
   191  	// Outline the function body so that the returned key can be stack-allocated.
   192  	privateKey := make([]byte, PrivateKeySize)
   193  	newKeyFromSeed(privateKey, seed)
   194  	return privateKey
   195  }
   196  
   197  func newKeyFromSeed(privateKey, seed []byte) {
   198  	k, err := ed25519.NewPrivateKeyFromSeed(seed)
   199  	if err != nil {
   200  		// NewPrivateKeyFromSeed only returns an error if the seed length is incorrect.
   201  		panic("ed25519: bad seed length: " + strconv.Itoa(len(seed)))
   202  	}
   203  	copy(privateKey, k.Bytes())
   204  }
   205  
   206  // Sign signs the message with privateKey and returns a signature. It will
   207  // panic if len(privateKey) is not [PrivateKeySize].
   208  func Sign(privateKey PrivateKey, message []byte) []byte {
   209  	// Outline the function body so that the returned signature can be
   210  	// stack-allocated.
   211  	signature := make([]byte, SignatureSize)
   212  	sign(signature, privateKey, message)
   213  	return signature
   214  }
   215  
   216  func sign(signature []byte, privateKey PrivateKey, message []byte) {
   217  	k, err := privateKeyCache.Get(&privateKey[0], func() (*ed25519.PrivateKey, error) {
   218  		return ed25519.NewPrivateKey(privateKey)
   219  	}, func(k *ed25519.PrivateKey) bool {
   220  		return subtle.ConstantTimeCompare(privateKey, k.Bytes()) == 1
   221  	})
   222  	if err != nil {
   223  		panic("ed25519: bad private key: " + err.Error())
   224  	}
   225  	sig := ed25519.Sign(k, message)
   226  	copy(signature, sig)
   227  }
   228  
   229  // Verify reports whether sig is a valid signature of message by publicKey. It
   230  // will panic if len(publicKey) is not [PublicKeySize].
   231  //
   232  // The inputs are not considered confidential, and may leak through timing side
   233  // channels, or if an attacker has control of part of the inputs.
   234  func Verify(publicKey PublicKey, message, sig []byte) bool {
   235  	return VerifyWithOptions(publicKey, message, sig, &Options{Hash: crypto.Hash(0)}) == nil
   236  }
   237  
   238  // VerifyWithOptions reports whether sig is a valid signature of message by
   239  // publicKey. A valid signature is indicated by returning a nil error. It will
   240  // panic if len(publicKey) is not [PublicKeySize].
   241  //
   242  // If opts.Hash is [crypto.SHA512], the pre-hashed variant Ed25519ph is used and
   243  // message is expected to be a SHA-512 hash, otherwise opts.Hash must be
   244  // [crypto.Hash](0) and the message must not be hashed, as Ed25519 performs two
   245  // passes over messages to be signed.
   246  //
   247  // The inputs are not considered confidential, and may leak through timing side
   248  // channels, or if an attacker has control of part of the inputs.
   249  func VerifyWithOptions(publicKey PublicKey, message, sig []byte, opts *Options) error {
   250  	if l := len(publicKey); l != PublicKeySize {
   251  		panic("ed25519: bad public key length: " + strconv.Itoa(l))
   252  	}
   253  	k, err := ed25519.NewPublicKey(publicKey)
   254  	if err != nil {
   255  		return err
   256  	}
   257  	switch {
   258  	case opts.Hash == crypto.SHA512: // Ed25519ph
   259  		return ed25519.VerifyPH(k, message, sig, opts.Context)
   260  	case opts.Hash == crypto.Hash(0) && opts.Context != "": // Ed25519ctx
   261  		if fips140only.Enforced() {
   262  			return errors.New("crypto/ed25519: use of Ed25519ctx is not allowed in FIPS 140-only mode")
   263  		}
   264  		return ed25519.VerifyCtx(k, message, sig, opts.Context)
   265  	case opts.Hash == crypto.Hash(0): // Ed25519
   266  		return ed25519.Verify(k, message, sig)
   267  	default:
   268  		return errors.New("ed25519: expected opts.Hash zero (unhashed message, for standard Ed25519) or SHA-512 (for Ed25519ph)")
   269  	}
   270  }
   271  

View as plain text