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

View as plain text