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 }