github.com/cloudflare/circl@v1.5.0/hpke/marshal.go (about)

     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  }