marshal.go raw

   1  package hpke
   2  
   3  import (
   4  	"errors"
   5  
   6  	"golang.org/x/crypto/cryptobyte"
   7  )
   8  
   9  // marshal serializes an HPKE context.
  10  func (c *encdecContext) marshal() ([]byte, error) {
  11  	var b cryptobyte.Builder
  12  	b.AddUint16(uint16(c.suite.kemID))
  13  	b.AddUint16(uint16(c.suite.kdfID))
  14  	b.AddUint16(uint16(c.suite.aeadID))
  15  	b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
  16  		b.AddBytes(c.exporterSecret)
  17  	})
  18  	b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
  19  		b.AddBytes(c.key)
  20  	})
  21  	b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
  22  		b.AddBytes(c.baseNonce)
  23  	})
  24  	b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
  25  		b.AddBytes(c.sequenceNumber)
  26  	})
  27  	return b.Bytes()
  28  }
  29  
  30  // unmarshalContext parses an HPKE context.
  31  func unmarshalContext(raw []byte) (*encdecContext, error) {
  32  	var (
  33  		err error
  34  		t   cryptobyte.String
  35  	)
  36  
  37  	c := new(encdecContext)
  38  	s := cryptobyte.String(raw)
  39  	if !s.ReadUint16((*uint16)(&c.suite.kemID)) ||
  40  		!s.ReadUint16((*uint16)(&c.suite.kdfID)) ||
  41  		!s.ReadUint16((*uint16)(&c.suite.aeadID)) ||
  42  		!s.ReadUint8LengthPrefixed(&t) ||
  43  		!t.ReadBytes(&c.exporterSecret, len(t)) ||
  44  		!s.ReadUint8LengthPrefixed(&t) ||
  45  		!t.ReadBytes(&c.key, len(t)) ||
  46  		!s.ReadUint8LengthPrefixed(&t) ||
  47  		!t.ReadBytes(&c.baseNonce, len(t)) ||
  48  		!s.ReadUint8LengthPrefixed(&t) ||
  49  		!t.ReadBytes(&c.sequenceNumber, len(t)) {
  50  		return nil, errors.New("failed to parse context")
  51  	}
  52  
  53  	if !c.suite.isValid() {
  54  		return nil, ErrInvalidHPKESuite
  55  	}
  56  
  57  	Nh := c.suite.kdfID.ExtractSize()
  58  	if len(c.exporterSecret) != Nh {
  59  		return nil, errors.New("invalid exporter secret length")
  60  	}
  61  
  62  	Nk := int(c.suite.aeadID.KeySize())
  63  	if len(c.key) != Nk {
  64  		return nil, errors.New("invalid key length")
  65  	}
  66  
  67  	c.AEAD, err = c.suite.aeadID.New(c.key)
  68  	if err != nil {
  69  		return nil, err
  70  	}
  71  
  72  	Nn := int(c.suite.aeadID.NonceSize())
  73  	if len(c.baseNonce) != Nn {
  74  		return nil, errors.New("invalid base nonce length")
  75  	}
  76  	if len(c.sequenceNumber) != Nn {
  77  		return nil, errors.New("invalid sequence number length")
  78  	}
  79  	c.nonce = make([]byte, Nn)
  80  
  81  	return c, nil
  82  }
  83  
  84  // MarshalBinary serializes an HPKE sealer according to the format specified
  85  // below. (Expressed in TLS syntax.) Note that this format is not defined by
  86  // the HPKE standard.
  87  //
  88  // enum { sealer(0), opener(1) } HpkeRole;
  89  //
  90  //	struct {
  91  //	    HpkeKemId kem_id;   // draft-irtf-cfrg-hpke-07
  92  //	    HpkeKdfId kdf_id;   // draft-irtf-cfrg-hpke-07
  93  //	    HpkeAeadId aead_id; // draft-irtf-cfrg-hpke-07
  94  //	    opaque exporter_secret<0..255>;
  95  //	    opaque key<0..255>;
  96  //	    opaque base_nonce<0..255>;
  97  //	    opaque seq<0..255>;
  98  //	} HpkeContext;
  99  //
 100  //	struct {
 101  //	  HpkeRole role = 0; // sealer
 102  //	  HpkeContext context;
 103  //	} HpkeSealer;
 104  func (c *sealContext) MarshalBinary() ([]byte, error) {
 105  	rawContext, err := c.encdecContext.marshal()
 106  	if err != nil {
 107  		return nil, err
 108  	}
 109  	return append([]byte{0}, rawContext...), nil
 110  }
 111  
 112  // UnmarshalSealer parses an HPKE sealer.
 113  func UnmarshalSealer(raw []byte) (Sealer, error) {
 114  	if raw[0] != 0 {
 115  		return nil, errors.New("incorrect role")
 116  	}
 117  	context, err := unmarshalContext(raw[1:])
 118  	if err != nil {
 119  		return nil, err
 120  	}
 121  	return &sealContext{context}, nil
 122  }
 123  
 124  // MarshalBinary serializes an HPKE opener according to the format specified
 125  // below. (Expressed in TLS syntax.) Note that this format is not defined by the
 126  // HPKE standard.
 127  //
 128  //	struct {
 129  //	  HpkeRole role = 1; // opener
 130  //	  HpkeContext context;
 131  //	} HpkeOpener;
 132  func (c *openContext) MarshalBinary() ([]byte, error) {
 133  	rawContext, err := c.encdecContext.marshal()
 134  	if err != nil {
 135  		return nil, err
 136  	}
 137  	return append([]byte{1}, rawContext...), nil
 138  }
 139  
 140  // UnmarshalOpener parses a serialized HPKE opener and returns the corresponding
 141  // Opener.
 142  func UnmarshalOpener(raw []byte) (Opener, error) {
 143  	if raw[0] != 1 {
 144  		return nil, errors.New("incorrect role")
 145  	}
 146  	context, err := unmarshalContext(raw[1:])
 147  	if err != nil {
 148  		return nil, err
 149  	}
 150  	return &openContext{context}, nil
 151  }
 152