framing.go raw

   1  package mls
   2  
   3  import (
   4  	"bytes"
   5  	"crypto/rand"
   6  	"fmt"
   7  	"io"
   8  
   9  	"golang.org/x/crypto/cryptobyte"
  10  )
  11  
  12  type protocolVersion uint16
  13  
  14  const (
  15  	protocolVersionMLS10 protocolVersion = 1
  16  )
  17  
  18  type contentType uint8
  19  
  20  const (
  21  	contentTypeApplication contentType = 1
  22  	contentTypeProposal    contentType = 2
  23  	contentTypeCommit      contentType = 3
  24  )
  25  
  26  func (ct *contentType) unmarshal(s *cryptobyte.String) error {
  27  	if !s.ReadUint8((*uint8)(ct)) {
  28  		return io.ErrUnexpectedEOF
  29  	}
  30  	switch *ct {
  31  	case contentTypeApplication, contentTypeProposal, contentTypeCommit:
  32  		return nil
  33  	default:
  34  		return fmt.Errorf("mls: invalid content type %d", *ct)
  35  	}
  36  }
  37  
  38  func (ct contentType) marshal(b *cryptobyte.Builder) {
  39  	b.AddUint8(uint8(ct))
  40  }
  41  
  42  type senderType uint8
  43  
  44  const (
  45  	senderTypeMember            senderType = 1
  46  	senderTypeExternal          senderType = 2
  47  	senderTypeNewMemberProposal senderType = 3
  48  	senderTypeNewMemberCommit   senderType = 4
  49  )
  50  
  51  func (st *senderType) unmarshal(s *cryptobyte.String) error {
  52  	if !s.ReadUint8((*uint8)(st)) {
  53  		return io.ErrUnexpectedEOF
  54  	}
  55  	switch *st {
  56  	case senderTypeMember, senderTypeExternal, senderTypeNewMemberProposal, senderTypeNewMemberCommit:
  57  		return nil
  58  	default:
  59  		return fmt.Errorf("mls: invalid sender type %d", *st)
  60  	}
  61  }
  62  
  63  func (st senderType) marshal(b *cryptobyte.Builder) {
  64  	b.AddUint8(uint8(st))
  65  }
  66  
  67  type sender struct {
  68  	senderType  senderType
  69  	leafIndex   leafIndex // for senderTypeMember
  70  	senderIndex uint32    // for senderTypeExternal
  71  }
  72  
  73  func (snd *sender) unmarshal(s *cryptobyte.String) error {
  74  	*snd = sender{}
  75  	if err := snd.senderType.unmarshal(s); err != nil {
  76  		return err
  77  	}
  78  	switch snd.senderType {
  79  	case senderTypeMember:
  80  		if !s.ReadUint32((*uint32)(&snd.leafIndex)) {
  81  			return io.ErrUnexpectedEOF
  82  		}
  83  	case senderTypeExternal:
  84  		if !s.ReadUint32(&snd.senderIndex) {
  85  			return io.ErrUnexpectedEOF
  86  		}
  87  	}
  88  	return nil
  89  }
  90  
  91  func (snd *sender) marshal(b *cryptobyte.Builder) {
  92  	snd.senderType.marshal(b)
  93  	switch snd.senderType {
  94  	case senderTypeMember:
  95  		b.AddUint32(uint32(snd.leafIndex))
  96  	case senderTypeExternal:
  97  		b.AddUint32(snd.senderIndex)
  98  	}
  99  }
 100  
 101  type wireFormat uint16
 102  
 103  // http://www.iana.org/assignments/mls/mls.xhtml#mls-wire-formats
 104  const (
 105  	wireFormatMLSPublicMessage  wireFormat = 0x0001
 106  	wireFormatMLSPrivateMessage wireFormat = 0x0002
 107  	wireFormatMLSWelcome        wireFormat = 0x0003
 108  	wireFormatMLSGroupInfo      wireFormat = 0x0004
 109  	wireFormatMLSKeyPackage     wireFormat = 0x0005
 110  )
 111  
 112  func (wf *wireFormat) unmarshal(s *cryptobyte.String) error {
 113  	if !s.ReadUint16((*uint16)(wf)) {
 114  		return io.ErrUnexpectedEOF
 115  	}
 116  	switch *wf {
 117  	case wireFormatMLSPublicMessage, wireFormatMLSPrivateMessage, wireFormatMLSWelcome, wireFormatMLSGroupInfo, wireFormatMLSKeyPackage:
 118  		return nil
 119  	default:
 120  		return fmt.Errorf("mls: invalid wire format %d", *wf)
 121  	}
 122  }
 123  
 124  func (wf wireFormat) marshal(b *cryptobyte.Builder) {
 125  	b.AddUint16(uint16(wf))
 126  }
 127  
 128  // GroupID is an application-specific group identifier.
 129  type GroupID []byte
 130  
 131  // Equal checks whether two key package references are equal.
 132  func (ref GroupID) Equal(other GroupID) bool {
 133  	return bytes.Equal([]byte(ref), []byte(other))
 134  }
 135  
 136  type framedContent struct {
 137  	groupID           GroupID
 138  	epoch             uint64
 139  	sender            sender
 140  	authenticatedData []byte
 141  
 142  	contentType     contentType
 143  	applicationData []byte    // for contentTypeApplication
 144  	proposal        *proposal // for contentTypeProposal
 145  	commit          *commit   // for contentTypeCommit
 146  }
 147  
 148  func (content *framedContent) unmarshal(s *cryptobyte.String) error {
 149  	*content = framedContent{}
 150  
 151  	if !readOpaqueVec(s, (*[]byte)(&content.groupID)) || !s.ReadUint64(&content.epoch) {
 152  		return io.ErrUnexpectedEOF
 153  	}
 154  	if err := content.sender.unmarshal(s); err != nil {
 155  		return err
 156  	}
 157  	if !readOpaqueVec(s, &content.authenticatedData) {
 158  		return io.ErrUnexpectedEOF
 159  	}
 160  	if err := content.contentType.unmarshal(s); err != nil {
 161  		return err
 162  	}
 163  
 164  	switch content.contentType {
 165  	case contentTypeApplication:
 166  		if !readOpaqueVec(s, &content.applicationData) {
 167  			return io.ErrUnexpectedEOF
 168  		}
 169  		return nil
 170  	case contentTypeProposal:
 171  		content.proposal = new(proposal)
 172  		return content.proposal.unmarshal(s)
 173  	case contentTypeCommit:
 174  		content.commit = new(commit)
 175  		return content.commit.unmarshal(s)
 176  	default:
 177  		panic("unreachable")
 178  	}
 179  }
 180  
 181  func (content *framedContent) marshal(b *cryptobyte.Builder) {
 182  	writeOpaqueVec(b, []byte(content.groupID))
 183  	b.AddUint64(content.epoch)
 184  	content.sender.marshal(b)
 185  	writeOpaqueVec(b, content.authenticatedData)
 186  	content.contentType.marshal(b)
 187  	switch content.contentType {
 188  	case contentTypeApplication:
 189  		writeOpaqueVec(b, content.applicationData)
 190  	case contentTypeProposal:
 191  		content.proposal.marshal(b)
 192  	case contentTypeCommit:
 193  		content.commit.marshal(b)
 194  	default:
 195  		panic("unreachable")
 196  	}
 197  }
 198  
 199  type mlsMessage struct {
 200  	version        protocolVersion
 201  	wireFormat     wireFormat
 202  	publicMessage  *publicMessage  // for wireFormatMLSPublicMessage
 203  	privateMessage *privateMessage // for wireFormatMLSPrivateMessage
 204  	welcome        *Welcome        // for wireFormatMLSWelcome
 205  	groupInfo      *groupInfo      // for wireFormatMLSGroupInfo
 206  	keyPackage     *KeyPackage     // for wireFormatMLSKeyPackage
 207  }
 208  
 209  func (msg *mlsMessage) unmarshal(s *cryptobyte.String) error {
 210  	*msg = mlsMessage{}
 211  
 212  	if !s.ReadUint16((*uint16)(&msg.version)) {
 213  		return io.ErrUnexpectedEOF
 214  	}
 215  	if msg.version != protocolVersionMLS10 {
 216  		return fmt.Errorf("mls: invalid protocol version %d", msg.version)
 217  	}
 218  
 219  	if err := msg.wireFormat.unmarshal(s); err != nil {
 220  		return err
 221  	}
 222  
 223  	switch msg.wireFormat {
 224  	case wireFormatMLSPublicMessage:
 225  		msg.publicMessage = new(publicMessage)
 226  		return msg.publicMessage.unmarshal(s)
 227  	case wireFormatMLSPrivateMessage:
 228  		msg.privateMessage = new(privateMessage)
 229  		return msg.privateMessage.unmarshal(s)
 230  	case wireFormatMLSWelcome:
 231  		msg.welcome = new(Welcome)
 232  		return msg.welcome.unmarshal(s)
 233  	case wireFormatMLSGroupInfo:
 234  		msg.groupInfo = new(groupInfo)
 235  		return msg.groupInfo.unmarshal(s)
 236  	case wireFormatMLSKeyPackage:
 237  		msg.keyPackage = new(KeyPackage)
 238  		return msg.keyPackage.unmarshal(s)
 239  	default:
 240  		panic("unreachable")
 241  	}
 242  }
 243  
 244  func (msg *mlsMessage) marshal(b *cryptobyte.Builder) {
 245  	b.AddUint16(uint16(msg.version))
 246  	msg.wireFormat.marshal(b)
 247  	switch msg.wireFormat {
 248  	case wireFormatMLSPublicMessage:
 249  		msg.publicMessage.marshal(b)
 250  	case wireFormatMLSPrivateMessage:
 251  		msg.privateMessage.marshal(b)
 252  	case wireFormatMLSWelcome:
 253  		msg.welcome.marshal(b)
 254  	case wireFormatMLSGroupInfo:
 255  		msg.groupInfo.marshal(b)
 256  	case wireFormatMLSKeyPackage:
 257  		msg.keyPackage.marshal(b)
 258  	default:
 259  		panic("unreachable")
 260  	}
 261  }
 262  
 263  type authenticatedContent struct {
 264  	wireFormat wireFormat
 265  	content    framedContent
 266  	auth       framedContentAuthData
 267  }
 268  
 269  func signAuthenticatedContent(cs CipherSuite, signKey signaturePrivateKey, wf wireFormat, content *framedContent, ctx *groupContext) (*authenticatedContent, error) {
 270  	authContent := authenticatedContent{
 271  		wireFormat: wf,
 272  		content:    *content,
 273  	}
 274  	tbs := authContent.framedContentTBS(ctx)
 275  	signature, err := signFramedContent(cs, signKey, tbs)
 276  	if err != nil {
 277  		return nil, err
 278  	}
 279  	authContent.auth.signature = signature
 280  	return &authContent, nil
 281  }
 282  
 283  func (authContent *authenticatedContent) unmarshal(s *cryptobyte.String) error {
 284  	if err := authContent.wireFormat.unmarshal(s); err != nil {
 285  		return err
 286  	}
 287  	if err := authContent.content.unmarshal(s); err != nil {
 288  		return err
 289  	}
 290  	if err := authContent.auth.unmarshal(s, authContent.content.contentType); err != nil {
 291  		return err
 292  	}
 293  	return nil
 294  }
 295  
 296  func (authContent *authenticatedContent) marshal(b *cryptobyte.Builder) {
 297  	authContent.wireFormat.marshal(b)
 298  	authContent.content.marshal(b)
 299  	authContent.auth.marshal(b, authContent.content.contentType)
 300  }
 301  
 302  func (authContent *authenticatedContent) confirmedTranscriptHashInput() *confirmedTranscriptHashInput {
 303  	return &confirmedTranscriptHashInput{
 304  		wireFormat: authContent.wireFormat,
 305  		content:    authContent.content,
 306  		signature:  authContent.auth.signature,
 307  	}
 308  }
 309  
 310  func (authContent *authenticatedContent) framedContentTBS(ctx *groupContext) *framedContentTBS {
 311  	return &framedContentTBS{
 312  		version:    protocolVersionMLS10,
 313  		wireFormat: authContent.wireFormat,
 314  		content:    authContent.content,
 315  		context:    ctx,
 316  	}
 317  }
 318  
 319  func (authContent *authenticatedContent) verifySignature(verifKey signaturePublicKey, ctx *groupContext) bool {
 320  	return authContent.auth.verifySignature(ctx.cipherSuite, verifKey, authContent.framedContentTBS(ctx))
 321  }
 322  
 323  func (authContent *authenticatedContent) generateProposalRef(cs CipherSuite) (proposalRef, error) {
 324  	if authContent.content.contentType != contentTypeProposal {
 325  		panic("mls: AuthenticatedContent is not a proposal")
 326  	}
 327  
 328  	var b cryptobyte.Builder
 329  	authContent.marshal(&b)
 330  	raw, err := b.Bytes()
 331  	if err != nil {
 332  		return nil, err
 333  	}
 334  
 335  	hash, err := cs.refHash([]byte("MLS 1.0 Proposal Reference"), raw)
 336  	if err != nil {
 337  		return nil, err
 338  	}
 339  
 340  	return proposalRef(hash), nil
 341  }
 342  
 343  type framedContentAuthData struct {
 344  	signature       []byte
 345  	confirmationTag []byte // for contentTypeCommit
 346  }
 347  
 348  func (authData *framedContentAuthData) unmarshal(s *cryptobyte.String, ct contentType) error {
 349  	*authData = framedContentAuthData{}
 350  
 351  	if !readOpaqueVec(s, &authData.signature) {
 352  		return io.ErrUnexpectedEOF
 353  	}
 354  
 355  	if ct == contentTypeCommit {
 356  		if !readOpaqueVec(s, &authData.confirmationTag) {
 357  			return io.ErrUnexpectedEOF
 358  		}
 359  	}
 360  
 361  	return nil
 362  }
 363  
 364  func (authData *framedContentAuthData) marshal(b *cryptobyte.Builder, ct contentType) {
 365  	writeOpaqueVec(b, authData.signature)
 366  
 367  	if ct == contentTypeCommit {
 368  		writeOpaqueVec(b, authData.confirmationTag)
 369  	}
 370  }
 371  
 372  func (authData *framedContentAuthData) verifyConfirmationTag(cs CipherSuite, confirmationKey, confirmedTranscriptHash []byte) bool {
 373  	if len(authData.confirmationTag) == 0 {
 374  		return false
 375  	}
 376  	return cs.verifyMAC(confirmationKey, confirmedTranscriptHash, authData.confirmationTag)
 377  }
 378  
 379  func (authData *framedContentAuthData) verifySignature(cs CipherSuite, verifKey signaturePublicKey, content *framedContentTBS) bool {
 380  	rawContent, err := marshal(content)
 381  	if err != nil {
 382  		return false
 383  	}
 384  	return cs.verifyWithLabel(verifKey, []byte("FramedContentTBS"), rawContent, authData.signature)
 385  }
 386  
 387  func signFramedContent(cs CipherSuite, signKey signaturePrivateKey, content *framedContentTBS) ([]byte, error) {
 388  	rawContent, err := marshal(content)
 389  	if err != nil {
 390  		return nil, err
 391  	}
 392  	return cs.signWithLabel(signKey, []byte("FramedContentTBS"), rawContent)
 393  }
 394  
 395  type framedContentTBS struct {
 396  	version    protocolVersion
 397  	wireFormat wireFormat
 398  	content    framedContent
 399  	context    *groupContext // for senderTypeMember and senderTypeNewMemberCommit
 400  }
 401  
 402  func (content *framedContentTBS) marshal(b *cryptobyte.Builder) {
 403  	b.AddUint16(uint16(content.version))
 404  	content.wireFormat.marshal(b)
 405  	content.content.marshal(b)
 406  	switch content.content.sender.senderType {
 407  	case senderTypeMember, senderTypeNewMemberCommit:
 408  		content.context.marshal(b)
 409  	}
 410  }
 411  
 412  type publicMessage struct {
 413  	content       framedContent
 414  	auth          framedContentAuthData
 415  	membershipTag []byte // for senderTypeMember
 416  }
 417  
 418  func signPublicMessage(cs CipherSuite, signKey signaturePrivateKey, content *framedContent, ctx *groupContext) (*publicMessage, error) {
 419  	authContent, err := signAuthenticatedContent(cs, signKey, wireFormatMLSPublicMessage, content, ctx)
 420  	if err != nil {
 421  		return nil, err
 422  	}
 423  	return &publicMessage{
 424  		content: authContent.content,
 425  		auth:    authContent.auth,
 426  	}, nil
 427  }
 428  
 429  func (msg *publicMessage) unmarshal(s *cryptobyte.String) error {
 430  	*msg = publicMessage{}
 431  
 432  	if err := msg.content.unmarshal(s); err != nil {
 433  		return err
 434  	}
 435  	if err := msg.auth.unmarshal(s, msg.content.contentType); err != nil {
 436  		return err
 437  	}
 438  
 439  	if msg.content.sender.senderType == senderTypeMember {
 440  		if !readOpaqueVec(s, &msg.membershipTag) {
 441  			return io.ErrUnexpectedEOF
 442  		}
 443  	}
 444  
 445  	return nil
 446  }
 447  
 448  func (msg *publicMessage) marshal(b *cryptobyte.Builder) {
 449  	msg.content.marshal(b)
 450  	msg.auth.marshal(b, msg.content.contentType)
 451  
 452  	if msg.content.sender.senderType == senderTypeMember {
 453  		writeOpaqueVec(b, msg.membershipTag)
 454  	}
 455  }
 456  
 457  func (msg *publicMessage) authenticatedContent() *authenticatedContent {
 458  	return &authenticatedContent{
 459  		wireFormat: wireFormatMLSPublicMessage,
 460  		content:    msg.content,
 461  		auth:       msg.auth,
 462  	}
 463  }
 464  
 465  func (msg *publicMessage) authenticatedContentTBM(ctx *groupContext) *authenticatedContentTBM {
 466  	return &authenticatedContentTBM{
 467  		contentTBS: *msg.authenticatedContent().framedContentTBS(ctx),
 468  		auth:       msg.auth,
 469  	}
 470  }
 471  
 472  func (msg *publicMessage) signMembershipTag(cs CipherSuite, membershipKey []byte, ctx *groupContext) error {
 473  	if msg.content.sender.senderType != senderTypeMember {
 474  		return nil
 475  	}
 476  	rawAuthContentTBM, err := marshal(msg.authenticatedContentTBM(ctx))
 477  	if err != nil {
 478  		return err
 479  	}
 480  	msg.membershipTag = cs.signMAC(membershipKey, rawAuthContentTBM)
 481  	return nil
 482  }
 483  
 484  func (msg *publicMessage) verifyMembershipTag(membershipKey []byte, ctx *groupContext) bool {
 485  	if msg.content.sender.senderType != senderTypeMember {
 486  		return true // there is no membership tag
 487  	}
 488  	rawAuthContentTBM, err := marshal(msg.authenticatedContentTBM(ctx))
 489  	if err != nil {
 490  		return false
 491  	}
 492  	return ctx.cipherSuite.verifyMAC(membershipKey, rawAuthContentTBM, msg.membershipTag)
 493  }
 494  
 495  type authenticatedContentTBM struct {
 496  	contentTBS framedContentTBS
 497  	auth       framedContentAuthData
 498  }
 499  
 500  func (tbm *authenticatedContentTBM) marshal(b *cryptobyte.Builder) {
 501  	tbm.contentTBS.marshal(b)
 502  	tbm.auth.marshal(b, tbm.contentTBS.content.contentType)
 503  }
 504  
 505  type privateMessage struct {
 506  	groupID             GroupID
 507  	epoch               uint64
 508  	contentType         contentType
 509  	authenticatedData   []byte
 510  	encryptedSenderData []byte
 511  	ciphertext          []byte
 512  }
 513  
 514  func encryptPrivateMessage(cs CipherSuite, secret ratchetSecret, senderDataSecret []byte, content *framedContent, privContent *privateMessageContent, senderData *senderData) (*privateMessage, error) {
 515  	ciphertext, err := encryptPrivateMessageContent(cs, secret, content, privContent, senderData.reuseGuard)
 516  	if err != nil {
 517  		return nil, err
 518  	}
 519  	encryptedSenderData, err := encryptSenderData(cs, senderDataSecret, senderData, content, ciphertext)
 520  	if err != nil {
 521  		return nil, err
 522  	}
 523  	return &privateMessage{
 524  		groupID:             content.groupID,
 525  		epoch:               content.epoch,
 526  		contentType:         content.contentType,
 527  		authenticatedData:   content.authenticatedData,
 528  		encryptedSenderData: encryptedSenderData,
 529  		ciphertext:          ciphertext,
 530  	}, nil
 531  }
 532  
 533  func (msg *privateMessage) unmarshal(s *cryptobyte.String) error {
 534  	*msg = privateMessage{}
 535  	ok := readOpaqueVec(s, (*[]byte)(&msg.groupID)) &&
 536  		s.ReadUint64(&msg.epoch)
 537  	if !ok {
 538  		return io.ErrUnexpectedEOF
 539  	}
 540  	if err := msg.contentType.unmarshal(s); err != nil {
 541  		return err
 542  	}
 543  	ok = readOpaqueVec(s, &msg.authenticatedData) &&
 544  		readOpaqueVec(s, &msg.encryptedSenderData) &&
 545  		readOpaqueVec(s, &msg.ciphertext)
 546  	if !ok {
 547  		return io.ErrUnexpectedEOF
 548  	}
 549  	return nil
 550  }
 551  
 552  func (msg *privateMessage) marshal(b *cryptobyte.Builder) {
 553  	writeOpaqueVec(b, []byte(msg.groupID))
 554  	b.AddUint64(msg.epoch)
 555  	msg.contentType.marshal(b)
 556  	writeOpaqueVec(b, msg.authenticatedData)
 557  	writeOpaqueVec(b, msg.encryptedSenderData)
 558  	writeOpaqueVec(b, msg.ciphertext)
 559  }
 560  
 561  func (msg *privateMessage) decryptSenderData(cs CipherSuite, senderDataSecret []byte) (*senderData, error) {
 562  	key, err := expandSenderDataKey(cs, senderDataSecret, msg.ciphertext)
 563  	if err != nil {
 564  		return nil, err
 565  	}
 566  	nonce, err := expandSenderDataNonce(cs, senderDataSecret, msg.ciphertext)
 567  	if err != nil {
 568  		return nil, err
 569  	}
 570  
 571  	aad := senderDataAAD{
 572  		groupID:     msg.groupID,
 573  		epoch:       msg.epoch,
 574  		contentType: msg.contentType,
 575  	}
 576  	rawAAD, err := marshal(&aad)
 577  	if err != nil {
 578  		return nil, err
 579  	}
 580  
 581  	_, _, aead := cs.hpke().Params()
 582  	cipher, err := aead.New(key)
 583  	if err != nil {
 584  		return nil, err
 585  	}
 586  
 587  	rawSenderData, err := cipher.Open(nil, nonce, msg.encryptedSenderData, rawAAD)
 588  	if err != nil {
 589  		return nil, err
 590  	}
 591  
 592  	var senderData senderData
 593  	if err := unmarshal(rawSenderData, &senderData); err != nil {
 594  		return nil, err
 595  	}
 596  
 597  	return &senderData, nil
 598  }
 599  
 600  func (msg *privateMessage) decryptContent(cs CipherSuite, secret ratchetSecret, reuseGuard [4]byte) (*privateMessageContent, error) {
 601  	key, nonce, err := derivePrivateMessageKeyAndNonce(cs, secret, reuseGuard)
 602  	if err != nil {
 603  		return nil, err
 604  	}
 605  
 606  	aad := privateContentAAD{
 607  		groupID:           msg.groupID,
 608  		epoch:             msg.epoch,
 609  		contentType:       msg.contentType,
 610  		authenticatedData: msg.authenticatedData,
 611  	}
 612  	rawAAD, err := marshal(&aad)
 613  	if err != nil {
 614  		return nil, err
 615  	}
 616  
 617  	_, _, aead := cs.hpke().Params()
 618  	cipher, err := aead.New(key)
 619  	if err != nil {
 620  		return nil, err
 621  	}
 622  
 623  	rawContent, err := cipher.Open(nil, nonce, msg.ciphertext, rawAAD)
 624  	if err != nil {
 625  		return nil, err
 626  	}
 627  
 628  	s := cryptobyte.String(rawContent)
 629  	var content privateMessageContent
 630  	if err := content.unmarshal(&s, msg.contentType); err != nil {
 631  		return nil, err
 632  	}
 633  
 634  	for _, v := range s {
 635  		if v != 0 {
 636  			return nil, fmt.Errorf("mls: padding contains non-zero bytes")
 637  		}
 638  	}
 639  
 640  	return &content, nil
 641  }
 642  
 643  func derivePrivateMessageKeyAndNonce(cs CipherSuite, secret ratchetSecret, reuseGuard [4]byte) (key, nonce []byte, err error) {
 644  	key, err = secret.deriveKey(cs)
 645  	if err != nil {
 646  		return nil, nil, err
 647  	}
 648  	nonce, err = secret.deriveNonce(cs)
 649  	if err != nil {
 650  		return nil, nil, err
 651  	}
 652  
 653  	for i := range reuseGuard {
 654  		nonce[i] = nonce[i] ^ reuseGuard[i]
 655  	}
 656  
 657  	return key, nonce, nil
 658  }
 659  
 660  func (msg *privateMessage) authenticatedContent(senderData *senderData, content *privateMessageContent) *authenticatedContent {
 661  	return content.authenticatedContent(&framedContent{
 662  		groupID: msg.groupID,
 663  		epoch:   msg.epoch,
 664  		sender: sender{
 665  			senderType: senderTypeMember,
 666  			leafIndex:  senderData.leafIndex,
 667  		},
 668  		authenticatedData: msg.authenticatedData,
 669  		contentType:       msg.contentType,
 670  		applicationData:   content.applicationData,
 671  		proposal:          content.proposal,
 672  		commit:            content.commit,
 673  	})
 674  }
 675  
 676  type senderDataAAD struct {
 677  	groupID     GroupID
 678  	epoch       uint64
 679  	contentType contentType
 680  }
 681  
 682  func (aad *senderDataAAD) marshal(b *cryptobyte.Builder) {
 683  	writeOpaqueVec(b, []byte(aad.groupID))
 684  	b.AddUint64(aad.epoch)
 685  	aad.contentType.marshal(b)
 686  }
 687  
 688  type privateContentAAD struct {
 689  	groupID           GroupID
 690  	epoch             uint64
 691  	contentType       contentType
 692  	authenticatedData []byte
 693  }
 694  
 695  func (aad *privateContentAAD) marshal(b *cryptobyte.Builder) {
 696  	writeOpaqueVec(b, []byte(aad.groupID))
 697  	b.AddUint64(aad.epoch)
 698  	aad.contentType.marshal(b)
 699  	writeOpaqueVec(b, aad.authenticatedData)
 700  }
 701  
 702  type privateMessageContent struct {
 703  	applicationData []byte    // for contentTypeApplication
 704  	proposal        *proposal // for contentTypeProposal
 705  	commit          *commit   // for contentTypeCommit
 706  
 707  	auth framedContentAuthData
 708  }
 709  
 710  func (content *privateMessageContent) unmarshal(s *cryptobyte.String, ct contentType) error {
 711  	*content = privateMessageContent{}
 712  
 713  	var err error
 714  	switch ct {
 715  	case contentTypeApplication:
 716  		if !readOpaqueVec(s, &content.applicationData) {
 717  			err = io.ErrUnexpectedEOF
 718  		}
 719  	case contentTypeProposal:
 720  		content.proposal = new(proposal)
 721  		err = content.proposal.unmarshal(s)
 722  	case contentTypeCommit:
 723  		content.commit = new(commit)
 724  		err = content.commit.unmarshal(s)
 725  	default:
 726  		panic("unreachable")
 727  	}
 728  	if err != nil {
 729  		return err
 730  	}
 731  
 732  	return content.auth.unmarshal(s, ct)
 733  }
 734  
 735  func (content *privateMessageContent) marshal(b *cryptobyte.Builder, ct contentType) {
 736  	switch ct {
 737  	case contentTypeApplication:
 738  		writeOpaqueVec(b, content.applicationData)
 739  	case contentTypeProposal:
 740  		content.proposal.marshal(b)
 741  	case contentTypeCommit:
 742  		content.commit.marshal(b)
 743  	default:
 744  		panic("unreachable")
 745  	}
 746  	content.auth.marshal(b, ct)
 747  }
 748  
 749  func (content *privateMessageContent) authenticatedContent(framedContent *framedContent) *authenticatedContent {
 750  	return &authenticatedContent{
 751  		wireFormat: wireFormatMLSPrivateMessage,
 752  		content:    *framedContent,
 753  		auth:       content.auth,
 754  	}
 755  }
 756  
 757  func signPrivateMessageContent(cs CipherSuite, signKey signaturePrivateKey, content *framedContent, ctx *groupContext) (*privateMessageContent, error) {
 758  	authContent, err := signAuthenticatedContent(cs, signKey, wireFormatMLSPrivateMessage, content, ctx)
 759  	if err != nil {
 760  		return nil, err
 761  	}
 762  
 763  	return &privateMessageContent{
 764  		applicationData: content.applicationData,
 765  		proposal:        content.proposal,
 766  		commit:          content.commit,
 767  		auth:            authContent.auth,
 768  	}, nil
 769  }
 770  
 771  func encryptPrivateMessageContent(cs CipherSuite, secret ratchetSecret, content *framedContent, privContent *privateMessageContent, reuseGuard [4]byte) ([]byte, error) {
 772  	var b cryptobyte.Builder
 773  	privContent.marshal(&b, content.contentType)
 774  	plaintext, err := b.Bytes()
 775  	if err != nil {
 776  		return nil, err
 777  	}
 778  
 779  	key, nonce, err := derivePrivateMessageKeyAndNonce(cs, secret, reuseGuard)
 780  	if err != nil {
 781  		return nil, err
 782  	}
 783  
 784  	aad := privateContentAAD{
 785  		groupID:           content.groupID,
 786  		epoch:             content.epoch,
 787  		contentType:       content.contentType,
 788  		authenticatedData: content.authenticatedData,
 789  	}
 790  	rawAAD, err := marshal(&aad)
 791  	if err != nil {
 792  		return nil, err
 793  	}
 794  
 795  	_, _, aead := cs.hpke().Params()
 796  	cipher, err := aead.New(key)
 797  	if err != nil {
 798  		return nil, err
 799  	}
 800  
 801  	return cipher.Seal(nil, nonce, plaintext, rawAAD), nil
 802  }
 803  
 804  func encryptSenderData(cs CipherSuite, senderDataSecret []byte, senderData *senderData, content *framedContent, ciphertext []byte) ([]byte, error) {
 805  	key, err := expandSenderDataKey(cs, senderDataSecret, ciphertext)
 806  	if err != nil {
 807  		return nil, err
 808  	}
 809  	nonce, err := expandSenderDataNonce(cs, senderDataSecret, ciphertext)
 810  	if err != nil {
 811  		return nil, err
 812  	}
 813  
 814  	aad := senderDataAAD{
 815  		groupID:     content.groupID,
 816  		epoch:       content.epoch,
 817  		contentType: content.contentType,
 818  	}
 819  	rawAAD, err := marshal(&aad)
 820  	if err != nil {
 821  		return nil, err
 822  	}
 823  
 824  	_, _, aead := cs.hpke().Params()
 825  	cipher, err := aead.New(key)
 826  	if err != nil {
 827  		return nil, err
 828  	}
 829  
 830  	rawSenderData, err := marshal(senderData)
 831  	if err != nil {
 832  		return nil, err
 833  	}
 834  
 835  	return cipher.Seal(nil, nonce, rawSenderData, rawAAD), nil
 836  }
 837  
 838  type senderData struct {
 839  	leafIndex  leafIndex
 840  	generation uint32
 841  	reuseGuard [4]byte
 842  }
 843  
 844  func newSenderData(leafIndex leafIndex, generation uint32) (*senderData, error) {
 845  	data := senderData{
 846  		leafIndex:  leafIndex,
 847  		generation: generation,
 848  	}
 849  	if _, err := rand.Read(data.reuseGuard[:]); err != nil {
 850  		return nil, err
 851  	}
 852  	return &data, nil
 853  }
 854  
 855  func (data *senderData) unmarshal(s *cryptobyte.String) error {
 856  	if !s.ReadUint32((*uint32)(&data.leafIndex)) || !s.ReadUint32(&data.generation) || !s.CopyBytes(data.reuseGuard[:]) {
 857  		return io.ErrUnexpectedEOF
 858  	}
 859  	return nil
 860  }
 861  
 862  func (data *senderData) marshal(b *cryptobyte.Builder) {
 863  	b.AddUint32(uint32(data.leafIndex))
 864  	b.AddUint32(data.generation)
 865  	b.AddBytes(data.reuseGuard[:])
 866  }
 867  
 868  func expandSenderDataKey(cs CipherSuite, senderDataSecret, ciphertext []byte) ([]byte, error) {
 869  	_, _, aead := cs.hpke().Params()
 870  	ciphertextSample := sampleCiphertext(cs, ciphertext)
 871  	return cs.expandWithLabel(senderDataSecret, []byte("key"), ciphertextSample, uint16(aead.KeySize()))
 872  }
 873  
 874  func expandSenderDataNonce(cs CipherSuite, senderDataSecret, ciphertext []byte) ([]byte, error) {
 875  	_, _, aead := cs.hpke().Params()
 876  	ciphertextSample := sampleCiphertext(cs, ciphertext)
 877  	return cs.expandWithLabel(senderDataSecret, []byte("nonce"), ciphertextSample, uint16(aead.NonceSize()))
 878  }
 879  
 880  func sampleCiphertext(cs CipherSuite, ciphertext []byte) []byte {
 881  	_, kdf, _ := cs.hpke().Params()
 882  	n := kdf.ExtractSize()
 883  	if len(ciphertext) < n {
 884  		return ciphertext
 885  	}
 886  	return ciphertext[:n]
 887  }
 888