...

Source file src/github.com/lestrrat-go/jwx/jwe/internal/keygen/keygen.go

Documentation: github.com/lestrrat-go/jwx/jwe/internal/keygen

     1  package keygen
     2  
     3  import (
     4  	"crypto"
     5  	"crypto/ecdsa"
     6  	"crypto/rand"
     7  	"encoding/binary"
     8  	"io"
     9  
    10  	"golang.org/x/crypto/curve25519"
    11  
    12  	"github.com/lestrrat-go/jwx/internal/ecutil"
    13  	"github.com/lestrrat-go/jwx/jwa"
    14  	"github.com/lestrrat-go/jwx/jwe/internal/concatkdf"
    15  	"github.com/lestrrat-go/jwx/jwk"
    16  	"github.com/lestrrat-go/jwx/x25519"
    17  	"github.com/pkg/errors"
    18  )
    19  
    20  // Bytes returns the byte from this ByteKey
    21  func (k ByteKey) Bytes() []byte {
    22  	return []byte(k)
    23  }
    24  
    25  // Size returns the size of the key
    26  func (g Static) Size() int {
    27  	return len(g)
    28  }
    29  
    30  // Generate returns the key
    31  func (g Static) Generate() (ByteSource, error) {
    32  	buf := make([]byte, g.Size())
    33  	copy(buf, g)
    34  	return ByteKey(buf), nil
    35  }
    36  
    37  // NewRandom creates a new Generator that returns
    38  // random bytes
    39  func NewRandom(n int) Random {
    40  	return Random{keysize: n}
    41  }
    42  
    43  // Size returns the key size
    44  func (g Random) Size() int {
    45  	return g.keysize
    46  }
    47  
    48  // Generate generates a random new key
    49  func (g Random) Generate() (ByteSource, error) {
    50  	buf := make([]byte, g.keysize)
    51  	if _, err := io.ReadFull(rand.Reader, buf); err != nil {
    52  		return nil, errors.Wrap(err, "failed to read from rand.Reader")
    53  	}
    54  	return ByteKey(buf), nil
    55  }
    56  
    57  // NewEcdhes creates a new key generator using ECDH-ES
    58  func NewEcdhes(alg jwa.KeyEncryptionAlgorithm, enc jwa.ContentEncryptionAlgorithm, keysize int, pubkey *ecdsa.PublicKey) (*Ecdhes, error) {
    59  	return &Ecdhes{
    60  		algorithm: alg,
    61  		enc:       enc,
    62  		keysize:   keysize,
    63  		pubkey:    pubkey,
    64  	}, nil
    65  }
    66  
    67  // Size returns the key size associated with this generator
    68  func (g Ecdhes) Size() int {
    69  	return g.keysize
    70  }
    71  
    72  // Generate generates new keys using ECDH-ES
    73  func (g Ecdhes) Generate() (ByteSource, error) {
    74  	priv, err := ecdsa.GenerateKey(g.pubkey.Curve, rand.Reader)
    75  	if err != nil {
    76  		return nil, errors.Wrap(err, "failed to generate key for ECDH-ES")
    77  	}
    78  
    79  	var algorithm string
    80  	if g.algorithm == jwa.ECDH_ES {
    81  		algorithm = g.enc.String()
    82  	} else {
    83  		algorithm = g.algorithm.String()
    84  	}
    85  
    86  	pubinfo := make([]byte, 4)
    87  	binary.BigEndian.PutUint32(pubinfo, uint32(g.keysize)*8)
    88  
    89  	z, _ := priv.PublicKey.Curve.ScalarMult(g.pubkey.X, g.pubkey.Y, priv.D.Bytes())
    90  	zBytes := ecutil.AllocECPointBuffer(z, priv.PublicKey.Curve)
    91  	defer ecutil.ReleaseECPointBuffer(zBytes)
    92  	kdf := concatkdf.New(crypto.SHA256, []byte(algorithm), zBytes, []byte{}, []byte{}, pubinfo, []byte{})
    93  	kek := make([]byte, g.keysize)
    94  	if _, err := kdf.Read(kek); err != nil {
    95  		return nil, errors.Wrap(err, "failed to read kdf")
    96  	}
    97  
    98  	return ByteWithECPublicKey{
    99  		PublicKey: &priv.PublicKey,
   100  		ByteKey:   ByteKey(kek),
   101  	}, nil
   102  }
   103  
   104  // NewX25519 creates a new key generator using ECDH-ES
   105  func NewX25519(alg jwa.KeyEncryptionAlgorithm, enc jwa.ContentEncryptionAlgorithm, keysize int, pubkey x25519.PublicKey) (*X25519, error) {
   106  	return &X25519{
   107  		algorithm: alg,
   108  		enc:       enc,
   109  		keysize:   keysize,
   110  		pubkey:    pubkey,
   111  	}, nil
   112  }
   113  
   114  // Size returns the key size associated with this generator
   115  func (g X25519) Size() int {
   116  	return g.keysize
   117  }
   118  
   119  // Generate generates new keys using ECDH-ES
   120  func (g X25519) Generate() (ByteSource, error) {
   121  	pub, priv, err := x25519.GenerateKey(rand.Reader)
   122  	if err != nil {
   123  		return nil, errors.Wrap(err, "failed to generate key for X25519")
   124  	}
   125  
   126  	var algorithm string
   127  	if g.algorithm == jwa.ECDH_ES {
   128  		algorithm = g.enc.String()
   129  	} else {
   130  		algorithm = g.algorithm.String()
   131  	}
   132  
   133  	pubinfo := make([]byte, 4)
   134  	binary.BigEndian.PutUint32(pubinfo, uint32(g.keysize)*8)
   135  
   136  	zBytes, err := curve25519.X25519(priv.Seed(), g.pubkey)
   137  	if err != nil {
   138  		return nil, errors.Wrap(err, "failed to compute Z")
   139  	}
   140  	kdf := concatkdf.New(crypto.SHA256, []byte(algorithm), zBytes, []byte{}, []byte{}, pubinfo, []byte{})
   141  	kek := make([]byte, g.keysize)
   142  	if _, err := kdf.Read(kek); err != nil {
   143  		return nil, errors.Wrap(err, "failed to read kdf")
   144  	}
   145  
   146  	return ByteWithECPublicKey{
   147  		PublicKey: pub,
   148  		ByteKey:   ByteKey(kek),
   149  	}, nil
   150  }
   151  
   152  // HeaderPopulate populates the header with the required EC-DSA public key
   153  // information ('epk' key)
   154  func (k ByteWithECPublicKey) Populate(h Setter) error {
   155  	key, err := jwk.New(k.PublicKey)
   156  	if err != nil {
   157  		return errors.Wrap(err, "failed to create JWK")
   158  	}
   159  
   160  	if err := h.Set("epk", key); err != nil {
   161  		return errors.Wrap(err, "failed to write header")
   162  	}
   163  	return nil
   164  }
   165  
   166  // HeaderPopulate populates the header with the required AES GCM
   167  // parameters ('iv' and 'tag')
   168  func (k ByteWithIVAndTag) Populate(h Setter) error {
   169  	if err := h.Set("iv", k.IV); err != nil {
   170  		return errors.Wrap(err, "failed to write header")
   171  	}
   172  
   173  	if err := h.Set("tag", k.Tag); err != nil {
   174  		return errors.Wrap(err, "failed to write header")
   175  	}
   176  
   177  	return nil
   178  }
   179  
   180  // HeaderPopulate populates the header with the required PBES2
   181  // parameters ('p2s' and 'p2c')
   182  func (k ByteWithSaltAndCount) Populate(h Setter) error {
   183  	if err := h.Set("p2c", k.Count); err != nil {
   184  		return errors.Wrap(err, "failed to write header")
   185  	}
   186  
   187  	if err := h.Set("p2s", k.Salt); err != nil {
   188  		return errors.Wrap(err, "failed to write header")
   189  	}
   190  
   191  	return nil
   192  }
   193  

View as plain text