shortkem.go raw

   1  package hpke
   2  
   3  import (
   4  	"crypto/ecdh"
   5  	"crypto/rand"
   6  	"fmt"
   7  
   8  	"github.com/cloudflare/circl/kem"
   9  )
  10  
  11  type shortKEM struct {
  12  	dhKemBase
  13  	ecdh.Curve
  14  }
  15  
  16  func (s shortKEM) PrivateKeySize() int        { return s.byteSize() }
  17  func (s shortKEM) SeedSize() int              { return s.byteSize() }
  18  func (s shortKEM) CiphertextSize() int        { return 1 + 2*s.byteSize() }
  19  func (s shortKEM) PublicKeySize() int         { return 1 + 2*s.byteSize() }
  20  func (s shortKEM) EncapsulationSeedSize() int { return s.byteSize() }
  21  
  22  func (s shortKEM) byteSize() int {
  23  	var bits int
  24  	switch s.Curve {
  25  	case ecdh.P256():
  26  		bits = 256
  27  	case ecdh.P384():
  28  		bits = 384
  29  	case ecdh.P521():
  30  		bits = 521
  31  	default:
  32  		panic(ErrInvalidKEM)
  33  	}
  34  
  35  	return (bits + 7) / 8
  36  }
  37  
  38  func (s shortKEM) sizeDH() int { return s.byteSize() }
  39  func (s shortKEM) calcDH(dh []byte, sk kem.PrivateKey, pk kem.PublicKey) error {
  40  	PK, ok := pk.(*shortKEMPubKey)
  41  	if !ok {
  42  		return ErrInvalidKEMPublicKey
  43  	}
  44  
  45  	SK, ok := sk.(*shortKEMPrivKey)
  46  	if !ok {
  47  		return ErrInvalidKEMPrivateKey
  48  	}
  49  
  50  	x, err := SK.priv.ECDH(&PK.pub)
  51  	if err != nil {
  52  		return err
  53  	}
  54  
  55  	copy(dh, x)
  56  	return nil
  57  }
  58  
  59  // Deterministically derives a keypair from a seed. If you're unsure,
  60  // you're better off using GenerateKey().
  61  //
  62  // Panics if seed is not of length SeedSize().
  63  func (s shortKEM) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) {
  64  	// Implementation based on
  65  	// https://www.ietf.org/archive/id/draft-irtf-cfrg-hpke-07.html#name-derivekeypair
  66  	if len(seed) != s.SeedSize() {
  67  		panic(kem.ErrSeedSize)
  68  	}
  69  
  70  	bitmask := byte(0xFF)
  71  	if s.Curve == ecdh.P521() {
  72  		bitmask = 0x01
  73  	}
  74  
  75  	dkpPrk := s.labeledExtract([]byte(""), []byte("dkp_prk"), seed)
  76  	for ctr := 0; ctr <= 255; ctr++ {
  77  		bytes := s.labeledExpand(
  78  			dkpPrk,
  79  			[]byte("candidate"),
  80  			[]byte{byte(ctr)},
  81  			uint16(s.byteSize()),
  82  		)
  83  		bytes[0] &= bitmask
  84  		sk, err := s.UnmarshalBinaryPrivateKey(bytes)
  85  		if err == nil {
  86  			return sk.Public(), sk
  87  		}
  88  	}
  89  
  90  	panic(ErrInvalidKEMDeriveKey)
  91  }
  92  
  93  func (s shortKEM) GenerateKeyPair() (kem.PublicKey, kem.PrivateKey, error) {
  94  	key, err := s.Curve.GenerateKey(rand.Reader)
  95  	if err != nil {
  96  		return nil, nil, err
  97  	}
  98  
  99  	sk := &shortKEMPrivKey{s, key}
 100  	return sk.Public(), sk, err
 101  }
 102  
 103  func (s shortKEM) UnmarshalBinaryPrivateKey(data []byte) (kem.PrivateKey, error) {
 104  	key, err := s.Curve.NewPrivateKey(data)
 105  	if err != nil {
 106  		return nil, ErrInvalidKEMPrivateKey
 107  	}
 108  
 109  	return &shortKEMPrivKey{s, key}, nil
 110  }
 111  
 112  func (s shortKEM) UnmarshalBinaryPublicKey(data []byte) (kem.PublicKey, error) {
 113  	key, err := s.Curve.NewPublicKey(data)
 114  	if err != nil {
 115  		return nil, ErrInvalidKEMPublicKey
 116  	}
 117  
 118  	return &shortKEMPubKey{s, *key}, nil
 119  }
 120  
 121  type shortKEMPubKey struct {
 122  	scheme shortKEM
 123  	pub    ecdh.PublicKey
 124  }
 125  
 126  func (k *shortKEMPubKey) String() string                 { return fmt.Sprintf("%x", k.pub.Bytes()) }
 127  func (k *shortKEMPubKey) Scheme() kem.Scheme             { return k.scheme }
 128  func (k *shortKEMPubKey) MarshalBinary() ([]byte, error) { return k.pub.Bytes(), nil }
 129  
 130  func (k *shortKEMPubKey) Equal(pk kem.PublicKey) bool {
 131  	k1, ok := pk.(*shortKEMPubKey)
 132  	return ok && k.scheme == k1.scheme && k.pub.Equal(&k1.pub)
 133  }
 134  
 135  type shortKEMPrivKey struct {
 136  	scheme shortKEM
 137  	priv   *ecdh.PrivateKey
 138  }
 139  
 140  func (k *shortKEMPrivKey) String() string                 { return fmt.Sprintf("%x", k.priv.Bytes()) }
 141  func (k *shortKEMPrivKey) Scheme() kem.Scheme             { return k.scheme }
 142  func (k *shortKEMPrivKey) MarshalBinary() ([]byte, error) { return k.priv.Bytes(), nil }
 143  
 144  func (k *shortKEMPrivKey) Equal(pk kem.PrivateKey) bool {
 145  	k1, ok := pk.(*shortKEMPrivKey)
 146  	return ok && k.scheme == k1.scheme && k.priv.Equal(k1.priv)
 147  }
 148  
 149  func (k *shortKEMPrivKey) Public() kem.PublicKey {
 150  	return &shortKEMPubKey{k.scheme, *k.priv.PublicKey()}
 151  }
 152