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