github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/chat/boxer.go (about)

     1  // Copyright 2016 Keybase, Inc. All rights reserved. Use of
     2  // this source code is governed by the included BSD license.
     3  
     4  package chat
     5  
     6  import (
     7  	"bytes"
     8  	"crypto/hmac"
     9  	"crypto/rand"
    10  	"crypto/sha256"
    11  	"encoding/binary"
    12  	"encoding/hex"
    13  	"errors"
    14  	"flag"
    15  	"fmt"
    16  	"sort"
    17  	"sync"
    18  	"time"
    19  
    20  	"golang.org/x/crypto/nacl/box"
    21  	"golang.org/x/crypto/nacl/secretbox"
    22  	"golang.org/x/net/context"
    23  	"golang.org/x/sync/errgroup"
    24  
    25  	"github.com/keybase/client/go/chat/globals"
    26  	"github.com/keybase/client/go/chat/signencrypt"
    27  	"github.com/keybase/client/go/chat/storage"
    28  	"github.com/keybase/client/go/chat/types"
    29  	"github.com/keybase/client/go/chat/utils"
    30  	"github.com/keybase/client/go/ephemeral"
    31  	"github.com/keybase/client/go/kbcrypto"
    32  	"github.com/keybase/client/go/libkb"
    33  	"github.com/keybase/client/go/logger"
    34  	"github.com/keybase/client/go/protocol/chat1"
    35  	"github.com/keybase/client/go/protocol/gregor1"
    36  	"github.com/keybase/client/go/protocol/keybase1"
    37  	"github.com/keybase/client/go/teambot"
    38  	"github.com/keybase/client/go/teams"
    39  	"github.com/keybase/clockwork"
    40  	"github.com/keybase/go-codec/codec"
    41  	"github.com/keybase/go-crypto/ed25519"
    42  )
    43  
    44  const CurrentMessageBoxedVersion = chat1.MessageBoxedVersion_V2
    45  
    46  var publicCryptKey keybase1.CryptKey
    47  
    48  func init() {
    49  	// publicCryptKey is a zero key used for public chat messages.
    50  	var zero [libkb.NaclDHKeySecretSize]byte
    51  	publicCryptKey = keybase1.CryptKey{
    52  		KeyGeneration: 1,
    53  		Key:           keybase1.Bytes32(zero),
    54  	}
    55  }
    56  
    57  type Boxer struct {
    58  	utils.DebugLabeler
    59  	globals.Contextified
    60  
    61  	boxVersionForTesting *chat1.MessageBoxedVersion
    62  
    63  	// Replaceable for testing.
    64  	// Normally set to normal implementations.
    65  	hashV1 func(data []byte) chat1.Hash
    66  
    67  	// Slots for replacing with test implementations.
    68  	// These are normally nil.
    69  	testingValidSenderKey     func(context.Context, gregor1.UID, []byte, gregor1.Time) (revoked *gregor1.Time, unboxingErr types.UnboxingError)
    70  	testingGetSenderInfoLocal func(context.Context, gregor1.UID, gregor1.DeviceID) (senderUsername string, senderDeviceName string, senderDeviceType keybase1.DeviceTypeV2)
    71  	// Post-process signatures and signencrypts
    72  	testingSignatureMangle func([]byte) []byte
    73  
    74  	clock clockwork.Clock
    75  }
    76  
    77  func NewBoxer(g *globals.Context) *Boxer {
    78  	return &Boxer{
    79  		DebugLabeler: utils.NewDebugLabeler(g.ExternalG(), "Boxer", false),
    80  		hashV1:       hashSha256V1,
    81  		Contextified: globals.NewContextified(g),
    82  		clock:        clockwork.NewRealClock(),
    83  	}
    84  }
    85  
    86  func (b *Boxer) SetClock(clock clockwork.Clock) {
    87  	b.clock = clock
    88  }
    89  
    90  func (b *Boxer) log() logger.Logger {
    91  	return b.G().GetLog()
    92  }
    93  
    94  func (b *Boxer) makeErrorMessageFromPieces(ctx context.Context, err types.UnboxingError,
    95  	msgID chat1.MessageID, msgType chat1.MessageType, ctime gregor1.Time,
    96  	sender gregor1.UID, senderDevice gregor1.DeviceID, botUID *gregor1.UID,
    97  	isEphemeral bool, explodedBy *string, etime gregor1.Time) chat1.MessageUnboxed {
    98  	e := chat1.MessageUnboxedError{
    99  		ErrType:        err.ExportType(),
   100  		ErrMsg:         err.Error(),
   101  		InternalErrMsg: err.InternalError(),
   102  		VersionKind:    err.VersionKind(),
   103  		VersionNumber:  err.VersionNumber(),
   104  		IsCritical:     err.IsCritical(),
   105  		MessageID:      msgID,
   106  		MessageType:    msgType,
   107  		Ctime:          ctime,
   108  		IsEphemeral:    isEphemeral,
   109  		ExplodedBy:     explodedBy,
   110  		Etime:          etime,
   111  		BotUsername:    b.getBotInfoLocal(ctx, botUID),
   112  	}
   113  	e.SenderUsername, e.SenderDeviceName, e.SenderDeviceType = b.getSenderInfoLocal(ctx,
   114  		sender, senderDevice)
   115  	return chat1.NewMessageUnboxedWithError(e)
   116  }
   117  
   118  func (b *Boxer) makeErrorMessage(ctx context.Context, msg chat1.MessageBoxed, err types.UnboxingError) chat1.MessageUnboxed {
   119  	return b.makeErrorMessageFromPieces(ctx, err, msg.GetMessageID(), msg.GetMessageType(),
   120  		msg.ServerHeader.Ctime, msg.ClientHeader.Sender, msg.ClientHeader.SenderDevice,
   121  		msg.ClientHeader.BotUID,
   122  		msg.IsEphemeral(), msg.ExplodedBy(), msg.Etime())
   123  }
   124  
   125  func (b *Boxer) detectPermanentError(conv types.UnboxConversationInfo, err error, tlfName string) types.UnboxingError {
   126  	// Check for team not exist error that is in raw form
   127  	if aerr, ok := err.(libkb.AppStatusError); ok {
   128  		switch keybase1.StatusCode(aerr.Code) {
   129  		case keybase1.StatusCode_SCTeamNotFound:
   130  			return NewPermanentUnboxingError(err)
   131  		default:
   132  			// Nothing to do.
   133  		}
   134  	}
   135  
   136  	if _, ok := IsRekeyError(err); ok && conv.GetFinalizeInfo() != nil {
   137  		return NewPermanentUnboxingError(err)
   138  	}
   139  
   140  	// Check if we have a permanent or tranisent team read error. Transient
   141  	// errors, are converted to rekey errors later.
   142  	if teams.IsTeamReadError(err) {
   143  		switch err.Error() {
   144  		case "Root team has been deleted",
   145  			"Root team has been abandoned: All members have left or reset",
   146  			"Root team is not active":
   147  			return NewPermanentUnboxingError(err)
   148  		default:
   149  			return NewTransientUnboxingError(err)
   150  		}
   151  	}
   152  	switch err := err.(type) {
   153  	case libkb.UserDeletedError:
   154  		if len(err.Msg) == 0 {
   155  			err.Msg = fmt.Sprintf("user deleted in chat '%v'", tlfName)
   156  		}
   157  		return NewPermanentUnboxingError(err)
   158  	case teams.TeamDoesNotExistError,
   159  		teams.KBFSKeyGenerationError,
   160  		libkb.KeyMaskNotFoundError,
   161  		libkb.AssertionCheckError,
   162  		DecryptionKeyNotFoundError,
   163  		NotAuthenticatedForThisDeviceError,
   164  		InvalidMACError,
   165  		ImpteamBadteamError,
   166  		teambot.TeambotPermanentKeyError:
   167  		return NewPermanentUnboxingError(err)
   168  	case ephemeral.EphemeralKeyError:
   169  		// Normalize error message with EphemeralUnboxingError
   170  		ekErr := NewEphemeralUnboxingError(err)
   171  		if err.IsPermanent() {
   172  			return NewPermanentUnboxingError(ekErr)
   173  		}
   174  		return NewTransientUnboxingError(ekErr)
   175  	}
   176  
   177  	// Check for no space left on device errors
   178  	if libkb.IsNoSpaceOnDeviceError(err) {
   179  		return NewPermanentUnboxingError(err)
   180  	}
   181  
   182  	// transient error. Rekey errors come through here
   183  	return NewTransientUnboxingError(err)
   184  }
   185  
   186  type basicUnboxConversationInfo struct {
   187  	convID       chat1.ConversationID
   188  	membersType  chat1.ConversationMembersType
   189  	finalizeInfo *chat1.ConversationFinalizeInfo
   190  	visibility   keybase1.TLFVisibility
   191  }
   192  
   193  var _ types.UnboxConversationInfo = (*basicUnboxConversationInfo)(nil)
   194  
   195  func newBasicUnboxConversationInfo(convID chat1.ConversationID,
   196  	membersType chat1.ConversationMembersType, finalizeInfo *chat1.ConversationFinalizeInfo,
   197  	visibility keybase1.TLFVisibility) *basicUnboxConversationInfo {
   198  	return &basicUnboxConversationInfo{
   199  		convID:       convID,
   200  		membersType:  membersType,
   201  		finalizeInfo: finalizeInfo,
   202  		visibility:   visibility,
   203  	}
   204  }
   205  
   206  func (b *basicUnboxConversationInfo) GetConvID() chat1.ConversationID {
   207  	return b.convID
   208  }
   209  
   210  func (b *basicUnboxConversationInfo) GetMembersType() chat1.ConversationMembersType {
   211  	return b.membersType
   212  }
   213  
   214  func (b *basicUnboxConversationInfo) GetFinalizeInfo() *chat1.ConversationFinalizeInfo {
   215  	return b.finalizeInfo
   216  }
   217  
   218  func (b *basicUnboxConversationInfo) GetExpunge() *chat1.Expunge {
   219  	return nil
   220  }
   221  
   222  func (b *basicUnboxConversationInfo) GetMaxDeletedUpTo() chat1.MessageID {
   223  	return 0
   224  }
   225  
   226  func (b *basicUnboxConversationInfo) IsPublic() bool {
   227  	return b.visibility == keybase1.TLFVisibility_PUBLIC
   228  }
   229  
   230  func (b *basicUnboxConversationInfo) GetMaxMessage(chat1.MessageType) (chat1.MessageSummary, error) {
   231  	return chat1.MessageSummary{}, nil
   232  }
   233  
   234  type extraInboxUnboxConversationInfo struct {
   235  	convID      chat1.ConversationID
   236  	membersType chat1.ConversationMembersType
   237  	visibility  keybase1.TLFVisibility
   238  }
   239  
   240  var _ types.UnboxConversationInfo = (*extraInboxUnboxConversationInfo)(nil)
   241  
   242  func newExtraInboxUnboxConverstionInfo(convID chat1.ConversationID, membersType chat1.ConversationMembersType,
   243  	visibility keybase1.TLFVisibility) *extraInboxUnboxConversationInfo {
   244  	return &extraInboxUnboxConversationInfo{
   245  		convID:      convID,
   246  		membersType: membersType,
   247  		visibility:  visibility,
   248  	}
   249  }
   250  
   251  func (p *extraInboxUnboxConversationInfo) GetConvID() chat1.ConversationID {
   252  	return p.convID
   253  }
   254  
   255  func (p *extraInboxUnboxConversationInfo) GetMembersType() chat1.ConversationMembersType {
   256  	return p.membersType
   257  }
   258  
   259  func (p *extraInboxUnboxConversationInfo) GetFinalizeInfo() *chat1.ConversationFinalizeInfo {
   260  	return nil
   261  }
   262  
   263  func (p *extraInboxUnboxConversationInfo) GetExpunge() *chat1.Expunge {
   264  	return nil
   265  }
   266  
   267  func (p *extraInboxUnboxConversationInfo) GetMaxDeletedUpTo() chat1.MessageID {
   268  	return 0
   269  }
   270  
   271  func (p *extraInboxUnboxConversationInfo) IsPublic() bool {
   272  	return p.visibility == keybase1.TLFVisibility_PUBLIC
   273  }
   274  
   275  func (p *extraInboxUnboxConversationInfo) GetMaxMessage(chat1.MessageType) (chat1.MessageSummary, error) {
   276  	return chat1.MessageSummary{}, nil
   277  }
   278  
   279  func (b *Boxer) getEffectiveMembersType(ctx context.Context, boxed chat1.MessageBoxed,
   280  	convMembersType chat1.ConversationMembersType) chat1.ConversationMembersType {
   281  	switch convMembersType {
   282  	case chat1.ConversationMembersType_IMPTEAMUPGRADE:
   283  		if boxed.KBFSEncrypted() {
   284  			b.Debug(ctx, "getEffectiveMembersType: overruling %v conv with KBFS keys", convMembersType)
   285  			return chat1.ConversationMembersType_KBFS
   286  		}
   287  	default:
   288  		// Nothing to do for other conv types.
   289  	}
   290  	return convMembersType
   291  }
   292  
   293  var errBoxerUnavailableMessage = NewPermanentUnboxingError(errors.New("message not available"))
   294  
   295  func (b *Boxer) castInternalError(ierr types.UnboxingError) error {
   296  	err, ok := ierr.(error)
   297  	if ok {
   298  		return err
   299  	}
   300  	return nil
   301  }
   302  
   303  // UnboxMessage unboxes a chat1.MessageBoxed into a chat1.MessageUnboxed. It
   304  // finds the appropriate keybase1.CryptKey, decrypts the message, and verifies
   305  // several things:
   306  //   - The message's signature is valid.
   307  //   - (TODO) The signing KID was valid when the signature was made.
   308  //   - (TODO) The signing KID belongs to the sending device.
   309  //   - (TODO) The sending device belongs to the sender.
   310  //     [Note that we do currently check the KID -> UID relationship,
   311  //     independent of the device ID.]
   312  //   - (TODO) The sender has write permission in the TLF.
   313  //   - (TODO) The TLF name, public flag, and finalized info resolve to the TLF ID.
   314  //   - The conversation ID derives from the ConversationIDTriple.
   315  //   - The body hash is not a replay from another message we know about.
   316  //   - The prev pointers are consistent with other messages we know about.
   317  //   - (TODO) The prev pointers are not absurdly ancient.
   318  //   - The ClientHeader provided with the BoxedMessage matches the one we decrypt.
   319  //
   320  // The first return value is unusable if the err != nil. Returns (_, err) for
   321  // non-permanent errors, and (MessageUnboxedError, nil) for permanent errors.
   322  // Permanent errors can be cached and must be treated as a value to deal with,
   323  // whereas temporary errors are transient failures.
   324  func (b *Boxer) UnboxMessage(ctx context.Context, boxed chat1.MessageBoxed, conv types.UnboxConversationInfo,
   325  	info *types.BoxerEncryptionInfo) (m chat1.MessageUnboxed, uberr types.UnboxingError) {
   326  	ctx = libkb.WithLogTag(ctx, "CHTUNBOX")
   327  	var err error
   328  	defer b.Trace(ctx, &err, "UnboxMessage(%s, %d)", conv.GetConvID(),
   329  		boxed.GetMessageID())()
   330  	defer func() { err = b.castInternalError(uberr) }()
   331  
   332  	// Check to see if the context has been cancelled
   333  	select {
   334  	case <-ctx.Done():
   335  		return m, NewTransientUnboxingError(ctx.Err())
   336  	default:
   337  	}
   338  
   339  	// if the server message doesn't have a TLFID, then it isn't available to us. This is most commonly
   340  	// used when restricted bots try to read messages not encrypted for them.
   341  	if boxed.ClientHeader.Conv.Tlfid.IsNil() {
   342  		return b.makeErrorMessage(ctx, boxed, errBoxerUnavailableMessage), nil
   343  	}
   344  
   345  	// If we don't have an rtime, add one.
   346  	if boxed.ServerHeader.Rtime == nil {
   347  		now := gregor1.ToTime(b.clock.Now())
   348  		boxed.ServerHeader.Rtime = &now
   349  	}
   350  	tlfName := boxed.ClientHeader.TLFNameExpanded(conv.GetFinalizeInfo())
   351  	if conv.IsPublic() != boxed.ClientHeader.TlfPublic {
   352  		return b.makeErrorMessage(ctx, boxed,
   353  			NewPermanentUnboxingError(fmt.Errorf("visibility mismatch: %v != %v", conv.IsPublic(),
   354  				boxed.ClientHeader.TlfPublic))), nil
   355  	}
   356  	if info == nil {
   357  		info = new(types.BoxerEncryptionInfo)
   358  		keyMembersType := b.getEffectiveMembersType(ctx, boxed, conv.GetMembersType())
   359  		encryptionKey, err := globals.CtxKeyFinder(ctx, b.G()).FindForDecryption(ctx,
   360  			tlfName, boxed.ClientHeader.Conv.Tlfid, conv.GetMembersType(),
   361  			conv.IsPublic(), boxed.KeyGeneration,
   362  			keyMembersType == chat1.ConversationMembersType_KBFS, boxed.ClientHeader.BotUID)
   363  		if err != nil {
   364  			// Post-process error from this
   365  			uberr = b.detectPermanentError(conv, err, tlfName)
   366  			if uberr.IsPermanent() {
   367  				return b.makeErrorMessage(ctx, boxed, uberr), nil
   368  			}
   369  			return chat1.MessageUnboxed{}, uberr
   370  		}
   371  
   372  		// If the message is exploding, load the ephemeral key.
   373  		var ephemeralKey types.EphemeralCryptKey
   374  		if boxed.IsEphemeral() {
   375  			ephemeralKey, err = globals.CtxKeyFinder(ctx, b.G()).EphemeralKeyForDecryption(
   376  				b.G().MetaContext(ctx), tlfName, boxed.ClientHeader.Conv.Tlfid, conv.GetMembersType(),
   377  				boxed.ClientHeader.TlfPublic, boxed.ClientHeader.BotUID,
   378  				boxed.EphemeralMetadata().Generation, &boxed.ServerHeader.Ctime)
   379  			if err != nil {
   380  				b.Debug(ctx, "failed to get a key for ephemeral message: msgID: %d err: %v", boxed.ServerHeader.MessageID, err)
   381  				uberr = b.detectPermanentError(conv, err, tlfName)
   382  				if uberr.IsPermanent() {
   383  					return b.makeErrorMessage(ctx, boxed, uberr), nil
   384  				}
   385  				return chat1.MessageUnboxed{}, uberr
   386  			}
   387  		}
   388  		info.Key = encryptionKey
   389  		info.EphemeralKey = ephemeralKey
   390  	}
   391  
   392  	unboxed, ierr := b.unbox(ctx, boxed, conv, info.Key, info.EphemeralKey)
   393  	if ierr == nil {
   394  		ierr = b.checkInvariants(ctx, conv.GetConvID(), boxed, unboxed)
   395  	}
   396  	if ierr != nil {
   397  		b.Debug(ctx, "failed to unbox message: msgID: %d err: %s", boxed.ServerHeader.MessageID,
   398  			ierr.Error())
   399  		if ierr.IsPermanent() {
   400  			return b.makeErrorMessage(ctx, boxed, ierr), nil
   401  		}
   402  		return chat1.MessageUnboxed{}, ierr
   403  	}
   404  	return chat1.NewMessageUnboxedWithValid(*unboxed), nil
   405  }
   406  
   407  func (b *Boxer) checkInvariants(ctx context.Context, convID chat1.ConversationID, boxed chat1.MessageBoxed, unboxed *chat1.MessageUnboxedValid) types.UnboxingError {
   408  	// Check that the ConversationIDTriple in the signed message header matches
   409  	// the conversation ID we were expecting.
   410  	if !unboxed.ClientHeader.Conv.Derivable(convID) {
   411  		err := fmt.Errorf("conversation ID mismatch: header: %x convID: %s",
   412  			unboxed.ClientHeader.Conv.Hash(), convID)
   413  		return NewPermanentUnboxingError(err)
   414  	}
   415  
   416  	// Check that message type on the client header matches the body
   417  	body := unboxed.MessageBody
   418  	if !body.IsNil() {
   419  		bodyTyp, err := body.MessageType()
   420  		if err != nil {
   421  			return NewPermanentUnboxingError(err)
   422  		}
   423  		if unboxed.ClientHeader.MessageType != bodyTyp {
   424  			err := fmt.Errorf("client header message type does not match body: %v(header) != %v(body)",
   425  				unboxed.ClientHeader.MessageType, bodyTyp)
   426  			return NewPermanentUnboxingError(err)
   427  		}
   428  	}
   429  
   430  	// Make sure the body hash is unique to this message, and then record it.
   431  	// This detects attempts by the server to replay a message. Right now we
   432  	// use a "first writer wins" rule here, though we could also consider a
   433  	// "duplication invalidates both" rule if we wanted to be stricter. Note
   434  	// that this only prevents replays of messages you *know about*. There's
   435  	// currently nothing stopping the server from replaying an ancient message
   436  	// if you're never going to fetch enough history to notice.
   437  	//
   438  	// But...wait...why aren't we using the header hash here? It covers more
   439  	// stuff, and we're using it below, when we check the consistency of
   440  	// messages and prev pointers...
   441  	//
   442  	// The reason we can't use the header hash to prevent replays is that it's
   443  	// a hash *of* a signature, rather than a hash that's *been signed*.
   444  	// Unfortunately, most signature schemes are "malleable" in some way,
   445  	// depending on the implementation. See
   446  	// http://crypto.stackexchange.com/a/14719/21442. If I have the shared
   447  	// encryption key (and recall that in public chats, everyone does), I can
   448  	// decrypt the message, twiddle your signature into another valid signature
   449  	// over the same plaintext, reencrypt the whole thing, and pass it off as a
   450  	// new valid message with a seemingly new signature and therefore a unique
   451  	// header hash. Because the body hash is unique to each message (derived
   452  	// from a random nonce), and because it's *inside* the signature, we use
   453  	// that to detect replays instead.
   454  	replayErr := storage.CheckAndRecordBodyHash(ctx, b.G(), unboxed.BodyHash, boxed.ServerHeader.MessageID, convID)
   455  	if replayErr != nil {
   456  		b.Debug(ctx, "UnboxMessage found a replayed body hash: %s", replayErr)
   457  		return NewPermanentUnboxingError(replayErr)
   458  	}
   459  
   460  	// Make sure the header hash and prev pointers of this message are
   461  	// consistent with every other message we've seen, and record them.
   462  	//
   463  	// The discussion above explains why we have to use the body hash there to
   464  	// prevent replays. But we need to use the header hash here, because it's
   465  	// the only thing that covers the entire message. The goal isn't to prevent
   466  	// the creation of new messages (as it was above), but to prevent an old
   467  	// message from changing.
   468  	prevPtrErr := storage.CheckAndRecordPrevPointer(ctx, b.G(), boxed.ServerHeader.MessageID, convID, unboxed.HeaderHash)
   469  	if prevPtrErr != nil {
   470  		b.Debug(ctx, "UnboxMessage found an inconsistent header hash: %s", prevPtrErr)
   471  		return NewPermanentUnboxingError(prevPtrErr)
   472  	}
   473  	for _, prevPtr := range unboxed.ClientHeader.Prev {
   474  		prevPtrErr := storage.CheckAndRecordPrevPointer(ctx, b.G(), prevPtr.Id, convID, prevPtr.Hash)
   475  		if prevPtrErr != nil {
   476  			b.Debug(ctx, "UnboxMessage found an inconsistent prev pointer: %s", prevPtrErr)
   477  			return NewPermanentUnboxingError(prevPtrErr)
   478  		}
   479  	}
   480  
   481  	return nil
   482  }
   483  
   484  func (b *Boxer) unbox(ctx context.Context, boxed chat1.MessageBoxed,
   485  	conv types.UnboxConversationInfo, encryptionKey types.CryptKey,
   486  	ephemeralKey types.EphemeralCryptKey) (*chat1.MessageUnboxedValid, types.UnboxingError) {
   487  	switch boxed.Version {
   488  	case chat1.MessageBoxedVersion_VNONE, chat1.MessageBoxedVersion_V1:
   489  		res, err := b.unboxV1(ctx, boxed, conv, encryptionKey)
   490  		if err != nil {
   491  			b.Debug(ctx, "error unboxing message version: %v", boxed.Version)
   492  		}
   493  		return res, err
   494  	// V3 is the same as V2, except that it indicates exploding message support.
   495  	// V4 is the same as V3, except if pairwise MACs are included, then the sender signing key is a dummy.
   496  	case chat1.MessageBoxedVersion_V2, chat1.MessageBoxedVersion_V3, chat1.MessageBoxedVersion_V4:
   497  		res, err := b.unboxV2orV3orV4(ctx, boxed, conv, encryptionKey, ephemeralKey)
   498  		if err != nil {
   499  			b.Debug(ctx, "error unboxing message version: %v, %s", boxed.Version, err)
   500  		}
   501  		return res, err
   502  	// NOTE: When adding new versions here, you must also update
   503  	// chat1/extras.go so MessageUnboxedError.ParseableVersion understands the
   504  	// new max version
   505  	default:
   506  		return nil,
   507  			NewPermanentUnboxingError(NewMessageBoxedVersionError(boxed.Version))
   508  	}
   509  }
   510  
   511  func (b *Boxer) headerUnsupported(ctx context.Context, headerVersion chat1.HeaderPlaintextVersion,
   512  	header chat1.HeaderPlaintext) chat1.HeaderPlaintextUnsupported {
   513  	switch headerVersion {
   514  	case chat1.HeaderPlaintextVersion_V2:
   515  		return header.V2()
   516  	case chat1.HeaderPlaintextVersion_V3:
   517  		return header.V3()
   518  	case chat1.HeaderPlaintextVersion_V4:
   519  		return header.V4()
   520  	case chat1.HeaderPlaintextVersion_V5:
   521  		return header.V5()
   522  	case chat1.HeaderPlaintextVersion_V6:
   523  		return header.V6()
   524  	case chat1.HeaderPlaintextVersion_V7:
   525  		return header.V7()
   526  	case chat1.HeaderPlaintextVersion_V8:
   527  		return header.V8()
   528  	case chat1.HeaderPlaintextVersion_V9:
   529  		return header.V9()
   530  	case chat1.HeaderPlaintextVersion_V10:
   531  		return header.V10()
   532  	default:
   533  		b.Debug(ctx, "headerUnsupported: unknown version: %v", headerVersion)
   534  		return chat1.HeaderPlaintextUnsupported{
   535  			Mi: chat1.HeaderPlaintextMetaInfo{
   536  				Crit: true,
   537  			},
   538  		}
   539  	}
   540  }
   541  
   542  func (b *Boxer) bodyUnsupported(ctx context.Context, bodyVersion chat1.BodyPlaintextVersion,
   543  	body chat1.BodyPlaintext) chat1.BodyPlaintextUnsupported {
   544  	switch bodyVersion {
   545  	case chat1.BodyPlaintextVersion_V3:
   546  		return body.V3()
   547  	case chat1.BodyPlaintextVersion_V4:
   548  		return body.V4()
   549  	case chat1.BodyPlaintextVersion_V5:
   550  		return body.V5()
   551  	case chat1.BodyPlaintextVersion_V6:
   552  		return body.V6()
   553  	case chat1.BodyPlaintextVersion_V7:
   554  		return body.V7()
   555  	case chat1.BodyPlaintextVersion_V8:
   556  		return body.V8()
   557  	case chat1.BodyPlaintextVersion_V9:
   558  		return body.V9()
   559  	case chat1.BodyPlaintextVersion_V10:
   560  		return body.V10()
   561  	default:
   562  		b.Debug(ctx, "bodyUnsupported: unknown version: %v", bodyVersion)
   563  		return chat1.BodyPlaintextUnsupported{
   564  			Mi: chat1.BodyPlaintextMetaInfo{
   565  				Crit: true,
   566  			},
   567  		}
   568  	}
   569  }
   570  
   571  // unboxV1 unboxes a chat1.MessageBoxed into a keybase1.Message given
   572  // a keybase1.CryptKey.
   573  func (b *Boxer) unboxV1(ctx context.Context, boxed chat1.MessageBoxed,
   574  	conv types.UnboxConversationInfo, encryptionKey types.CryptKey) (*chat1.MessageUnboxedValid, types.UnboxingError) {
   575  	var err error
   576  	if boxed.ServerHeader == nil {
   577  		return nil, NewPermanentUnboxingError(errors.New("nil ServerHeader in MessageBoxed"))
   578  	}
   579  
   580  	if len(boxed.VerifyKey) != 0 {
   581  		return nil, NewPermanentUnboxingError(errors.New("populated VerifyKey in MBV1"))
   582  	}
   583  
   584  	// compute the header hash
   585  	headerHash := b.hashV1(boxed.HeaderCiphertext.E)
   586  
   587  	// Whether the body is missing (deleted)
   588  	skipBodyVerification := (len(boxed.BodyCiphertext.E) == 0)
   589  
   590  	// TODO We should check whether the body is allowed to have been deleted by checking
   591  	// that there is in fact a message that deleted it.
   592  	// We should fetch that message and check its signed body.
   593  	// That involves fetching a message whose ID is not known here.
   594  
   595  	// decrypt body
   596  	// will remain empty if the body was deleted
   597  	var bodyVersioned chat1.BodyPlaintext
   598  	if !skipBodyVerification {
   599  		packedBody, err := b.open(boxed.BodyCiphertext, libkb.NaclSecretBoxKey(encryptionKey.Material()))
   600  		if err != nil {
   601  			return nil, NewPermanentUnboxingError(err)
   602  		}
   603  		if err := b.unmarshal(packedBody, &bodyVersioned); err != nil {
   604  			return nil, NewPermanentUnboxingError(err)
   605  		}
   606  	}
   607  
   608  	// decrypt header
   609  	packedHeader, err := b.open(boxed.HeaderCiphertext.AsEncrypted(), libkb.NaclSecretBoxKey(encryptionKey.Material()))
   610  	if err != nil {
   611  		return nil, NewPermanentUnboxingError(err)
   612  	}
   613  	var header chat1.HeaderPlaintext
   614  	if err := b.unmarshal(packedHeader, &header); err != nil {
   615  		return nil, NewPermanentUnboxingError(err)
   616  	}
   617  
   618  	// verify the message
   619  	validity, ierr := b.verifyMessageV1(ctx, header, boxed, skipBodyVerification)
   620  	if ierr != nil {
   621  		return nil, ierr
   622  	}
   623  
   624  	// create a chat1.MessageClientHeader from versioned HeaderPlaintext
   625  	var clientHeader chat1.MessageClientHeaderVerified
   626  	headerVersion, err := header.Version()
   627  	if err != nil {
   628  		return nil, NewPermanentUnboxingError(err)
   629  	}
   630  
   631  	rtime := gregor1.ToTime(b.clock.Now())
   632  	if boxed.ServerHeader.Rtime != nil {
   633  		rtime = *boxed.ServerHeader.Rtime
   634  	}
   635  	var headerSignature *chat1.SignatureInfo
   636  	var bodyHash chat1.Hash
   637  	switch headerVersion {
   638  	case chat1.HeaderPlaintextVersion_V1:
   639  		// Verified above in verifyMessageV1
   640  		headerSignature = header.V1().HeaderSignature
   641  		hp := header.V1()
   642  		bodyHash = hp.BodyHash
   643  		clientHeader = chat1.MessageClientHeaderVerified{
   644  			Conv:         hp.Conv,
   645  			TlfName:      hp.TlfName,
   646  			TlfPublic:    hp.TlfPublic,
   647  			MessageType:  hp.MessageType,
   648  			Prev:         hp.Prev,
   649  			Sender:       hp.Sender,
   650  			SenderDevice: hp.SenderDevice,
   651  			// MerkleRoot is not expected to be in any v1 messages. Ignore it.
   652  			MerkleRoot:        nil,
   653  			OutboxID:          hp.OutboxID,
   654  			OutboxInfo:        hp.OutboxInfo,
   655  			KbfsCryptKeysUsed: hp.KbfsCryptKeysUsed,
   656  			Rtime:             rtime,
   657  		}
   658  	// NOTE: When adding new versions here, you must also update
   659  	// chat1/extras.go so MessageUnboxedError.ParseableVersion understands the
   660  	// new max version
   661  	default:
   662  		return nil,
   663  			NewPermanentUnboxingError(NewHeaderVersionError(headerVersion,
   664  				b.headerUnsupported(ctx, headerVersion, header)))
   665  	}
   666  
   667  	// Check for sender match on the inner and outer header.
   668  	if !clientHeader.Sender.Eq(boxed.ClientHeader.Sender) {
   669  		return nil, NewPermanentUnboxingError(fmt.Errorf("sender does not match"))
   670  	}
   671  	if !bytes.Equal(clientHeader.SenderDevice.Bytes(), boxed.ClientHeader.SenderDevice.Bytes()) {
   672  		return nil, NewPermanentUnboxingError(fmt.Errorf("sender device does not match"))
   673  	}
   674  
   675  	// Any of (senderUsername, senderDeviceName, senderDeviceType) could be empty strings because of non-critical failures.
   676  	senderUsername, senderDeviceName, senderDeviceType := b.getSenderInfoLocal(
   677  		ctx, clientHeader.Sender, clientHeader.SenderDevice)
   678  
   679  	// create a chat1.MessageBody from versioned chat1.BodyPlaintext
   680  	// Will remain empty if the body was deleted.
   681  	var body chat1.MessageBody
   682  	if !skipBodyVerification {
   683  		bodyVersion, err := bodyVersioned.Version()
   684  		if err != nil {
   685  			return nil, NewPermanentUnboxingError(err)
   686  		}
   687  		switch bodyVersion {
   688  		case chat1.BodyPlaintextVersion_V1:
   689  			body = bodyVersioned.V1().MessageBody
   690  		// NOTE: When adding new versions here, you must also update
   691  		// chat1/extras.go so MessageUnboxedError.ParseableVersion understands the
   692  		// new max version
   693  		default:
   694  			return nil,
   695  				NewPermanentUnboxingError(NewBodyVersionError(bodyVersion,
   696  					b.bodyUnsupported(ctx, bodyVersion, bodyVersioned)))
   697  		}
   698  	}
   699  
   700  	// Get at mention usernames
   701  	atMentions, atMentionUsernames, maybeRes, chanMention, channelNameMentions :=
   702  		b.getAtMentionInfo(ctx, clientHeader.Conv.Tlfid, clientHeader.Conv.TopicType, conv, body)
   703  
   704  	ierr = b.compareHeadersMBV1(ctx, boxed.ClientHeader, clientHeader)
   705  	if ierr != nil {
   706  		return nil, ierr
   707  	}
   708  
   709  	// create an unboxed message
   710  	return &chat1.MessageUnboxedValid{
   711  		ClientHeader:          clientHeader,
   712  		ServerHeader:          *boxed.ServerHeader,
   713  		MessageBody:           body,
   714  		SenderUsername:        senderUsername,
   715  		SenderDeviceName:      senderDeviceName,
   716  		SenderDeviceType:      senderDeviceType,
   717  		BodyHash:              bodyHash,
   718  		HeaderHash:            headerHash,
   719  		HeaderSignature:       headerSignature,
   720  		VerificationKey:       &validity.validationKey,
   721  		SenderDeviceRevokedAt: validity.senderDeviceRevokedAt,
   722  		AtMentions:            atMentions,
   723  		AtMentionUsernames:    atMentionUsernames,
   724  		ChannelMention:        chanMention,
   725  		ChannelNameMentions:   channelNameMentions,
   726  		MaybeMentions:         maybeRes,
   727  		BotUsername:           b.getBotInfoLocal(ctx, clientHeader.BotUID),
   728  		Emojis:                b.getEmojis(ctx, clientHeader.Conv.TopicType, body),
   729  	}, nil
   730  }
   731  
   732  func (b *Boxer) memberCtime(mctx libkb.MetaContext, conv types.UnboxConversationInfo, tlfID chat1.TLFID, tlfName string) (*keybase1.Time, error) {
   733  	team, err := NewTeamLoader(b.G().ExternalG()).loadTeam(mctx.Ctx(), tlfID, tlfName,
   734  		conv.GetMembersType(), conv.IsPublic(), nil)
   735  	if err != nil {
   736  		return nil, err
   737  	}
   738  	uv, err := mctx.G().GetMeUV(mctx.Ctx())
   739  	if err != nil {
   740  		return nil, err
   741  	}
   742  	return team.MemberCtime(mctx.Ctx(), uv), nil
   743  }
   744  
   745  func (b *Boxer) validatePairwiseMAC(ctx context.Context, boxed chat1.MessageBoxed,
   746  	conv types.UnboxConversationInfo, headerHash chat1.Hash) (senderKey []byte, err error) {
   747  	defer b.Trace(ctx, &err, "validatePairwiseMAC")()
   748  
   749  	// First, find a MAC that matches our receiving device encryption KID.
   750  	ourDeviceKeyNacl, err := b.G().ActiveDevice.NaclEncryptionKey()
   751  	if err != nil {
   752  		return nil, err
   753  	}
   754  	messageMAC, found := boxed.ClientHeader.PairwiseMacs[ourDeviceKeyNacl.GetKID()]
   755  	if !found {
   756  		// This is an error users will actually see when they've just joined a
   757  		// team or added a new device.
   758  		mctx := b.G().MetaContext(ctx)
   759  		memberCtime, err := b.memberCtime(mctx, conv, boxed.ClientHeader.Conv.Tlfid, boxed.ClientHeader.TlfName)
   760  		if err != nil {
   761  			b.Debug(ctx, "Unable to get member ctime: %v", err)
   762  		}
   763  		return nil, NewNotAuthenticatedForThisDeviceError(mctx,
   764  			memberCtime, boxed.ServerHeader.Ctime)
   765  	}
   766  
   767  	// Second, load the device encryption KID for the sender.
   768  	senderUID, err := keybase1.UIDFromSlice(boxed.ClientHeader.Sender)
   769  	if err != nil {
   770  		return nil, err
   771  	}
   772  	senderDeviceID, err := keybase1.DeviceIDFromSlice(boxed.ClientHeader.SenderDevice)
   773  	if err != nil {
   774  		return nil, err
   775  	}
   776  	// Use the loading function that hits the server if-and-only-if we don't
   777  	// have the given deviceID in cache.
   778  	senderUPAK, err := b.G().GetUPAKLoader().LoadUPAKWithDeviceID(ctx, senderUID, senderDeviceID)
   779  	if err != nil {
   780  		return nil, err
   781  	}
   782  	senderEncryptionKID := senderUPAK.Current.FindEncryptionKIDFromDeviceID(senderDeviceID)
   783  	if senderEncryptionKID.IsNil() {
   784  		for _, upk := range senderUPAK.PastIncarnations {
   785  			senderEncryptionKID = upk.FindEncryptionKIDFromDeviceID(senderDeviceID)
   786  			if !senderEncryptionKID.IsNil() {
   787  				break
   788  			}
   789  		}
   790  		if senderEncryptionKID.IsNil() {
   791  			return nil, fmt.Errorf("failed to find encryption key for device %s", senderDeviceID.String())
   792  		}
   793  	}
   794  	senderDeviceDHKeyNacl, err := libkb.ImportDHKeypairFromKID(senderEncryptionKID)
   795  	if err != nil {
   796  		return nil, err
   797  	}
   798  
   799  	// Finally, validate the MAC.
   800  	computedMAC := makeOnePairwiseMAC(*ourDeviceKeyNacl.Private, senderDeviceDHKeyNacl.Public, headerHash)
   801  	if !hmac.Equal(messageMAC, computedMAC) {
   802  		return nil, NewInvalidMACError()
   803  	}
   804  
   805  	return senderEncryptionKID.ToBytes(), nil
   806  }
   807  
   808  func (b *Boxer) ResolveSkippedUnboxed(ctx context.Context, msg chat1.MessageUnboxed) (res chat1.MessageUnboxed, modified bool, err types.UnboxingError) {
   809  	if !msg.IsValid() {
   810  		return msg, false, nil
   811  	}
   812  	if msg.Valid().VerificationKey == nil {
   813  		return msg, false, nil
   814  	}
   815  	// verify sender key
   816  	revokedAt, ierr := b.ValidSenderKey(ctx, msg.Valid().ClientHeader.Sender, *msg.Valid().VerificationKey,
   817  		msg.Valid().ServerHeader.Ctime)
   818  	if ierr != nil {
   819  		if ierr.IsPermanent() {
   820  			return b.makeErrorMessageFromPieces(ctx, ierr, msg.GetMessageID(), msg.GetMessageType(),
   821  				msg.Valid().ServerHeader.Ctime, msg.Valid().ClientHeader.Sender,
   822  				msg.Valid().ClientHeader.SenderDevice,
   823  				msg.Valid().ClientHeader.BotUID, msg.Valid().IsEphemeral(),
   824  				msg.Valid().ExplodedBy(), msg.Valid().Etime()), true, nil
   825  		}
   826  		return msg, false, ierr
   827  	}
   828  	mvalid := msg.Valid()
   829  	mvalid.SenderDeviceRevokedAt = revokedAt
   830  	return chat1.NewMessageUnboxedWithValid(mvalid), revokedAt != nil, nil
   831  }
   832  
   833  func (b *Boxer) ResolveSkippedUnboxeds(ctx context.Context, msgs []chat1.MessageUnboxed) (res []chat1.MessageUnboxed, modifiedMap map[chat1.MessageID]bool, err types.UnboxingError) {
   834  	modifiedMap = make(map[chat1.MessageID]bool)
   835  	for _, msg := range msgs {
   836  		rmsg, modified, err := b.ResolveSkippedUnboxed(ctx, msg)
   837  		if err != nil {
   838  			return res, modifiedMap, err
   839  		}
   840  		modifiedMap[rmsg.GetMessageID()] = modified
   841  		res = append(res, rmsg)
   842  	}
   843  	return res, modifiedMap, nil
   844  }
   845  
   846  func (b *Boxer) unboxV2orV3orV4(ctx context.Context, boxed chat1.MessageBoxed,
   847  	conv types.UnboxConversationInfo, baseEncryptionKey types.CryptKey,
   848  	ephemeralKey types.EphemeralCryptKey) (*chat1.MessageUnboxedValid, types.UnboxingError) {
   849  	if boxed.ServerHeader == nil {
   850  		return nil, NewPermanentUnboxingError(errors.New("nil ServerHeader in MessageBoxed"))
   851  	}
   852  
   853  	// Compute the header hash
   854  	headerHash, ierr := b.makeHeaderHash(boxed.HeaderCiphertext.AsSignEncrypted())
   855  	if ierr != nil {
   856  		return nil, ierr
   857  	}
   858  
   859  	// Regular messages use the same encryption key for the header and for the
   860  	// body. Exploding messages use a derived ephemeral key for the body.
   861  	headerEncryptionKey, err := libkb.DeriveSymmetricKey(
   862  		libkb.NaclSecretBoxKey(baseEncryptionKey.Material()), libkb.EncryptionReasonChatMessage)
   863  	if err != nil {
   864  		return nil, NewPermanentUnboxingError(err)
   865  	}
   866  	bodyEncryptionKey := headerEncryptionKey
   867  	if boxed.IsEphemeral() {
   868  		bodyEncryptionKey, err = libkb.DeriveFromSecret(ephemeralKey.Material(), libkb.DeriveReasonTeamEKExplodingChat)
   869  		if err != nil {
   870  			return nil, NewPermanentUnboxingError(err)
   871  		}
   872  	}
   873  
   874  	// Validate verification key against unverified sender id.
   875  	// Later it is asserted that the claimed and signing sender are the same.
   876  	// ValidSenderKey uses the server-given ctime, but emits senderDeviceRevokedAt as a workaround.
   877  	// See ValidSenderKey for details.
   878  	if boxed.VerifyKey == nil {
   879  		return nil, NewPermanentUnboxingError(libkb.NoKeyError{Msg: "sender key missing"})
   880  	}
   881  
   882  	// This will be the message's signing key in the normal case, and the
   883  	// sending device's encryption key in the pairwise MAC case.
   884  	senderKeyToValidate := boxed.VerifyKey
   885  
   886  	// When pairwise MACs are present (in practice only on exploding messages,
   887  	// but in theory we support them anywhere), we validate the one that's
   888  	// intended for our device, and error out if it's missing or invalid. If it
   889  	// is valid, then we *don't* validate the message signing key. That is,
   890  	// even though signEncryptOpen will check a signature in the end, we no
   891  	// longer care what signing key it's using.
   892  	if len(boxed.ClientHeader.PairwiseMacs) > 0 {
   893  		if boxed.Version != chat1.MessageBoxedVersion_V3 && !bytes.Equal(boxed.VerifyKey, dummySigningKey().GetKID().ToBytes()) {
   894  			return nil, NewPermanentUnboxingError(fmt.Errorf("expected dummy signing key (%s), got %s", dummySigningKey().GetKID(), hex.EncodeToString(boxed.VerifyKey)))
   895  		}
   896  		senderKeyToValidate, err = b.validatePairwiseMAC(ctx, boxed, conv, headerHash)
   897  		if err != nil {
   898  			// Return a transient error if possible
   899  			return nil, b.detectPermanentError(conv, err, boxed.ClientHeader.TlfName)
   900  		}
   901  	} else if bytes.Equal(boxed.VerifyKey, dummySigningKey().GetKID().ToBytes()) {
   902  		// Note that this can happen if the server is stripping MACs for some
   903  		// reason, for example if you're testing against an out-of-date server
   904  		// version.
   905  		return nil, NewPermanentUnboxingError(fmt.Errorf("unexpected dummy signing key with no pairwise MACs present"))
   906  	}
   907  
   908  	// If we validated a pairwise MAC above, then senderKeyToValidate will be
   909  	// the sender's device encryption key, instead of the VerifyKey from the
   910  	// message. In this case, ValidSenderKey is just fetching revocation info for us.
   911  	var senderDeviceRevokedAt *gregor1.Time
   912  	switch globals.CtxUnboxMode(ctx) {
   913  	case types.UnboxModeFull:
   914  		senderDeviceRevokedAt, ierr = b.ValidSenderKey(
   915  			ctx, boxed.ClientHeader.Sender, senderKeyToValidate, boxed.ServerHeader.Ctime)
   916  		if ierr != nil {
   917  			return nil, ierr
   918  		}
   919  	case types.UnboxModeQuick:
   920  		// we skip this check in quick mode, the idea is we will do it later asynchonously so we can
   921  		// deliver messages quicker to the UI.
   922  	}
   923  
   924  	// Open header and verify against VerifyKey
   925  	headerPacked, err := b.signEncryptOpen(boxed.HeaderCiphertext.AsSignEncrypted(), headerEncryptionKey,
   926  		boxed.VerifyKey, kbcrypto.SignaturePrefixChatMBv2)
   927  	if err != nil {
   928  		return nil, NewPermanentUnboxingError(err)
   929  	}
   930  	var headerVersioned chat1.HeaderPlaintext
   931  	err = b.unmarshal(headerPacked, &headerVersioned)
   932  	if err != nil {
   933  		return nil, NewPermanentUnboxingError(err)
   934  	}
   935  
   936  	// Unversion header
   937  	// Also check that the HeaderSignature field from MessageBoxed V1 is nil
   938  	// This object has been signed
   939  	clientHeader, bodyHashSigned, ierr := b.unversionHeaderMBV2(ctx, boxed.ServerHeader, headerVersioned)
   940  	if ierr != nil {
   941  		return nil, ierr
   942  	}
   943  
   944  	// Whether the body is missing (deleted)
   945  	isBodyDeleted := (len(boxed.BodyCiphertext.E) == 0)
   946  
   947  	// TODO We should check whether the body is allowed to have been deleted by checking
   948  	// that there is in fact a message that deleted it.
   949  	// We should fetch that message and check its signed body.
   950  	// That involves fetching a message whose ID is not known here.
   951  
   952  	// Verify body hash
   953  	// The hash of the encrypted body must match that signed into the header.
   954  	if !isBodyDeleted {
   955  		ierr = b.verifyBodyHash(ctx, boxed.BodyCiphertext, bodyHashSigned)
   956  		if ierr != nil {
   957  			return nil, ierr
   958  		}
   959  	}
   960  
   961  	// Compare the signed and unsigned header.
   962  	// Checks that [Sender, SenderDevice] match, and other things.
   963  	ierr = b.compareHeadersMBV2orV3(ctx, boxed.ClientHeader, clientHeader, boxed.Version)
   964  	if ierr != nil {
   965  		return nil, ierr
   966  	}
   967  
   968  	// Decrypt body
   969  	// If the body is deleted, this is left blank.
   970  	var body chat1.MessageBody
   971  	if !isBodyDeleted {
   972  		bodyPacked, err := b.open(boxed.BodyCiphertext, bodyEncryptionKey)
   973  		if err != nil {
   974  			return nil, NewPermanentUnboxingError(err)
   975  		}
   976  		var bodyVersioned chat1.BodyPlaintext
   977  		err = b.unmarshal(bodyPacked, &bodyVersioned)
   978  		if err != nil {
   979  			return nil, NewPermanentUnboxingError(err)
   980  		}
   981  
   982  		// Unversion the body
   983  		body, ierr = b.unversionBody(ctx, bodyVersioned)
   984  		if ierr != nil {
   985  			return nil, ierr
   986  		}
   987  	}
   988  
   989  	// Get sender info
   990  	// Any of (senderUsername, senderDeviceName, senderDeviceType) could be empty strings because of non-critical failures.
   991  	senderUsername, senderDeviceName, senderDeviceType := b.getSenderInfoLocal(
   992  		ctx, clientHeader.Sender, clientHeader.SenderDevice)
   993  
   994  	// Get at mention usernames
   995  	atMentions, atMentionUsernames, maybeRes, chanMention, channelNameMentions :=
   996  		b.getAtMentionInfo(ctx, clientHeader.Conv.Tlfid, clientHeader.Conv.TopicType, conv, body)
   997  
   998  	clientHeader.HasPairwiseMacs = len(boxed.ClientHeader.PairwiseMacs) > 0
   999  
  1000  	// create an unboxed message
  1001  	return &chat1.MessageUnboxedValid{
  1002  		ClientHeader:          clientHeader,
  1003  		ServerHeader:          *boxed.ServerHeader,
  1004  		MessageBody:           body,
  1005  		SenderUsername:        senderUsername,
  1006  		SenderDeviceName:      senderDeviceName,
  1007  		SenderDeviceType:      senderDeviceType,
  1008  		BodyHash:              bodyHashSigned,
  1009  		HeaderHash:            headerHash,
  1010  		HeaderSignature:       nil,
  1011  		VerificationKey:       &senderKeyToValidate,
  1012  		SenderDeviceRevokedAt: senderDeviceRevokedAt,
  1013  		AtMentions:            atMentions,
  1014  		AtMentionUsernames:    atMentionUsernames,
  1015  		ChannelMention:        chanMention,
  1016  		ChannelNameMentions:   channelNameMentions,
  1017  		MaybeMentions:         maybeRes,
  1018  		BotUsername:           b.getBotInfoLocal(ctx, clientHeader.BotUID),
  1019  		Emojis:                b.getEmojis(ctx, clientHeader.Conv.TopicType, body),
  1020  	}, nil
  1021  }
  1022  
  1023  // Unversions a header.
  1024  // Also check that the HeaderSignature field from MessageBoxed V1 is nil.
  1025  // Therefore only for use with MessageBoxed V2.
  1026  // Returns (header, bodyHash, err)
  1027  func (b *Boxer) unversionHeaderMBV2(ctx context.Context, serverHeader *chat1.MessageServerHeader, headerVersioned chat1.HeaderPlaintext) (chat1.MessageClientHeaderVerified, []byte, types.UnboxingError) {
  1028  	if serverHeader == nil {
  1029  		return chat1.MessageClientHeaderVerified{}, nil, NewPermanentUnboxingError(errors.New("nil ServerHeader in MessageBoxed"))
  1030  	}
  1031  
  1032  	rtime := gregor1.ToTime(b.clock.Now())
  1033  	if serverHeader.Rtime != nil {
  1034  		rtime = *serverHeader.Rtime
  1035  	}
  1036  
  1037  	headerVersion, err := headerVersioned.Version()
  1038  	if err != nil {
  1039  		return chat1.MessageClientHeaderVerified{}, nil, NewPermanentUnboxingError(err)
  1040  	}
  1041  	switch headerVersion {
  1042  	case chat1.HeaderPlaintextVersion_V1:
  1043  		hp := headerVersioned.V1()
  1044  		if hp.HeaderSignature != nil {
  1045  			return chat1.MessageClientHeaderVerified{}, nil,
  1046  				NewPermanentUnboxingError(fmt.Errorf("HeaderSignature non-nil in MBV2"))
  1047  		}
  1048  		return chat1.MessageClientHeaderVerified{
  1049  			Conv:              hp.Conv,
  1050  			TlfName:           hp.TlfName,
  1051  			TlfPublic:         hp.TlfPublic,
  1052  			MessageType:       hp.MessageType,
  1053  			Prev:              hp.Prev,
  1054  			Sender:            hp.Sender,
  1055  			SenderDevice:      hp.SenderDevice,
  1056  			MerkleRoot:        hp.MerkleRoot,
  1057  			OutboxID:          hp.OutboxID,
  1058  			OutboxInfo:        hp.OutboxInfo,
  1059  			KbfsCryptKeysUsed: hp.KbfsCryptKeysUsed,
  1060  			EphemeralMetadata: hp.EphemeralMetadata,
  1061  			BotUID:            hp.BotUID,
  1062  			Rtime:             rtime,
  1063  		}, hp.BodyHash, nil
  1064  	// NOTE: When adding new versions here, you must also update
  1065  	// chat1/extras.go so MessageUnboxedError.ParseableVersion understands the
  1066  	// new max version
  1067  	default:
  1068  		return chat1.MessageClientHeaderVerified{}, nil,
  1069  			NewPermanentUnboxingError(NewHeaderVersionError(headerVersion,
  1070  				b.headerUnsupported(ctx, headerVersion, headerVersioned)))
  1071  	}
  1072  }
  1073  
  1074  func (b *Boxer) unversionBody(ctx context.Context, bodyVersioned chat1.BodyPlaintext) (chat1.MessageBody, types.UnboxingError) {
  1075  	bodyVersion, err := bodyVersioned.Version()
  1076  	if err != nil {
  1077  		return chat1.MessageBody{}, NewPermanentUnboxingError(err)
  1078  	}
  1079  	switch bodyVersion {
  1080  	case chat1.BodyPlaintextVersion_V1:
  1081  		return bodyVersioned.V1().MessageBody, nil
  1082  	case chat1.BodyPlaintextVersion_V2:
  1083  		return bodyVersioned.V2().MessageBody, nil
  1084  	// NOTE: When adding new versions here, you must also update
  1085  	// chat1/extras.go so MessageUnboxedError.ParseableVersion understands the
  1086  	// new max version
  1087  	default:
  1088  		return chat1.MessageBody{},
  1089  			NewPermanentUnboxingError(NewBodyVersionError(bodyVersion,
  1090  				b.bodyUnsupported(ctx, bodyVersion, bodyVersioned)))
  1091  	}
  1092  }
  1093  
  1094  func (b *Boxer) verifyBodyHash(ctx context.Context, bodyEncrypted chat1.EncryptedData, bodyHashSigned []byte) types.UnboxingError {
  1095  	bodyHashObserved, err := b.makeBodyHash(bodyEncrypted)
  1096  	if err != nil {
  1097  		return err
  1098  	}
  1099  
  1100  	if len(bodyHashSigned) == 0 {
  1101  		return NewPermanentUnboxingError(BodyHashInvalid{})
  1102  	}
  1103  
  1104  	if !libkb.SecureByteArrayEq(bodyHashObserved, bodyHashSigned) {
  1105  		return NewPermanentUnboxingError(BodyHashInvalid{})
  1106  	}
  1107  	return nil
  1108  }
  1109  
  1110  // Compare the unsigned and signed header for MessageBoxedVersion_V2.
  1111  // The V1 and V2 checks are different methods because they are strict on slightly different things.
  1112  // Confirm that fields in the server-supplied ClientHeader match what
  1113  // we decrypt. It would be preferable if the server didn't supply this data
  1114  // at all (so that we didn't have to worry about anyone trusting it
  1115  // *before* we get to this check, for example), but since we have it we
  1116  // need to check it.
  1117  // The most important check here is that the Sender and SenderDevice match.
  1118  // That is the only thing that gives the verification key used credibility.
  1119  func (b *Boxer) compareHeadersMBV2orV3(ctx context.Context, hServer chat1.MessageClientHeader, hSigned chat1.MessageClientHeaderVerified, version chat1.MessageBoxedVersion) types.UnboxingError {
  1120  	// Conv
  1121  	if !hServer.Conv.Eq(hSigned.Conv) {
  1122  		return NewPermanentUnboxingError(NewHeaderMismatchError("Conv"))
  1123  	}
  1124  
  1125  	// TlfName
  1126  	if hServer.TlfName != hSigned.TlfName {
  1127  		return NewPermanentUnboxingError(NewHeaderMismatchError("TlfName"))
  1128  	}
  1129  
  1130  	// TlfPublic
  1131  	if hServer.TlfPublic != hSigned.TlfPublic {
  1132  		return NewPermanentUnboxingError(NewHeaderMismatchError("TlfPublic"))
  1133  	}
  1134  
  1135  	// MessageType
  1136  	if hServer.MessageType != hSigned.MessageType {
  1137  		return NewPermanentUnboxingError(NewHeaderMismatchError("MessageType"))
  1138  	}
  1139  
  1140  	// Note: Supersedes and Deletes are not checked because they are not
  1141  	//       part of MessageClientHeaderVerified.
  1142  
  1143  	// Prev
  1144  	if len(hServer.Prev) != len(hSigned.Prev) {
  1145  		return NewPermanentUnboxingError(NewHeaderMismatchError("Prev"))
  1146  	}
  1147  	for i, a := range hServer.Prev {
  1148  		b := hSigned.Prev[i]
  1149  		if !a.Eq(b) {
  1150  			return NewPermanentUnboxingError(NewHeaderMismatchError("Prev"))
  1151  		}
  1152  	}
  1153  
  1154  	// Sender
  1155  	// This prevents someone from re-using a header for another sender
  1156  	if !hServer.Sender.Eq(hSigned.Sender) {
  1157  		return NewPermanentUnboxingError(NewHeaderMismatchError("Sender"))
  1158  	}
  1159  
  1160  	// SenderDevice
  1161  	if !bytes.Equal(hServer.SenderDevice.Bytes(), hSigned.SenderDevice.Bytes()) {
  1162  		return NewPermanentUnboxingError(NewHeaderMismatchError("SenderDevice"))
  1163  	}
  1164  
  1165  	// MerkleRoot
  1166  	if !hServer.MerkleRoot.Eq(hSigned.MerkleRoot) {
  1167  		return NewPermanentUnboxingError(NewHeaderMismatchError("MerkleRoot"))
  1168  	}
  1169  	if hSigned.MerkleRoot == nil {
  1170  		return NewPermanentUnboxingError(fmt.Errorf("missing MerkleRoot in chat message"))
  1171  	}
  1172  
  1173  	// OutboxID
  1174  	if !hServer.OutboxID.Eq(hSigned.OutboxID) {
  1175  		return NewPermanentUnboxingError(NewHeaderMismatchError("OutboxID"))
  1176  	}
  1177  
  1178  	// OutboxInfo
  1179  	if !hServer.OutboxInfo.Eq(hSigned.OutboxInfo) {
  1180  		return NewPermanentUnboxingError(NewHeaderMismatchError("OutboxInfo"))
  1181  	}
  1182  
  1183  	// EphemeralMetadata (only present in V3 and greater)
  1184  	if version > chat1.MessageBoxedVersion_V2 && !hServer.EphemeralMetadata.Eq(hSigned.EphemeralMetadata) {
  1185  		return NewPermanentUnboxingError(NewHeaderMismatchError("EphemeralMetadata"))
  1186  	}
  1187  
  1188  	// BotUID (only present in V3 and greater)
  1189  	if version > chat1.MessageBoxedVersion_V2 && !gregor1.UIDPtrEq(hServer.BotUID, hSigned.BotUID) {
  1190  		return NewPermanentUnboxingError(NewHeaderMismatchError("BotUID"))
  1191  	}
  1192  
  1193  	return nil
  1194  }
  1195  
  1196  func (b *Boxer) makeHeaderHash(headerSealed chat1.SignEncryptedData) (chat1.Hash, types.UnboxingError) {
  1197  	buf := bytes.Buffer{}
  1198  	err := binary.Write(&buf, binary.BigEndian, int32(headerSealed.V))
  1199  	if err != nil {
  1200  		return nil, NewPermanentUnboxingError(err)
  1201  	}
  1202  	// Only the ciphertext at the end should be of variable length, otherwise
  1203  	// this hash could be ambiguous.
  1204  	if len(headerSealed.N) != signencrypt.NonceSize {
  1205  		return nil, NewPermanentUnboxingError(fmt.Errorf("unexpected nonce size, %d != %d", len(headerSealed.N), signencrypt.NonceSize))
  1206  	}
  1207  	_, err = buf.Write(headerSealed.N)
  1208  	if err != nil {
  1209  		return nil, NewPermanentUnboxingError(err)
  1210  	}
  1211  	_, err = buf.Write(headerSealed.E)
  1212  	if err != nil {
  1213  		return nil, NewPermanentUnboxingError(err)
  1214  	}
  1215  	return b.hashV1(buf.Bytes()), nil
  1216  }
  1217  
  1218  func (b *Boxer) makeBodyHash(bodyCiphertext chat1.EncryptedData) (chat1.Hash, types.UnboxingError) {
  1219  	buf := bytes.Buffer{}
  1220  	err := binary.Write(&buf, binary.BigEndian, int32(bodyCiphertext.V))
  1221  	if err != nil {
  1222  		return nil, NewPermanentUnboxingError(err)
  1223  	}
  1224  	_, err = buf.Write(bodyCiphertext.N)
  1225  	if err != nil {
  1226  		return nil, NewPermanentUnboxingError(err)
  1227  	}
  1228  	_, err = buf.Write(bodyCiphertext.E)
  1229  	if err != nil {
  1230  		return nil, NewPermanentUnboxingError(err)
  1231  	}
  1232  	return b.hashV1(buf.Bytes()), nil
  1233  }
  1234  
  1235  // unboxThread transforms a chat1.ThreadViewBoxed to a keybase1.ThreadView.
  1236  func (b *Boxer) UnboxThread(ctx context.Context, boxed chat1.ThreadViewBoxed, conv types.UnboxConversationInfo) (thread chat1.ThreadView, err error) {
  1237  
  1238  	thread = chat1.ThreadView{
  1239  		Pagination: boxed.Pagination,
  1240  	}
  1241  
  1242  	if thread.Messages, err = b.UnboxMessages(ctx, boxed.Messages, conv); err != nil {
  1243  		return chat1.ThreadView{}, err
  1244  	}
  1245  
  1246  	return thread, nil
  1247  }
  1248  
  1249  func (b *Boxer) getUsernameAndDevice(ctx context.Context, uid keybase1.UID, deviceID keybase1.DeviceID) (string, string, keybase1.DeviceTypeV2, error) {
  1250  	nun, devName, devType, err := globals.CtxUPAKFinder(ctx, b.G()).LookupUsernameAndDevice(ctx, uid, deviceID)
  1251  	if err != nil {
  1252  		return "", "", keybase1.DeviceTypeV2_NONE, err
  1253  	}
  1254  	return nun.String(), devName, devType, nil
  1255  }
  1256  
  1257  func (b *Boxer) getUsername(ctx context.Context, uid keybase1.UID) (string, error) {
  1258  	name, err := b.G().GetUPAKLoader().LookupUsername(ctx, uid)
  1259  	if err != nil {
  1260  		return "", err
  1261  	}
  1262  	return name.String(), nil
  1263  }
  1264  
  1265  // Any of (senderUsername, senderDeviceName, senderDeviceType) could be empty strings because of non-critical failures.
  1266  // This first tries to username and device info, falling back to just username, falling back to empty strings.
  1267  // The reason for this soft error handling is that a permanent failure would be inappropriate, a transient
  1268  // failure could cause an entire thread not to load, and loading the names of revoked devices may not work this way.
  1269  // This deserves to be reconsidered.
  1270  func (b *Boxer) getSenderInfoLocal(ctx context.Context, uid1 gregor1.UID, deviceID1 gregor1.DeviceID) (senderUsername string, senderDeviceName string, senderDeviceType keybase1.DeviceTypeV2) {
  1271  	if uid1.IsNil() {
  1272  		b.Debug(ctx, "unable to fetch sender and device information: nil UID")
  1273  		return "", "", ""
  1274  	}
  1275  
  1276  	if b.testingGetSenderInfoLocal != nil {
  1277  		b.assertInTest()
  1278  		return b.testingGetSenderInfoLocal(ctx, uid1, deviceID1)
  1279  	}
  1280  
  1281  	uid := keybase1.UID(uid1.String())
  1282  	did := keybase1.DeviceID(deviceID1.String())
  1283  
  1284  	username, deviceName, deviceType, err := b.getUsernameAndDevice(ctx, uid, did)
  1285  	if err != nil {
  1286  		b.Debug(ctx, "unable to fetch sender and device information: UID: %s deviceID: %s",
  1287  			uid1, deviceID1)
  1288  		// try to just get username
  1289  		username, err = b.getUsername(ctx, uid)
  1290  		if err != nil {
  1291  			b.Debug(ctx, "failed to fetch sender username after initial error: err: %s", err.Error())
  1292  		}
  1293  	}
  1294  	return username, deviceName, deviceType
  1295  }
  1296  
  1297  func (b *Boxer) getBotInfoLocal(ctx context.Context, uid *gregor1.UID) string {
  1298  	if uid == nil {
  1299  		return ""
  1300  	}
  1301  	kbuid := keybase1.UID(uid.String())
  1302  	username, err := b.getUsername(ctx, kbuid)
  1303  	if err != nil {
  1304  		b.Debug(ctx, "failed to fetch bot username: %v", err)
  1305  		return ""
  1306  	}
  1307  	return username
  1308  }
  1309  
  1310  func (b *Boxer) getEmojis(ctx context.Context, topicType chat1.TopicType, body chat1.MessageBody) (res []chat1.HarvestedEmoji) {
  1311  	if topicType != chat1.TopicType_CHAT {
  1312  		return nil
  1313  	}
  1314  	emojis := body.GetEmojis()
  1315  	if emojis == nil {
  1316  		return nil
  1317  	}
  1318  	res = make([]chat1.HarvestedEmoji, 0, len(emojis))
  1319  	for _, emoji := range emojis {
  1320  		res = append(res, emoji)
  1321  	}
  1322  	return res
  1323  }
  1324  
  1325  func (b *Boxer) getAtMentionInfo(ctx context.Context, tlfID chat1.TLFID, topicType chat1.TopicType,
  1326  	conv types.UnboxConversationInfo, body chat1.MessageBody) (atMentions []gregor1.UID, atMentionUsernames []string, maybeRes []chat1.MaybeMention, chanMention chat1.ChannelMention, channelNameMentions []chat1.ChannelNameMention) {
  1327  	if topicType != chat1.TopicType_CHAT {
  1328  		// only care about chat conversations for these mentions
  1329  		return atMentions, atMentionUsernames, maybeRes, chanMention, channelNameMentions
  1330  	}
  1331  	chanMention = chat1.ChannelMention_NONE
  1332  	typ, err := body.MessageType()
  1333  	if err != nil {
  1334  		return nil, nil, nil, chanMention, nil
  1335  	}
  1336  	uid := gregor1.UID(b.G().GetEnv().GetUID().ToBytes())
  1337  	tcs := b.G().TeamChannelSource
  1338  	var userAtMentions []chat1.KnownUserMention
  1339  	switch typ {
  1340  	case chat1.MessageType_TEXT:
  1341  		userAtMentions, maybeRes, chanMention = utils.GetTextAtMentionedItems(ctx, b.G(), uid,
  1342  			conv.GetConvID(), body.Text(), nil, &b.DebugLabeler)
  1343  		if conv.GetMembersType() == chat1.ConversationMembersType_TEAM {
  1344  			channelNameMentions = utils.ParseChannelNameMentions(ctx, body.Text().Body, uid, tlfID, tcs)
  1345  		}
  1346  	case chat1.MessageType_ATTACHMENT:
  1347  		userAtMentions, maybeRes, chanMention = utils.ParseAtMentionedItems(ctx, b.G(),
  1348  			body.Attachment().GetTitle(), body.Attachment().UserMentions, nil)
  1349  		if conv.GetMembersType() == chat1.ConversationMembersType_TEAM {
  1350  			channelNameMentions = utils.ParseChannelNameMentions(ctx, body.Attachment().GetTitle(), uid, tlfID, tcs)
  1351  		}
  1352  	case chat1.MessageType_FLIP:
  1353  		if topicType == chat1.TopicType_CHAT {
  1354  			userAtMentions, maybeRes, chanMention = utils.ParseAtMentionedItems(ctx, b.G(), body.Flip().Text,
  1355  				body.Flip().UserMentions, nil)
  1356  		}
  1357  	case chat1.MessageType_EDIT:
  1358  		userAtMentions, maybeRes, chanMention = utils.ParseAtMentionedItems(ctx, b.G(), body.Edit().Body,
  1359  			body.Edit().UserMentions, nil)
  1360  		if conv.GetMembersType() == chat1.ConversationMembersType_TEAM {
  1361  			channelNameMentions = utils.ParseChannelNameMentions(ctx, body.Edit().Body, uid, tlfID, tcs)
  1362  		}
  1363  	case chat1.MessageType_SYSTEM:
  1364  		atMentions, chanMention, channelNameMentions = utils.SystemMessageMentions(ctx, b.G(), uid,
  1365  			body.System())
  1366  	case chat1.MessageType_REACTION:
  1367  		targetUID := body.Reaction().TargetUID
  1368  		if targetUID != nil {
  1369  			atMentions = []gregor1.UID{*targetUID}
  1370  		}
  1371  	default:
  1372  		return nil, nil, nil, chanMention, nil
  1373  	}
  1374  	for _, uat := range userAtMentions {
  1375  		atMentions = append(atMentions, uat.Uid)
  1376  	}
  1377  	usernames := make(map[string]bool)
  1378  	for _, uid := range atMentions {
  1379  		name, err := b.G().GetUPAKLoader().LookupUsername(ctx, keybase1.UID(uid.String()))
  1380  		if err != nil {
  1381  			continue
  1382  		}
  1383  		usernames[name.String()] = true
  1384  	}
  1385  	for u := range usernames {
  1386  		atMentionUsernames = append(atMentionUsernames, u)
  1387  	}
  1388  	return atMentions, atMentionUsernames, maybeRes, chanMention, channelNameMentions
  1389  }
  1390  
  1391  func (b *Boxer) UnboxMessages(ctx context.Context, boxed []chat1.MessageBoxed, conv types.UnboxConversationInfo) (unboxed []chat1.MessageUnboxed, err error) {
  1392  	defer b.Trace(ctx, &err, "UnboxMessages: %s, boxed: %d", conv.GetConvID(), len(boxed))()
  1393  
  1394  	// First stamp all of the messages as received
  1395  	now := gregor1.ToTime(b.clock.Now())
  1396  	for i, msg := range boxed {
  1397  		msg.ServerHeader.Rtime = &now
  1398  		boxed[i] = msg
  1399  	}
  1400  
  1401  	boxCh := make(chan chat1.MessageBoxed)
  1402  	eg, ctx := errgroup.WithContext(ctx)
  1403  	eg.Go(func() error {
  1404  		defer close(boxCh)
  1405  		for _, msg := range boxed {
  1406  			select {
  1407  			case boxCh <- msg:
  1408  			case <-ctx.Done():
  1409  				return ctx.Err()
  1410  			}
  1411  		}
  1412  		return nil
  1413  	})
  1414  	var resLock sync.Mutex
  1415  	numUnboxThreads := 2
  1416  	for i := 0; i < numUnboxThreads; i++ {
  1417  		eg.Go(func() error {
  1418  			for msg := range boxCh {
  1419  				decmsg, err := b.UnboxMessage(ctx, msg, conv, nil)
  1420  				if err != nil {
  1421  					return err
  1422  				}
  1423  				resLock.Lock()
  1424  				unboxed = append(unboxed, decmsg)
  1425  				resLock.Unlock()
  1426  			}
  1427  			return nil
  1428  		})
  1429  	}
  1430  
  1431  	if err := eg.Wait(); err != nil {
  1432  		return unboxed, err
  1433  	}
  1434  	sort.Sort(utils.ByMsgUnboxedMsgID(unboxed))
  1435  	return unboxed, nil
  1436  }
  1437  
  1438  // If no error then MerkleRoot is non-nil.
  1439  func (b *Boxer) latestMerkleRoot(ctx context.Context) (*chat1.MerkleRoot, error) {
  1440  	merkleClient := b.G().GetMerkleClient()
  1441  	if merkleClient == nil {
  1442  		return nil, fmt.Errorf("no MerkleClient available")
  1443  	}
  1444  	mr, err := merkleClient.FetchRootFromServer(b.G().MetaContext(ctx), libkb.ChatBoxerMerkleFreshness)
  1445  	if err != nil {
  1446  		return nil, err
  1447  	}
  1448  	if mr == nil {
  1449  		return nil, fmt.Errorf("No merkle root available for chat header")
  1450  	}
  1451  	merkleRoot := mr.ToInfo()
  1452  	return &merkleRoot, nil
  1453  }
  1454  
  1455  var dummySigningKeyPtr *libkb.NaclSigningKeyPair
  1456  var dummySigningKeyOnce sync.Once
  1457  
  1458  // We use this constant key when we already have pairwiseMACs providing
  1459  // authentication. Creating a keypair requires a curve multiply, so we cache it
  1460  // here, in case someone uses it in a tight loop.
  1461  func dummySigningKey() libkb.NaclSigningKeyPair {
  1462  	dummySigningKeyOnce.Do(func() {
  1463  		var allZeroSecretKey [libkb.NaclSigningKeySecretSize]byte
  1464  		dummyKeypair, err := libkb.MakeNaclSigningKeyPairFromSecret(allZeroSecretKey)
  1465  		if err != nil {
  1466  			panic("errors in key generation should be impossible: " + err.Error())
  1467  		}
  1468  		dummySigningKeyPtr = &dummyKeypair
  1469  	})
  1470  	return *dummySigningKeyPtr
  1471  }
  1472  
  1473  func (b *Boxer) GetEncryptionInfo(ctx context.Context, msg *chat1.MessagePlaintext,
  1474  	membersType chat1.ConversationMembersType, signingKeyPair libkb.NaclSigningKeyPair) (res types.BoxerEncryptionInfo, err error) {
  1475  
  1476  	tlfName := msg.ClientHeader.TlfName
  1477  	version, err := b.GetBoxedVersion(*msg)
  1478  	if err != nil {
  1479  		return res, err
  1480  	}
  1481  	encryptionKey, nameInfo, err := globals.CtxKeyFinder(ctx, b.G()).FindForEncryption(ctx,
  1482  		tlfName, msg.ClientHeader.Conv.Tlfid, membersType,
  1483  		msg.ClientHeader.TlfPublic, msg.ClientHeader.BotUID)
  1484  	if err != nil {
  1485  		return res, NewBoxingCryptKeysError(err)
  1486  	}
  1487  	msg.ClientHeader.TlfName = nameInfo.CanonicalName
  1488  
  1489  	// If the message is exploding, load the ephemeral key, and tweak the
  1490  	// version. Make sure we're not using MessageBoxedVersion_V1, since that
  1491  	// doesn't support exploding messages.
  1492  	var ephemeralKey types.EphemeralCryptKey
  1493  	var pairwiseMACRecipients []keybase1.KID
  1494  	if msg.IsEphemeral() {
  1495  		ephemeralKey, err = globals.CtxKeyFinder(ctx, b.G()).EphemeralKeyForEncryption(
  1496  			b.G().MetaContext(ctx), tlfName, msg.ClientHeader.Conv.Tlfid,
  1497  			membersType, msg.ClientHeader.TlfPublic, msg.ClientHeader.BotUID)
  1498  		if err != nil {
  1499  			return res, NewBoxingCryptKeysError(err)
  1500  		}
  1501  		// V3 is "V2 plus support for exploding messages", and V4 is "V3 plus
  1502  		// support for pairwise MACs". Thus we'll bump all exploding messages
  1503  		// from V2 to V3, and all MAC'd messages from V3 to V4. Eventually we
  1504  		// can deprecate the old versions and remove these branches, once
  1505  		// support is widespread.
  1506  		if version == chat1.MessageBoxedVersion_V2 {
  1507  			version = chat1.MessageBoxedVersion_V3
  1508  		}
  1509  
  1510  		// If this is a team conversation, and the team is small enough, load
  1511  		// the list of pairwise MAC recipients. Note that this is all the
  1512  		// devices in the team, not just those that can read the current
  1513  		// teamEK. There are a few reasons for doing it this way:
  1514  		//   - It's probably better performance. Including all devices
  1515  		//     makes the message bigger and takes more Curve25519 ops, but
  1516  		//     it means we only need to reference the UPAK cache. To get
  1517  		//     the set of devices-that-are-not-stale, we'd need to ask the
  1518  		//     server and pay the cost of a network round trip. We could
  1519  		//     introduce yet another caching layer, but EKs change more
  1520  		//     frequently than devices in general.
  1521  		//   - It leaves us more flexibility in the future. If say we
  1522  		//     introduce a best-effort rekey mechanism for ephmeral keys,
  1523  		//     existing pairwise MACs will Just Work™ after a rekey.
  1524  		shouldPairwiseMAC, recipients, err := globals.CtxKeyFinder(ctx, b.G()).ShouldPairwiseMAC(
  1525  			ctx, tlfName, msg.ClientHeader.Conv.Tlfid, membersType, msg.ClientHeader.TlfPublic)
  1526  		if err != nil {
  1527  			return res, err
  1528  		} else if shouldPairwiseMAC {
  1529  			if len(recipients) == 0 {
  1530  				return res, fmt.Errorf("unexpected empty pairwise recipients list")
  1531  			}
  1532  			pairwiseMACRecipients = recipients
  1533  			// As noted above, bump the version to V4 when we're MAC'ing.
  1534  			if version == chat1.MessageBoxedVersion_V3 {
  1535  				version = chat1.MessageBoxedVersion_V4
  1536  			}
  1537  			// Replace the signing key with a dummy. Using the real signing key
  1538  			// would sabotage the repudiability that pairwise MACs are
  1539  			// providing. We could avoid signing entirely, but this approach
  1540  			// keeps the difference between the two modes very small.
  1541  			signingKeyPair = dummySigningKey()
  1542  		}
  1543  	}
  1544  	return types.BoxerEncryptionInfo{
  1545  		Key:                   encryptionKey,
  1546  		EphemeralKey:          ephemeralKey,
  1547  		PairwiseMACRecipients: pairwiseMACRecipients,
  1548  		Version:               version,
  1549  		SigningKeyPair:        signingKeyPair,
  1550  	}, nil
  1551  }
  1552  
  1553  func (b *Boxer) GetBoxedVersion(msg chat1.MessagePlaintext) (chat1.MessageBoxedVersion, error) {
  1554  	version := CurrentMessageBoxedVersion
  1555  	if b.boxVersionForTesting != nil {
  1556  		version = *b.boxVersionForTesting
  1557  	}
  1558  	if msg.IsEphemeral() && version == chat1.MessageBoxedVersion_V1 {
  1559  		return version, fmt.Errorf("cannot use exploding messages with V1")
  1560  	}
  1561  	return version, nil
  1562  }
  1563  
  1564  // BoxMessage encrypts a keybase1.MessagePlaintext into a chat1.MessageBoxed.  It
  1565  // finds the most recent key for the TLF.
  1566  func (b *Boxer) BoxMessage(ctx context.Context, msg chat1.MessagePlaintext,
  1567  	membersType chat1.ConversationMembersType,
  1568  	signingKeyPair libkb.NaclSigningKeyPair, info *types.BoxerEncryptionInfo) (res chat1.MessageBoxed, err error) {
  1569  	defer b.Trace(ctx, &err, "BoxMessage")()
  1570  	tlfName := msg.ClientHeader.TlfName
  1571  	if len(tlfName) == 0 {
  1572  		return res, NewBoxingError("blank TLF name given", true)
  1573  	}
  1574  	version, err := b.GetBoxedVersion(msg)
  1575  	if err != nil {
  1576  		return res, err
  1577  	}
  1578  	if err = b.attachMerkleRoot(ctx, &msg, version); err != nil {
  1579  		return res, err
  1580  	}
  1581  	if info == nil {
  1582  		info = new(types.BoxerEncryptionInfo)
  1583  		if *info, err = b.GetEncryptionInfo(ctx, &msg, membersType, signingKeyPair); err != nil {
  1584  			return res, err
  1585  		}
  1586  		if len(msg.ClientHeader.TlfName) == 0 {
  1587  			msg := fmt.Sprintf("blank TLF name received: original: %s canonical: %s", tlfName,
  1588  				msg.ClientHeader.TlfName)
  1589  			return res, NewBoxingError(msg, true)
  1590  		}
  1591  	}
  1592  	boxed, err := b.box(ctx, msg, info.Key, info.EphemeralKey, info.SigningKeyPair, info.Version,
  1593  		info.PairwiseMACRecipients)
  1594  	if err != nil {
  1595  		return res, NewBoxingError(err.Error(), true)
  1596  	}
  1597  	return boxed, nil
  1598  }
  1599  
  1600  // Attach a merkle root to the message to send.
  1601  // Modifies msg.
  1602  // For MessageBoxedV1 makes sure there is no MR.
  1603  // For MessageBoxedV2 attaches a MR that is no more out of date than ChatBoxerMerkleFreshness.
  1604  func (b *Boxer) attachMerkleRoot(ctx context.Context, msg *chat1.MessagePlaintext, version chat1.MessageBoxedVersion) error {
  1605  	switch version {
  1606  	case chat1.MessageBoxedVersion_V1:
  1607  		if msg.ClientHeader.MerkleRoot != nil {
  1608  			return NewBoxingError("cannot send v1 message with merkle root", true)
  1609  		}
  1610  	case chat1.MessageBoxedVersion_V2, chat1.MessageBoxedVersion_V3, chat1.MessageBoxedVersion_V4:
  1611  		merkleRoot, err := b.latestMerkleRoot(ctx)
  1612  		if err != nil {
  1613  			return NewBoxingError(err.Error(), false)
  1614  		}
  1615  		msg.ClientHeader.MerkleRoot = merkleRoot
  1616  		if msg.ClientHeader.MerkleRoot == nil {
  1617  			return NewBoxingError("cannot send message without merkle root", false)
  1618  		}
  1619  	default:
  1620  		return fmt.Errorf("attachMerkleRoot unrecognized version: %s", version)
  1621  	}
  1622  	return nil
  1623  }
  1624  
  1625  func (b *Boxer) preBoxCheck(ctx context.Context, messagePlaintext chat1.MessagePlaintext) error {
  1626  	typ, err := messagePlaintext.MessageBody.MessageType()
  1627  	if err != nil {
  1628  		return err
  1629  	}
  1630  	e := func(format string, args ...interface{}) error {
  1631  		return errors.New(fmt.Sprintf("malformed %v message: ", typ) + fmt.Sprintf(format, args...))
  1632  	}
  1633  	switch typ {
  1634  	case chat1.MessageType_DELETEHISTORY:
  1635  		body := messagePlaintext.MessageBody.Deletehistory()
  1636  		dhHeader := messagePlaintext.ClientHeader.DeleteHistory
  1637  		if dhHeader == nil {
  1638  			return e("missing header")
  1639  		}
  1640  		if *dhHeader != body {
  1641  			return e("header-body mismatch")
  1642  		}
  1643  	default:
  1644  		if messagePlaintext.ClientHeader.DeleteHistory != nil {
  1645  			return e("cannot have delete-history header")
  1646  		}
  1647  	}
  1648  
  1649  	return nil
  1650  }
  1651  
  1652  func (b *Boxer) box(ctx context.Context, messagePlaintext chat1.MessagePlaintext, encryptionKey types.CryptKey,
  1653  	ephemeralKey types.EphemeralCryptKey, signingKeyPair libkb.NaclSigningKeyPair, version chat1.MessageBoxedVersion,
  1654  	pairwiseMACRecipients []keybase1.KID) (res chat1.MessageBoxed, err error) {
  1655  	if err = b.preBoxCheck(ctx, messagePlaintext); err != nil {
  1656  		return res, err
  1657  	}
  1658  
  1659  	switch version {
  1660  	case chat1.MessageBoxedVersion_V1:
  1661  		if res, err = b.boxV1(messagePlaintext, encryptionKey, signingKeyPair); err != nil {
  1662  			b.Debug(ctx, "error boxing message version: %v", version)
  1663  		}
  1664  		return res, err
  1665  	// V3 is the same as V2, except that it indicates exploding message
  1666  	// support. V4 is the same as V3, except that it signs with the zero key
  1667  	// when pairwise MACs are included.
  1668  	case chat1.MessageBoxedVersion_V2, chat1.MessageBoxedVersion_V3, chat1.MessageBoxedVersion_V4:
  1669  		if res, err = b.boxV2orV3orV4(ctx, messagePlaintext, encryptionKey, ephemeralKey, signingKeyPair,
  1670  			version, pairwiseMACRecipients); err != nil {
  1671  			b.Debug(ctx, "error boxing message version: %v", version)
  1672  		}
  1673  		return res, err
  1674  	default:
  1675  		return res, fmt.Errorf("invalid version for boxing: %v", version)
  1676  	}
  1677  }
  1678  
  1679  // boxMessageWithKeys encrypts and signs a keybase1.MessagePlaintext into a
  1680  // chat1.MessageBoxed given a keybase1.CryptKey.
  1681  func (b *Boxer) boxV1(messagePlaintext chat1.MessagePlaintext, key types.CryptKey,
  1682  	signingKeyPair libkb.NaclSigningKeyPair) (res chat1.MessageBoxed, err error) {
  1683  
  1684  	body := chat1.BodyPlaintextV1{
  1685  		MessageBody: messagePlaintext.MessageBody,
  1686  	}
  1687  	plaintextBody := chat1.NewBodyPlaintextWithV1(body)
  1688  	encryptedBody, err := b.seal(plaintextBody, libkb.NaclSecretBoxKey(key.Material()))
  1689  	if err != nil {
  1690  		return res, err
  1691  	}
  1692  
  1693  	// create the v1 header, adding hash
  1694  	bodyHash := b.hashV1(encryptedBody.E)
  1695  	if messagePlaintext.ClientHeader.MerkleRoot != nil {
  1696  		return res, fmt.Errorf("cannot box v1 message with merkle root")
  1697  	}
  1698  	header := chat1.HeaderPlaintextV1{
  1699  		Conv:              messagePlaintext.ClientHeader.Conv,
  1700  		TlfName:           messagePlaintext.ClientHeader.TlfName,
  1701  		TlfPublic:         messagePlaintext.ClientHeader.TlfPublic,
  1702  		MessageType:       messagePlaintext.ClientHeader.MessageType,
  1703  		Prev:              messagePlaintext.ClientHeader.Prev,
  1704  		Sender:            messagePlaintext.ClientHeader.Sender,
  1705  		SenderDevice:      messagePlaintext.ClientHeader.SenderDevice,
  1706  		MerkleRoot:        nil, // MerkleRoot cannot be sent in MBv1 messages
  1707  		BodyHash:          bodyHash[:],
  1708  		OutboxInfo:        messagePlaintext.ClientHeader.OutboxInfo,
  1709  		OutboxID:          messagePlaintext.ClientHeader.OutboxID,
  1710  		KbfsCryptKeysUsed: messagePlaintext.ClientHeader.KbfsCryptKeysUsed,
  1711  	}
  1712  
  1713  	// sign the header and insert the signature
  1714  	sig, err := b.signMarshal(header, signingKeyPair, kbcrypto.SignaturePrefixChatMBv1)
  1715  	if err != nil {
  1716  		return res, err
  1717  	}
  1718  	header.HeaderSignature = &sig
  1719  
  1720  	// create a plaintext header
  1721  	plaintextHeader := chat1.NewHeaderPlaintextWithV1(header)
  1722  	encryptedHeader, err := b.seal(plaintextHeader, libkb.NaclSecretBoxKey(key.Material()))
  1723  	if err != nil {
  1724  		return res, err
  1725  	}
  1726  	return chat1.MessageBoxed{
  1727  		Version:          chat1.MessageBoxedVersion_V1,
  1728  		ClientHeader:     messagePlaintext.ClientHeader,
  1729  		BodyCiphertext:   *encryptedBody,
  1730  		HeaderCiphertext: encryptedHeader.AsSealed(),
  1731  		KeyGeneration:    key.Generation(),
  1732  	}, nil
  1733  }
  1734  
  1735  func makeOnePairwiseMAC(private libkb.NaclDHKeyPrivate, public libkb.NaclDHKeyPublic, input []byte) []byte {
  1736  	privKeyBytes := [32]byte(private)
  1737  	pubKeyBytes := [32]byte(public)
  1738  	var rawShared [32]byte
  1739  	box.Precompute(&rawShared, &pubKeyBytes, &privKeyBytes)
  1740  	derivedShared, err := libkb.DeriveFromSecret(rawShared, libkb.DeriveReasonChatPairwiseMAC)
  1741  	if err != nil {
  1742  		panic(err) // key derivation should never fail
  1743  	}
  1744  	hmacState := hmac.New(sha256.New, derivedShared[:])
  1745  	_, _ = hmacState.Write(input)
  1746  	return hmacState.Sum(nil)
  1747  }
  1748  
  1749  func (b *Boxer) makeAllPairwiseMACs(ctx context.Context, headerSealed chat1.SignEncryptedData, recipients []keybase1.KID) (macs map[keybase1.KID][]byte, err error) {
  1750  	defer b.G().CTrace(ctx, fmt.Sprintf("makeAllPairwiseMACs with %d recipients", len(recipients)), &err)()
  1751  
  1752  	pairwiseMACs := map[keybase1.KID][]byte{}
  1753  	headerHash, ierr := b.makeHeaderHash(headerSealed)
  1754  	if ierr != nil {
  1755  		return nil, ierr
  1756  	}
  1757  	deviceKeyNacl, err := b.G().ActiveDevice.NaclEncryptionKey()
  1758  	if err != nil {
  1759  		return nil, err
  1760  	}
  1761  	for _, recipientKID := range recipients {
  1762  		recipientKeyNacl, err := libkb.ImportDHKeypairFromKID(recipientKID)
  1763  		if err != nil {
  1764  			return nil, err
  1765  		}
  1766  		pairwiseMACs[recipientKID] = makeOnePairwiseMAC(*deviceKeyNacl.Private, recipientKeyNacl.Public, headerHash)
  1767  	}
  1768  	return pairwiseMACs, nil
  1769  }
  1770  
  1771  func (b *Boxer) versionBody(ctx context.Context, messagePlaintext chat1.MessagePlaintext) chat1.BodyPlaintext {
  1772  	switch messagePlaintext.ClientHeader.MessageType {
  1773  	case chat1.MessageType_PIN:
  1774  		return chat1.NewBodyPlaintextWithV2(chat1.BodyPlaintextV2{
  1775  			MessageBody: messagePlaintext.MessageBody,
  1776  		})
  1777  	default:
  1778  		return chat1.NewBodyPlaintextWithV1(chat1.BodyPlaintextV1{
  1779  			MessageBody: messagePlaintext.MessageBody,
  1780  		})
  1781  	}
  1782  }
  1783  
  1784  // V3 is just V2 but with exploding messages support. V4 is just V3, but it
  1785  // signs with the zero key when pairwise MACs are included.
  1786  func (b *Boxer) boxV2orV3orV4(ctx context.Context, messagePlaintext chat1.MessagePlaintext,
  1787  	baseEncryptionKey types.CryptKey, ephemeralKey types.EphemeralCryptKey, signingKeyPair libkb.NaclSigningKeyPair,
  1788  	version chat1.MessageBoxedVersion, pairwiseMACRecipients []keybase1.KID) (res chat1.MessageBoxed, err error) {
  1789  
  1790  	if messagePlaintext.ClientHeader.MerkleRoot == nil {
  1791  		return res, NewBoxingError("cannot send message without merkle root", false)
  1792  	}
  1793  	headerEncryptionKey, err := libkb.DeriveSymmetricKey(
  1794  		libkb.NaclSecretBoxKey(baseEncryptionKey.Material()), libkb.EncryptionReasonChatMessage)
  1795  	if err != nil {
  1796  		return res, err
  1797  	}
  1798  
  1799  	// Regular messages use the same encryption key for the header and for the
  1800  	// body. Exploding messages use a derived ephemeral key for the body.
  1801  	bodyEncryptionKey := headerEncryptionKey
  1802  	if messagePlaintext.IsEphemeral() {
  1803  		bodyEncryptionKey, err = libkb.DeriveFromSecret(ephemeralKey.Material(), libkb.DeriveReasonTeamEKExplodingChat)
  1804  		if err != nil {
  1805  			return res, err
  1806  		}
  1807  		// The MessagePlaintext supplied by the caller has a Lifetime, but we
  1808  		// expect the Generation is left uninitialized, and we set it here.
  1809  		messagePlaintext.ClientHeader.EphemeralMetadata.Generation = ephemeralKey.Generation()
  1810  	}
  1811  
  1812  	bodyVersioned := b.versionBody(ctx, messagePlaintext)
  1813  	bodyEncrypted, err := b.seal(bodyVersioned, bodyEncryptionKey)
  1814  	if err != nil {
  1815  		return res, err
  1816  	}
  1817  
  1818  	bodyHash, err := b.makeBodyHash(*bodyEncrypted)
  1819  	if err != nil {
  1820  		return res, err
  1821  	}
  1822  
  1823  	// create the v1 header, adding hash
  1824  	headerVersioned := chat1.NewHeaderPlaintextWithV1(chat1.HeaderPlaintextV1{
  1825  		Conv:              messagePlaintext.ClientHeader.Conv,
  1826  		TlfName:           messagePlaintext.ClientHeader.TlfName,
  1827  		TlfPublic:         messagePlaintext.ClientHeader.TlfPublic,
  1828  		MessageType:       messagePlaintext.ClientHeader.MessageType,
  1829  		Prev:              messagePlaintext.ClientHeader.Prev,
  1830  		Sender:            messagePlaintext.ClientHeader.Sender,
  1831  		SenderDevice:      messagePlaintext.ClientHeader.SenderDevice,
  1832  		BodyHash:          bodyHash,
  1833  		MerkleRoot:        messagePlaintext.ClientHeader.MerkleRoot,
  1834  		OutboxInfo:        messagePlaintext.ClientHeader.OutboxInfo,
  1835  		OutboxID:          messagePlaintext.ClientHeader.OutboxID,
  1836  		KbfsCryptKeysUsed: messagePlaintext.ClientHeader.KbfsCryptKeysUsed,
  1837  		EphemeralMetadata: messagePlaintext.ClientHeader.EphemeralMetadata,
  1838  		BotUID:            messagePlaintext.ClientHeader.BotUID,
  1839  		// In MessageBoxed.V2 HeaderSignature is nil.
  1840  		HeaderSignature: nil,
  1841  	})
  1842  
  1843  	// signencrypt the header
  1844  	headerSealed, err := b.signEncryptMarshal(headerVersioned, headerEncryptionKey,
  1845  		signingKeyPair, kbcrypto.SignaturePrefixChatMBv2)
  1846  	if err != nil {
  1847  		return res, err
  1848  	}
  1849  
  1850  	// Make pairwise MACs if there are any pairwise recipients supplied. Note
  1851  	// that we still sign+encrypt with a signing key above. If we want
  1852  	// repudiability, it's the caller's responsibility to provide a zero
  1853  	// signing key or similar. Signing with a real key and also MAC'ing is
  1854  	// redundant, but it will let us test the MAC code in prod in a backwards
  1855  	// compatible way.
  1856  	if len(pairwiseMACRecipients) > 0 {
  1857  		pairwiseMACs, err := b.makeAllPairwiseMACs(ctx, headerSealed, pairwiseMACRecipients)
  1858  		if err != nil {
  1859  			return res, err
  1860  		}
  1861  		messagePlaintext.ClientHeader.PairwiseMacs = pairwiseMACs
  1862  	}
  1863  
  1864  	// verify
  1865  	verifyKey := signingKeyPair.GetBinaryKID()
  1866  
  1867  	return chat1.MessageBoxed{
  1868  		Version:          version,
  1869  		ServerHeader:     nil,
  1870  		ClientHeader:     messagePlaintext.ClientHeader,
  1871  		HeaderCiphertext: headerSealed.AsSealed(),
  1872  		BodyCiphertext:   *bodyEncrypted,
  1873  		VerifyKey:        verifyKey,
  1874  		KeyGeneration:    baseEncryptionKey.Generation(),
  1875  	}, nil
  1876  }
  1877  
  1878  // seal encrypts data into chat1.EncryptedData.
  1879  func (b *Boxer) seal(data interface{}, key libkb.NaclSecretBoxKey) (*chat1.EncryptedData, error) {
  1880  	s, err := b.marshal(data)
  1881  	if err != nil {
  1882  		return nil, err
  1883  	}
  1884  
  1885  	var nonce [libkb.NaclDHNonceSize]byte
  1886  	if _, err := rand.Read(nonce[:]); err != nil {
  1887  		return nil, err
  1888  	}
  1889  
  1890  	var encKey [libkb.NaclSecretBoxKeySize]byte = key
  1891  
  1892  	sealed := secretbox.Seal(nil, s, &nonce, &encKey)
  1893  	enc := &chat1.EncryptedData{
  1894  		V: 1,
  1895  		E: sealed,
  1896  		N: nonce[:],
  1897  	}
  1898  
  1899  	return enc, nil
  1900  }
  1901  
  1902  // open decrypts chat1.EncryptedData.
  1903  func (b *Boxer) open(data chat1.EncryptedData, key libkb.NaclSecretBoxKey) ([]byte, error) {
  1904  	if len(data.N) != libkb.NaclDHNonceSize {
  1905  		return nil, libkb.DecryptBadNonceError{}
  1906  	}
  1907  	var nonce [libkb.NaclDHNonceSize]byte
  1908  	copy(nonce[:], data.N)
  1909  
  1910  	plain, ok := secretbox.Open(nil, data.E, &nonce, (*[32]byte)(&key))
  1911  	if !ok {
  1912  		return nil, libkb.DecryptOpenError{}
  1913  	}
  1914  	return plain, nil
  1915  }
  1916  
  1917  // signMarshal signs data with a NaclSigningKeyPair, returning a chat1.SignatureInfo.
  1918  // It marshals data before signing.
  1919  func (b *Boxer) signMarshal(data interface{}, kp libkb.NaclSigningKeyPair, prefix kbcrypto.SignaturePrefix) (chat1.SignatureInfo, error) {
  1920  	encoded, err := b.marshal(data)
  1921  	if err != nil {
  1922  		return chat1.SignatureInfo{}, err
  1923  	}
  1924  
  1925  	return b.sign(encoded, kp, prefix)
  1926  }
  1927  
  1928  // signEncryptMarshal signencrypts data given an encryption and signing key, returning a chat1.SignEncryptedData.
  1929  // It marshals data before signing.
  1930  func (b *Boxer) signEncryptMarshal(data interface{}, encryptionKey libkb.NaclSecretBoxKey,
  1931  	signingKeyPair libkb.NaclSigningKeyPair, prefix kbcrypto.SignaturePrefix) (chat1.SignEncryptedData, error) {
  1932  	encoded, err := b.marshal(data)
  1933  	if err != nil {
  1934  		return chat1.SignEncryptedData{}, err
  1935  	}
  1936  
  1937  	return b.signEncrypt(encoded, encryptionKey, signingKeyPair, prefix)
  1938  }
  1939  
  1940  // sign signs msg with a NaclSigningKeyPair, returning a chat1.SignatureInfo.
  1941  func (b *Boxer) sign(msg []byte, kp libkb.NaclSigningKeyPair, prefix kbcrypto.SignaturePrefix) (chat1.SignatureInfo, error) {
  1942  	sig, err := kp.SignV2(msg, prefix)
  1943  	if err != nil {
  1944  		return chat1.SignatureInfo{}, err
  1945  	}
  1946  	sigInfo := chat1.SignatureInfo{
  1947  		V: sig.Version,
  1948  		S: sig.Sig[:],
  1949  		K: sig.Kid,
  1950  	}
  1951  
  1952  	if b.testingSignatureMangle != nil {
  1953  		b.assertInTest()
  1954  		sigInfo.S = b.testingSignatureMangle(sigInfo.S)
  1955  	}
  1956  
  1957  	return sigInfo, nil
  1958  }
  1959  
  1960  // signEncrypt signencrypts msg.
  1961  func (b *Boxer) signEncrypt(msg []byte, encryptionKey libkb.NaclSecretBoxKey,
  1962  	signingKeyPair libkb.NaclSigningKeyPair, prefix kbcrypto.SignaturePrefix) (chat1.SignEncryptedData, error) {
  1963  	if signingKeyPair.Private == nil {
  1964  		return chat1.SignEncryptedData{}, libkb.NoSecretKeyError{}
  1965  	}
  1966  
  1967  	var nonce [signencrypt.NonceSize]byte
  1968  	if _, err := rand.Read(nonce[:]); err != nil {
  1969  		return chat1.SignEncryptedData{}, err
  1970  	}
  1971  
  1972  	var encKey [signencrypt.SecretboxKeySize]byte = encryptionKey
  1973  	var signKey [ed25519.PrivateKeySize]byte = *signingKeyPair.Private
  1974  
  1975  	signEncryptedBytes := signencrypt.SealWhole(
  1976  		msg, &encKey, &signKey, prefix, &nonce)
  1977  	signEncryptedInfo := chat1.SignEncryptedData{
  1978  		V: 1,
  1979  		E: signEncryptedBytes,
  1980  		N: nonce[:],
  1981  	}
  1982  
  1983  	if b.testingSignatureMangle != nil {
  1984  		b.assertInTest()
  1985  		signEncryptedInfo.E = b.testingSignatureMangle(signEncryptedInfo.E)
  1986  	}
  1987  
  1988  	return signEncryptedInfo, nil
  1989  }
  1990  
  1991  // signEncryptOpen opens and verifies chat1.SignEncryptedData.
  1992  func (b *Boxer) signEncryptOpen(data chat1.SignEncryptedData, encryptionKey libkb.NaclSecretBoxKey,
  1993  	verifyKID []byte, prefix kbcrypto.SignaturePrefix) ([]byte, error) {
  1994  	var encKey [signencrypt.SecretboxKeySize]byte = encryptionKey
  1995  
  1996  	verifyKey := kbcrypto.KIDToNaclSigningKeyPublic(verifyKID)
  1997  	if verifyKey == nil {
  1998  		return nil, kbcrypto.BadKeyError{}
  1999  	}
  2000  	var verKey [ed25519.PublicKeySize]byte = *verifyKey
  2001  
  2002  	var nonce [signencrypt.NonceSize]byte
  2003  	if copy(nonce[:], data.N) != signencrypt.NonceSize {
  2004  		return nil, libkb.DecryptBadNonceError{}
  2005  	}
  2006  
  2007  	plain, err := signencrypt.OpenWhole(data.E, &encKey, &verKey, prefix, &nonce)
  2008  	if err != nil {
  2009  		return nil, err
  2010  	}
  2011  	return plain, nil
  2012  }
  2013  
  2014  type verifyMessageRes struct {
  2015  	senderDeviceRevokedAt *gregor1.Time
  2016  	validationKey         []byte
  2017  }
  2018  
  2019  // verifyMessage checks that a message is valid.
  2020  // Only works on MessageBoxedVersion_V1
  2021  func (b *Boxer) verifyMessageV1(ctx context.Context, header chat1.HeaderPlaintext, msg chat1.MessageBoxed, skipBodyVerification bool) (verifyMessageRes, types.UnboxingError) {
  2022  	headerVersion, err := header.Version()
  2023  	if err != nil {
  2024  		return verifyMessageRes{}, NewPermanentUnboxingError(err)
  2025  	}
  2026  
  2027  	switch headerVersion {
  2028  	case chat1.HeaderPlaintextVersion_V1:
  2029  		return b.verifyMessageHeaderV1(ctx, header.V1(), msg, skipBodyVerification)
  2030  	// NOTE: When adding new versions here, you must also update
  2031  	// chat1/extras.go so MessageUnboxedError.ParseableVersion understands the
  2032  	// new max version
  2033  	default:
  2034  		return verifyMessageRes{},
  2035  			NewPermanentUnboxingError(NewHeaderVersionError(headerVersion,
  2036  				b.headerUnsupported(ctx, headerVersion, header)))
  2037  	}
  2038  }
  2039  
  2040  // verifyMessageHeaderV1 checks the body hash, header signature, and signing key validity.
  2041  func (b *Boxer) verifyMessageHeaderV1(ctx context.Context, header chat1.HeaderPlaintextV1, msg chat1.MessageBoxed, skipBodyVerification bool) (verifyMessageRes, types.UnboxingError) {
  2042  	if !skipBodyVerification {
  2043  		// check body hash
  2044  		bh := b.hashV1(msg.BodyCiphertext.E)
  2045  		if !libkb.SecureByteArrayEq(bh[:], header.BodyHash) {
  2046  			return verifyMessageRes{}, NewPermanentUnboxingError(BodyHashInvalid{})
  2047  		}
  2048  	}
  2049  
  2050  	// check key validity
  2051  	// ValidSenderKey uses the server-given ctime, but emits senderDeviceRevokedAt as a workaround.
  2052  	// See ValidSenderKey for details.
  2053  	var revoked *gregor1.Time
  2054  	validationKey := header.HeaderSignature.K
  2055  	switch globals.CtxUnboxMode(ctx) {
  2056  	case types.UnboxModeFull:
  2057  		var ierr types.UnboxingError
  2058  		revoked, ierr = b.ValidSenderKey(ctx, header.Sender, header.HeaderSignature.K, msg.ServerHeader.Ctime)
  2059  		if ierr != nil {
  2060  			return verifyMessageRes{}, ierr
  2061  		}
  2062  	default:
  2063  		// Nothing to do.
  2064  	}
  2065  
  2066  	// check signature
  2067  	hcopy := header
  2068  	hcopy.HeaderSignature = nil
  2069  	hpack, err := b.marshal(hcopy)
  2070  	if err != nil {
  2071  		return verifyMessageRes{}, NewPermanentUnboxingError(err)
  2072  	}
  2073  	if !b.verify(hpack, *header.HeaderSignature, kbcrypto.SignaturePrefixChatMBv1) {
  2074  		return verifyMessageRes{}, NewPermanentUnboxingError(libkb.BadSigError{E: "header signature invalid"})
  2075  	}
  2076  
  2077  	return verifyMessageRes{
  2078  		senderDeviceRevokedAt: revoked,
  2079  		validationKey:         validationKey,
  2080  	}, nil
  2081  }
  2082  
  2083  // verify verifies the signature of data using SignatureInfo.
  2084  func (b *Boxer) verify(data []byte, si chat1.SignatureInfo, prefix kbcrypto.SignaturePrefix) bool {
  2085  	sigInfo := kbcrypto.NaclSigInfo{
  2086  		Version: si.V,
  2087  		Prefix:  prefix,
  2088  		Kid:     si.K,
  2089  		Payload: data,
  2090  	}
  2091  	copy(sigInfo.Sig[:], si.S)
  2092  	_, err := sigInfo.Verify()
  2093  	return (err == nil)
  2094  }
  2095  
  2096  // ValidSenderKey checks that the key was active for sender at ctime.
  2097  // This trusts the server for ctime, so a colluding server could use a revoked key and this check erroneously pass.
  2098  // But (revoked != nil) if the key was ever revoked, so that is irrespective of ctime.
  2099  // Returns (validAtCtime, revoked, err)
  2100  func (b *Boxer) ValidSenderKey(ctx context.Context, sender gregor1.UID, key []byte, ctime gregor1.Time) (revoked *gregor1.Time, unboxErr types.UnboxingError) {
  2101  	var found, deleted bool
  2102  	var revokedAt *keybase1.KeybaseTime
  2103  	validAtCtime := true
  2104  	if b.testingValidSenderKey != nil {
  2105  		b.assertInTest()
  2106  		return b.testingValidSenderKey(ctx, sender, key, ctime)
  2107  	}
  2108  	defer func() {
  2109  		if unboxErr == nil {
  2110  			if !found {
  2111  				unboxErr = NewPermanentUnboxingError(libkb.NoKeyError{Msg: "sender key not found"})
  2112  			} else if !validAtCtime {
  2113  				unboxErr = NewPermanentUnboxingError(libkb.NoKeyError{
  2114  					Msg: "key invalid for sender at message ctime",
  2115  				})
  2116  			}
  2117  		}
  2118  	}()
  2119  
  2120  	kbSender, err := keybase1.UIDFromString(hex.EncodeToString(sender.Bytes()))
  2121  	if err != nil {
  2122  		return nil, NewPermanentUnboxingError(err)
  2123  	}
  2124  	kid := keybase1.KIDFromSlice(key)
  2125  	ctime2 := gregor1.FromTime(ctime)
  2126  
  2127  	cachedUserLoader := globals.CtxUPAKFinder(ctx, b.G())
  2128  	if cachedUserLoader == nil {
  2129  		return nil, NewTransientUnboxingError(fmt.Errorf("no CachedUserLoader available in context"))
  2130  	}
  2131  
  2132  	found, revokedAt, deleted, err = cachedUserLoader.CheckKIDForUID(ctx, kbSender, kid)
  2133  	if err != nil {
  2134  		return nil, NewTransientUnboxingError(err)
  2135  	}
  2136  	if !found {
  2137  		return nil, nil
  2138  	}
  2139  
  2140  	if deleted {
  2141  		b.Debug(ctx, "sender %s key %s was deleted", kbSender, kid)
  2142  		// Set the key as being revoked since the beginning of time, so all messages will get labeled
  2143  		// as suspect
  2144  		zeroTime := gregor1.Time(0)
  2145  		return &zeroTime, nil
  2146  	}
  2147  
  2148  	if revokedAt != nil {
  2149  		if revokedAt.Unix.IsZero() {
  2150  			return nil, NewPermanentUnboxingError(fmt.Errorf("zero clock time on expired key"))
  2151  		}
  2152  		t := b.keybase1KeybaseTimeToTime(*revokedAt)
  2153  		revokedTime := gregor1.ToTime(t)
  2154  		revoked = &revokedTime
  2155  		validAtCtime = t.After(ctime2)
  2156  	}
  2157  	return revoked, nil
  2158  }
  2159  
  2160  func (b *Boxer) keybase1KeybaseTimeToTime(t1 keybase1.KeybaseTime) time.Time {
  2161  	// u is in milliseconds
  2162  	u := int64(t1.Unix)
  2163  	t2 := time.Unix(u/1e3, (u%1e3)*1e6)
  2164  	return t2
  2165  }
  2166  
  2167  func (b *Boxer) marshal(v interface{}) ([]byte, error) {
  2168  	mh := codec.MsgpackHandle{WriteExt: true}
  2169  	var data []byte
  2170  	enc := codec.NewEncoderBytes(&data, &mh)
  2171  	if err := enc.Encode(v); err != nil {
  2172  		return nil, err
  2173  	}
  2174  	return data, nil
  2175  }
  2176  
  2177  func (b *Boxer) unmarshal(data []byte, v interface{}) error {
  2178  	mh := codec.MsgpackHandle{WriteExt: true}
  2179  	dec := codec.NewDecoderBytes(data, &mh)
  2180  	return dec.Decode(&v)
  2181  }
  2182  
  2183  func (b *Boxer) assertInTest() {
  2184  	b.log().Warning("Using TESTING jig. Not suitable for normal use.")
  2185  	if flag.Lookup("test.v") == nil {
  2186  		panic("testing jig installed in normal mode")
  2187  	}
  2188  }
  2189  
  2190  func hashSha256V1(data []byte) chat1.Hash {
  2191  	sum := sha256.Sum256(data)
  2192  	return sum[:]
  2193  }
  2194  
  2195  // See note on compareHeadersMBV2orV3.
  2196  func (b *Boxer) compareHeadersMBV1(ctx context.Context, hServer chat1.MessageClientHeader, hSigned chat1.MessageClientHeaderVerified) types.UnboxingError {
  2197  	// Conv
  2198  	if !hServer.Conv.Eq(hSigned.Conv) {
  2199  		return NewPermanentUnboxingError(NewHeaderMismatchError("Conv"))
  2200  	}
  2201  
  2202  	// TlfName
  2203  	if hServer.TlfName != hSigned.TlfName {
  2204  		return NewPermanentUnboxingError(NewHeaderMismatchError("TlfName"))
  2205  	}
  2206  
  2207  	// TlfPublic
  2208  	if hServer.TlfPublic != hSigned.TlfPublic {
  2209  		return NewPermanentUnboxingError(NewHeaderMismatchError("TlfPublic"))
  2210  	}
  2211  
  2212  	// MessageType
  2213  	if hServer.MessageType != hSigned.MessageType {
  2214  		return NewPermanentUnboxingError(NewHeaderMismatchError("MessageType"))
  2215  	}
  2216  
  2217  	// Note: Supersedes, Deletes, and some other fields are not checked because they are not
  2218  	//       part of MessageClientHeaderVerified.
  2219  
  2220  	// Prev
  2221  	if len(hServer.Prev) != len(hSigned.Prev) {
  2222  		return NewPermanentUnboxingError(NewHeaderMismatchError("Prev"))
  2223  	}
  2224  	for i, a := range hServer.Prev {
  2225  		b := hSigned.Prev[i]
  2226  		if !a.Eq(b) {
  2227  			return NewPermanentUnboxingError(NewHeaderMismatchError("Prev"))
  2228  		}
  2229  	}
  2230  
  2231  	// Sender
  2232  	// This prevents someone from re-using a header for another sender
  2233  	if !hServer.Sender.Eq(hSigned.Sender) {
  2234  		return NewPermanentUnboxingError(NewHeaderMismatchError("Sender"))
  2235  	}
  2236  
  2237  	// SenderDevice
  2238  	if !bytes.Equal(hServer.SenderDevice.Bytes(), hSigned.SenderDevice.Bytes()) {
  2239  		return NewPermanentUnboxingError(NewHeaderMismatchError("SenderDevice"))
  2240  	}
  2241  
  2242  	// _Don't_ check that the MerkleRoot's match.
  2243  	// The signed MerkleRoot should be nil as it was not part of the protocol
  2244  	// when clients were writing MBV1. But we just allow anything here.
  2245  	// There are V1 messages in the wild with hServer.MerkleRoot set but nothing signed.
  2246  
  2247  	// OutboxID, OutboxInfo: Left unchecked as I'm not sure whether these hold in V1 messages.
  2248  
  2249  	return nil
  2250  }
  2251  
  2252  func (b *Boxer) CompareTlfNames(ctx context.Context, tlfName1, tlfName2 string,
  2253  	membersType chat1.ConversationMembersType, tlfPublic bool) (bool, error) {
  2254  	get1 := func(tlfName string, tlfPublic bool) (string, error) {
  2255  		nameInfo, err := CreateNameInfoSource(ctx, b.G(), membersType).LookupID(ctx, tlfName,
  2256  			tlfPublic)
  2257  		if err != nil {
  2258  			return "", err
  2259  		}
  2260  		return nameInfo.CanonicalName, nil
  2261  	}
  2262  
  2263  	c1, err := get1(tlfName1, tlfPublic)
  2264  	if err != nil {
  2265  		return false, err
  2266  	}
  2267  	c2, err := get1(tlfName2, tlfPublic)
  2268  	if err != nil {
  2269  		return false, err
  2270  	}
  2271  	return c1 == c2, nil
  2272  }