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

View as plain text