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

     1  package chat
     2  
     3  // Copyright 2016 Keybase, Inc. All rights reserved. Use of
     4  // this source code is governed by the included BSD license.
     5  
     6  import (
     7  	"crypto/sha256"
     8  	"encoding/hex"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/stretchr/testify/require"
    13  	"golang.org/x/net/context"
    14  
    15  	"github.com/keybase/client/go/chat/globals"
    16  	"github.com/keybase/client/go/chat/signencrypt"
    17  	"github.com/keybase/client/go/chat/types"
    18  	"github.com/keybase/client/go/engine"
    19  	"github.com/keybase/client/go/ephemeral"
    20  	"github.com/keybase/client/go/externalstest"
    21  	"github.com/keybase/client/go/kbtest"
    22  	"github.com/keybase/client/go/libkb"
    23  	"github.com/keybase/client/go/protocol/chat1"
    24  	"github.com/keybase/client/go/protocol/gregor1"
    25  	"github.com/keybase/client/go/protocol/keybase1"
    26  	"github.com/keybase/go-codec/codec"
    27  	insecureTriplesec "github.com/keybase/go-triplesec-insecure"
    28  )
    29  
    30  var mockTLFID = chat1.TLFID([]byte{0, 1})
    31  
    32  func cryptKey(t *testing.T) *keybase1.CryptKey {
    33  	kp, err := libkb.GenerateNaclDHKeyPair()
    34  	require.NoError(t, err)
    35  
    36  	return &keybase1.CryptKey{
    37  		KeyGeneration: 1,
    38  		Key:           keybase1.Bytes32(*kp.Private),
    39  	}
    40  }
    41  
    42  func textMsg(t *testing.T, text string, mbVersion chat1.MessageBoxedVersion) chat1.MessagePlaintext {
    43  	uid, err := libkb.RandBytes(16)
    44  	require.NoError(t, err)
    45  	uid[15] = keybase1.UID_SUFFIX_2
    46  	return textMsgWithSender(t, text, gregor1.UID(uid), mbVersion)
    47  }
    48  
    49  func textMsgWithSender(t *testing.T, text string, uid gregor1.UID, mbVersion chat1.MessageBoxedVersion) chat1.MessagePlaintext {
    50  	header := chat1.MessageClientHeader{
    51  		Conv: chat1.ConversationIDTriple{
    52  			Tlfid: mockTLFID,
    53  		},
    54  		Sender:      uid,
    55  		MessageType: chat1.MessageType_TEXT,
    56  	}
    57  	switch mbVersion {
    58  	case chat1.MessageBoxedVersion_V1:
    59  		// no-op
    60  	case chat1.MessageBoxedVersion_V2, chat1.MessageBoxedVersion_V3, chat1.MessageBoxedVersion_V4:
    61  		header.MerkleRoot = &chat1.MerkleRoot{
    62  			Seqno: 12,
    63  			Hash:  []byte{123, 117, 0, 99, 99, 79, 223, 37, 180, 168, 111, 107, 210, 227, 128, 35, 47, 158, 221, 210, 151, 242, 182, 199, 50, 29, 236, 93, 106, 149, 133, 221, 156, 216, 167, 79, 91, 28, 9, 196, 107, 173, 61, 248, 123, 97, 101, 34, 7, 15, 30, 80, 246, 162, 198, 12, 20, 19, 130, 151, 45, 2, 130, 170},
    64  		}
    65  	default:
    66  		panic("unrecognized version: " + mbVersion.String())
    67  	}
    68  	return textMsgWithHeader(t, text, header)
    69  }
    70  
    71  func textMsgWithHeader(t *testing.T, text string, header chat1.MessageClientHeader) chat1.MessagePlaintext {
    72  	return chat1.MessagePlaintext{
    73  		ClientHeader: header,
    74  		MessageBody:  chat1.NewMessageBodyWithText(chat1.MessageText{Body: text}),
    75  	}
    76  }
    77  
    78  func setupChatTest(t *testing.T, name string) (*kbtest.ChatTestContext, *Boxer) {
    79  	tc := externalstest.SetupTest(t, name, 2)
    80  
    81  	// use an insecure triplesec in tests
    82  	tc.G.NewTriplesec = func(passphrase []byte, salt []byte) (libkb.Triplesec, error) {
    83  		warner := func() { tc.G.Log.Warning("Installing insecure Triplesec with weak stretch parameters") }
    84  		isProduction := func() bool {
    85  			return tc.G.Env.GetRunMode() == libkb.ProductionRunMode
    86  		}
    87  		return insecureTriplesec.NewCipher(passphrase, salt, libkb.ClientTriplesecVersion, warner, isProduction)
    88  	}
    89  
    90  	ctc := kbtest.ChatTestContext{
    91  		TestContext: tc,
    92  		ChatG: &globals.ChatContext{
    93  			EmojiSource: types.DummyEmojiSource{},
    94  		},
    95  	}
    96  	g := globals.NewContext(ctc.G, ctc.ChatG)
    97  	g.CtxFactory = NewCtxFactory(g)
    98  
    99  	return &ctc, NewBoxer(ctc.Context())
   100  }
   101  
   102  func getSigningKeyPairForTest(t *testing.T, tc *kbtest.ChatTestContext, u *kbtest.FakeUser) libkb.NaclSigningKeyPair {
   103  	var err error
   104  	if u == nil {
   105  		u, err = kbtest.CreateAndSignupFakeUser("unbox", tc.G)
   106  		require.NoError(t, err)
   107  	}
   108  	kp, err := tc.G.Keyrings.GetSecretKeyWithPassphrase(kbtest.NewMetaContextForTest(*tc), u.User, u.Passphrase, nil)
   109  	require.NoError(t, err)
   110  	signKP, ok := kp.(libkb.NaclSigningKeyPair)
   111  	require.True(t, ok)
   112  	return signKP
   113  }
   114  
   115  func getActiveDevicesAndKeys(tc *kbtest.ChatTestContext, u *kbtest.FakeUser) ([]*libkb.Device, []libkb.GenericKey) {
   116  	arg := libkb.NewLoadUserByNameArg(tc.G, u.Username).WithPublicKeyOptional()
   117  	user, err := libkb.LoadUser(arg)
   118  	if err != nil {
   119  		tc.T.Fatal(err)
   120  	}
   121  	sibkeys := user.GetComputedKeyFamily().GetAllActiveSibkeys()
   122  	subkeys := user.GetComputedKeyFamily().GetAllActiveSubkeys()
   123  
   124  	activeDevices := []*libkb.Device{}
   125  	for _, device := range user.GetComputedKeyFamily().GetAllDevices() {
   126  		if device.Status != nil && *device.Status == libkb.DeviceStatusActive {
   127  			activeDevices = append(activeDevices, device.Device)
   128  		}
   129  	}
   130  	return activeDevices, append(sibkeys, subkeys...)
   131  }
   132  
   133  func doRevokeDevice(tc *kbtest.ChatTestContext, u *kbtest.FakeUser, id keybase1.DeviceID, force bool) error {
   134  	revokeEngine := engine.NewRevokeDeviceEngine(tc.G, engine.RevokeDeviceEngineArgs{ID: id, ForceSelf: force})
   135  	uis := libkb.UIs{
   136  		LogUI:    tc.G.UI.GetLogUI(),
   137  		SecretUI: u.NewSecretUI(),
   138  	}
   139  	m := libkb.NewMetaContextTODO(tc.G).WithUIs(uis)
   140  	err := engine.RunEngine2(m, revokeEngine)
   141  	return err
   142  }
   143  
   144  func doWithMBVersions(f func(chat1.MessageBoxedVersion)) {
   145  	f(chat1.MessageBoxedVersion_V1)
   146  	f(chat1.MessageBoxedVersion_V2)
   147  }
   148  
   149  func TestChatMessageBox(t *testing.T) {
   150  	doWithMBVersions(func(mbVersion chat1.MessageBoxedVersion) {
   151  		key := cryptKey(t)
   152  		msg := textMsg(t, "hello", mbVersion)
   153  		tc, boxer := setupChatTest(t, "box")
   154  		defer tc.Cleanup()
   155  		boxed, err := boxer.box(context.TODO(), msg, key, nil, getSigningKeyPairForTest(t, tc, nil), mbVersion, nil)
   156  		require.NoError(t, err)
   157  
   158  		require.Equal(t, mbVersion, boxed.Version)
   159  		if len(boxed.BodyCiphertext.E) == 0 {
   160  			t.Error("after boxMessage, BodyCipherText.E is empty")
   161  		}
   162  	})
   163  }
   164  
   165  var convInfo = newBasicUnboxConversationInfo([]byte{0, 0, 1}, chat1.ConversationMembersType_KBFS, nil,
   166  	keybase1.TLFVisibility_PRIVATE)
   167  
   168  func TestChatMessageUnbox(t *testing.T) {
   169  	doWithMBVersions(func(mbVersion chat1.MessageBoxedVersion) {
   170  		key := cryptKey(t)
   171  		text := "hi"
   172  		tc, boxer := setupChatTest(t, "unbox")
   173  		defer tc.Cleanup()
   174  
   175  		// need a real user
   176  		u, err := kbtest.CreateAndSignupFakeUser("unbox", tc.G)
   177  		require.NoError(t, err)
   178  
   179  		msg := textMsgWithSender(t, text, gregor1.UID(u.User.GetUID().ToBytes()), mbVersion)
   180  		outboxID := chat1.OutboxID{0xdc, 0x74, 0x6, 0x5d, 0xf9, 0x5f, 0x1c, 0x48}
   181  		msg.ClientHeader.OutboxID = &outboxID
   182  
   183  		signKP := getSigningKeyPairForTest(t, tc, u)
   184  
   185  		boxed, err := boxer.box(context.TODO(), msg, key, nil, signKP, mbVersion, nil)
   186  		require.NoError(t, err)
   187  		boxed = remarshalBoxed(t, boxed)
   188  
   189  		if boxed.ClientHeader.OutboxID == msg.ClientHeader.OutboxID {
   190  			t.Fatalf("defective test: %+v   ==   %+v", boxed.ClientHeader.OutboxID, msg.ClientHeader.OutboxID)
   191  		}
   192  
   193  		// need to give it a server header...
   194  		boxed.ServerHeader = &chat1.MessageServerHeader{
   195  			Ctime: gregor1.ToTime(time.Now()),
   196  		}
   197  
   198  		unboxed, err := boxer.unbox(context.TODO(), boxed, convInfo, key, nil)
   199  		require.NoError(t, err)
   200  		body := unboxed.MessageBody
   201  		typ, err := body.MessageType()
   202  		require.NoError(t, err)
   203  		require.Equal(t, typ, chat1.MessageType_TEXT)
   204  		require.Equal(t, body.Text().Body, text)
   205  		require.Nil(t, unboxed.SenderDeviceRevokedAt, "message should not be from revoked device")
   206  		require.NotNil(t, unboxed.BodyHash)
   207  	})
   208  }
   209  
   210  func TestChatMessageUnboxWithPairwiseMacs(t *testing.T) {
   211  	tc, boxer := setupChatTest(t, "unbox")
   212  	defer tc.Cleanup()
   213  
   214  	u, err := kbtest.CreateAndSignupFakeUser("unbox", tc.G)
   215  	require.NoError(t, err)
   216  
   217  	text := "hi"
   218  	msg := textMsgWithSender(t, text, gregor1.UID(u.User.GetUID().ToBytes()), chat1.MessageBoxedVersion_V3)
   219  	outboxID := chat1.OutboxID{0xdc, 0x74, 0x6, 0x5d, 0xf9, 0x5f, 0x1c, 0x48}
   220  	msg.ClientHeader.OutboxID = &outboxID
   221  	// Pairwise MACs rely on the sender's DeviceID in the header.
   222  	deviceID := make([]byte, libkb.DeviceIDLen)
   223  	err = tc.G.ActiveDevice.DeviceID().ToBytes(deviceID)
   224  	require.NoError(t, err)
   225  	msg.ClientHeader.SenderDevice = gregor1.DeviceID(deviceID)
   226  
   227  	signKP := getSigningKeyPairForTest(t, tc, u)
   228  
   229  	encryptionKeypair, err := tc.G.ActiveDevice.NaclEncryptionKey()
   230  	require.NoError(t, err)
   231  	pairwiseMACRecipients := []keybase1.KID{encryptionKeypair.GetKID()}
   232  
   233  	key := cryptKey(t)
   234  	boxed, err := boxer.box(context.TODO(), msg, key, nil, signKP, chat1.MessageBoxedVersion_V3, pairwiseMACRecipients)
   235  	require.NoError(t, err)
   236  	boxed = remarshalBoxed(t, boxed)
   237  	require.NotEqual(t, outboxID, boxed.ClientHeader.OutboxID)
   238  
   239  	// need to give it a server header...
   240  	boxed.ServerHeader = &chat1.MessageServerHeader{
   241  		Ctime: gregor1.ToTime(time.Now()),
   242  	}
   243  
   244  	unboxed, err := boxer.unbox(context.TODO(), boxed, convInfo, key, nil)
   245  	require.NoError(t, err)
   246  
   247  	require.True(t, unboxed.ClientHeader.HasPairwiseMacs)
   248  	body := unboxed.MessageBody
   249  	typ, err := body.MessageType()
   250  	require.NoError(t, err)
   251  
   252  	require.Equal(t, typ, chat1.MessageType_TEXT)
   253  	require.Equal(t, body.Text().Body, text)
   254  
   255  	require.Nil(t, unboxed.SenderDeviceRevokedAt, "message should not be from revoked device")
   256  	require.NotNil(t, unboxed.BodyHash)
   257  }
   258  
   259  func TestChatMessageUnboxWithPairwiseMacsCorrupted(t *testing.T) {
   260  	tc, boxer := setupChatTest(t, "unbox")
   261  	defer tc.Cleanup()
   262  
   263  	u, err := kbtest.CreateAndSignupFakeUser("unbox", tc.G)
   264  	require.NoError(t, err)
   265  
   266  	text := "hi"
   267  	msg := textMsgWithSender(t, text, gregor1.UID(u.User.GetUID().ToBytes()), chat1.MessageBoxedVersion_V3)
   268  	outboxID := chat1.OutboxID{0xdc, 0x74, 0x6, 0x5d, 0xf9, 0x5f, 0x1c, 0x48}
   269  	msg.ClientHeader.OutboxID = &outboxID
   270  	// Pairwise MACs rely on the sender's DeviceID in the header.
   271  	deviceID := make([]byte, libkb.DeviceIDLen)
   272  	err = tc.G.ActiveDevice.DeviceID().ToBytes(deviceID)
   273  	require.NoError(t, err)
   274  
   275  	msg.ClientHeader.SenderDevice = gregor1.DeviceID(deviceID)
   276  	signKP := getSigningKeyPairForTest(t, tc, u)
   277  
   278  	encryptionKeypair, err := tc.G.ActiveDevice.NaclEncryptionKey()
   279  	require.NoError(t, err)
   280  	pairwiseMACRecipients := []keybase1.KID{encryptionKeypair.GetKID()}
   281  
   282  	key := cryptKey(t)
   283  	boxed, err := boxer.box(context.TODO(), msg, key, nil, signKP, chat1.MessageBoxedVersion_V3, pairwiseMACRecipients)
   284  	require.NoError(t, err)
   285  
   286  	boxed = remarshalBoxed(t, boxed)
   287  	require.NotEqual(t, outboxID, boxed.ClientHeader.OutboxID)
   288  
   289  	// need to give it a server header...
   290  	boxed.ServerHeader = &chat1.MessageServerHeader{
   291  		Ctime: gregor1.ToTime(time.Now()),
   292  	}
   293  
   294  	// CORRUPT THE AUTHENTICATOR!!!
   295  	for _, mac := range boxed.ClientHeader.PairwiseMacs {
   296  		mac[0] ^= 1
   297  	}
   298  
   299  	_, err = boxer.unbox(context.TODO(), boxed, convInfo, key, nil)
   300  	require.Error(t, err)
   301  
   302  	// Check that we get the right failure type.
   303  	permErr, ok := err.(PermanentUnboxingError)
   304  	require.True(t, ok)
   305  	_, ok = permErr.Inner().(InvalidMACError)
   306  	require.True(t, ok)
   307  }
   308  
   309  func TestChatMessageUnboxWithPairwiseMacsMissing(t *testing.T) {
   310  	tc, boxer := setupChatTest(t, "unbox")
   311  	defer tc.Cleanup()
   312  
   313  	u, err := kbtest.CreateAndSignupFakeUser("unbox", tc.G)
   314  	require.NoError(t, err)
   315  
   316  	text := "hi"
   317  	msg := textMsgWithSender(t, text, gregor1.UID(u.User.GetUID().ToBytes()), chat1.MessageBoxedVersion_V3)
   318  	outboxID := chat1.OutboxID{0xdc, 0x74, 0x6, 0x5d, 0xf9, 0x5f, 0x1c, 0x48}
   319  	msg.ClientHeader.OutboxID = &outboxID
   320  
   321  	// Pairwise MACs rely on the sender's DeviceID in the header.
   322  	deviceID := make([]byte, libkb.DeviceIDLen)
   323  	err = tc.G.ActiveDevice.DeviceID().ToBytes(deviceID)
   324  	require.NoError(t, err)
   325  	msg.ClientHeader.SenderDevice = gregor1.DeviceID(deviceID)
   326  
   327  	// Put a bogus key in the recipients list, instead of our own.
   328  	bogusKey, err := libkb.GenerateNaclDHKeyPair()
   329  	require.NoError(t, err)
   330  	pairwiseMACRecipients := []keybase1.KID{bogusKey.GetKID()}
   331  
   332  	key := cryptKey(t)
   333  	signKP := getSigningKeyPairForTest(t, tc, u)
   334  	boxed, err := boxer.box(context.TODO(), msg, key, nil, signKP, chat1.MessageBoxedVersion_V3, pairwiseMACRecipients)
   335  	require.NoError(t, err)
   336  	boxed = remarshalBoxed(t, boxed)
   337  	require.NotEqual(t, outboxID, boxed.ClientHeader.OutboxID)
   338  
   339  	// need to give it a server header...
   340  	boxed.ServerHeader = &chat1.MessageServerHeader{
   341  		Ctime: gregor1.ToTime(time.Now()),
   342  	}
   343  
   344  	_, err = boxer.unbox(context.TODO(), boxed, convInfo, key, nil)
   345  	require.Error(t, err)
   346  
   347  	// Check that we get the right failure type.
   348  	permErr, ok := err.(PermanentUnboxingError)
   349  	require.True(t, ok)
   350  	_, ok = permErr.Inner().(NotAuthenticatedForThisDeviceError)
   351  	require.True(t, ok)
   352  }
   353  
   354  func TestChatMessageUnboxWithPairwiseMacsV4DummySigner(t *testing.T) {
   355  	tc, boxer := setupChatTest(t, "unbox")
   356  	defer tc.Cleanup()
   357  
   358  	u, err := kbtest.CreateAndSignupFakeUser("unbox", tc.G)
   359  	require.NoError(t, err)
   360  
   361  	text := "hi"
   362  	msg := textMsgWithSender(t, text, gregor1.UID(u.User.GetUID().ToBytes()), chat1.MessageBoxedVersion_V4)
   363  	outboxID := chat1.OutboxID{0xdc, 0x74, 0x6, 0x5d, 0xf9, 0x5f, 0x1c, 0x48}
   364  	msg.ClientHeader.OutboxID = &outboxID
   365  
   366  	// Pairwise MACs rely on the sender's DeviceID in the header.
   367  	deviceID := make([]byte, libkb.DeviceIDLen)
   368  	err = tc.G.ActiveDevice.DeviceID().ToBytes(deviceID)
   369  	require.NoError(t, err)
   370  	msg.ClientHeader.SenderDevice = gregor1.DeviceID(deviceID)
   371  
   372  	// V4 messages require this keypair.
   373  	encryptionKeypair, err := tc.G.ActiveDevice.NaclEncryptionKey()
   374  	require.NoError(t, err)
   375  	pairwiseMACRecipients := []keybase1.KID{encryptionKeypair.GetKID()}
   376  
   377  	key := cryptKey(t)
   378  	signKP := dummySigningKey()
   379  	boxed, err := boxer.box(context.TODO(), msg, key, nil, signKP, chat1.MessageBoxedVersion_V4, pairwiseMACRecipients)
   380  	require.NoError(t, err)
   381  	boxed = remarshalBoxed(t, boxed)
   382  	require.NotEqual(t, outboxID, boxed.ClientHeader.OutboxID)
   383  
   384  	// need to give it a server header...
   385  	boxed.ServerHeader = &chat1.MessageServerHeader{
   386  		Ctime: gregor1.ToTime(time.Now()),
   387  	}
   388  
   389  	unboxed, err := boxer.unbox(context.TODO(), boxed, convInfo, key, nil)
   390  	require.NoError(t, err)
   391  
   392  	require.True(t, unboxed.ClientHeader.HasPairwiseMacs)
   393  	body := unboxed.MessageBody
   394  	typ, err := body.MessageType()
   395  	require.NoError(t, err)
   396  	require.Equal(t, typ, chat1.MessageType_TEXT)
   397  	require.Equal(t, body.Text().Body, text)
   398  	require.Nil(t, unboxed.SenderDeviceRevokedAt, "message should not be from revoked device")
   399  	require.NotNil(t, unboxed.BodyHash)
   400  }
   401  
   402  func TestChatMessageMissingOutboxID(t *testing.T) {
   403  	// Test with an outbox ID missing.
   404  	mbVersion := chat1.MessageBoxedVersion_V2
   405  	key := cryptKey(t)
   406  	text := "hi"
   407  	tc, boxer := setupChatTest(t, "unbox")
   408  	defer tc.Cleanup()
   409  
   410  	// need a real user
   411  	u, err := kbtest.CreateAndSignupFakeUser("unbox", tc.G)
   412  	require.NoError(t, err)
   413  
   414  	msg := textMsgWithSender(t, text, gregor1.UID(u.User.GetUID().ToBytes()), mbVersion)
   415  	outboxID := chat1.OutboxID{0xdc, 0x74, 0x6, 0x5d, 0xf9, 0x5f, 0x1c, 0x48}
   416  	msg.ClientHeader.OutboxID = &outboxID
   417  
   418  	signKP := getSigningKeyPairForTest(t, tc, u)
   419  
   420  	boxed, err := boxer.box(context.TODO(), msg, key, nil, signKP, mbVersion, nil)
   421  	require.NoError(t, err)
   422  	boxed = remarshalBoxed(t, boxed)
   423  
   424  	if boxed.ClientHeader.OutboxID == msg.ClientHeader.OutboxID {
   425  		t.Fatalf("defective test: %+v   ==   %+v", boxed.ClientHeader.OutboxID, msg.ClientHeader.OutboxID)
   426  	}
   427  	// omit outbox id
   428  	boxed.ClientHeader.OutboxID = nil
   429  
   430  	// need to give it a server header...
   431  	boxed.ServerHeader = &chat1.MessageServerHeader{
   432  		Ctime: gregor1.ToTime(time.Now()),
   433  	}
   434  
   435  	_, uberr := boxer.unbox(context.TODO(), boxed, convInfo, key, nil)
   436  	require.Error(t, uberr)
   437  	ierr, ok := uberr.Inner().(HeaderMismatchError)
   438  	require.True(t, ok, "unexpected error: %T -> %T -> %v", uberr, uberr.Inner(), uberr)
   439  	require.Equal(t, "OutboxID", ierr.Field)
   440  }
   441  
   442  func TestChatMessageInvalidBodyHash(t *testing.T) {
   443  	doWithMBVersions(func(mbVersion chat1.MessageBoxedVersion) {
   444  		key := cryptKey(t)
   445  		text := "hi"
   446  		tc, boxer := setupChatTest(t, "unbox")
   447  		defer tc.Cleanup()
   448  
   449  		// need a real user
   450  		u, err := kbtest.CreateAndSignupFakeUser("unbox", tc.G)
   451  		require.NoError(t, err)
   452  
   453  		msg := textMsgWithSender(t, text, gregor1.UID(u.User.GetUID().ToBytes()), mbVersion)
   454  
   455  		signKP := getSigningKeyPairForTest(t, tc, u)
   456  
   457  		origHashFn := boxer.hashV1
   458  		boxer.hashV1 = func(data []byte) chat1.Hash {
   459  			data = append(data, []byte{1, 2, 3}...)
   460  			sum := sha256.Sum256(data)
   461  			return sum[:]
   462  		}
   463  
   464  		boxed, err := boxer.box(context.TODO(), msg, key, nil, signKP, mbVersion, nil)
   465  		require.NoError(t, err)
   466  
   467  		// need to give it a server header...
   468  		boxed.ServerHeader = &chat1.MessageServerHeader{
   469  			Ctime: gregor1.ToTime(time.Now()),
   470  		}
   471  
   472  		// put original hash fn back
   473  		boxer.hashV1 = origHashFn
   474  
   475  		_, ierr := boxer.unbox(context.TODO(), boxed, convInfo, key, nil)
   476  		_, ok := ierr.Inner().(BodyHashInvalid)
   477  		require.True(t, ok)
   478  	})
   479  }
   480  
   481  func TestChatMessageMismatchMessageType(t *testing.T) {
   482  	doWithMBVersions(func(mbVersion chat1.MessageBoxedVersion) {
   483  		tc, boxer := setupChatTest(t, "unbox")
   484  		defer tc.Cleanup()
   485  
   486  		world := NewChatMockWorld(t, "unbox", 4)
   487  		defer world.Cleanup()
   488  		u := world.GetUsers()[0]
   489  		tc = world.Tcs[u.Username]
   490  		uid := u.User.GetUID().ToBytes()
   491  		tlf := kbtest.NewTlfMock(world)
   492  		ctx := newTestContextWithTlfMock(tc, tlf)
   493  
   494  		ni, err := tlf.LookupID(ctx, u.Username, false)
   495  		require.NoError(t, err)
   496  		header := chat1.MessageClientHeader{
   497  			Conv: chat1.ConversationIDTriple{
   498  				Tlfid: ni.ID,
   499  			},
   500  			Sender:      uid,
   501  			TlfPublic:   false,
   502  			TlfName:     u.Username,
   503  			MessageType: chat1.MessageType_TEXT,
   504  		}
   505  		msg := textMsgWithHeader(t, "MIKE", header)
   506  		msg.MessageBody = chat1.NewMessageBodyWithEdit(chat1.MessageEdit{})
   507  
   508  		signKP := getSigningKeyPairForTest(t, tc, u)
   509  		boxer.boxVersionForTesting = &mbVersion
   510  		boxed, err := boxer.BoxMessage(ctx, msg, chat1.ConversationMembersType_KBFS, signKP, nil)
   511  		require.NoError(t, err)
   512  		boxed.ServerHeader = &chat1.MessageServerHeader{
   513  			Ctime: gregor1.ToTime(time.Now()),
   514  		}
   515  
   516  		convID := header.Conv.ToConversationID([2]byte{0, 0})
   517  		conv := chat1.Conversation{
   518  			Metadata: chat1.ConversationMetadata{
   519  				ConversationID: convID,
   520  			},
   521  		}
   522  		decmsg, err := boxer.UnboxMessage(ctx, boxed, conv, nil)
   523  		require.NoError(t, err)
   524  		require.False(t, decmsg.IsValid())
   525  	})
   526  }
   527  
   528  func TestChatMessageUnboxInvalidBodyHash(t *testing.T) {
   529  	doWithMBVersions(func(mbVersion chat1.MessageBoxedVersion) {
   530  		tc, boxer := setupChatTest(t, "unbox")
   531  		defer tc.Cleanup()
   532  
   533  		world := NewChatMockWorld(t, "unbox", 4)
   534  		defer world.Cleanup()
   535  		u := world.GetUsers()[0]
   536  		tc = world.Tcs[u.Username]
   537  		uid := u.User.GetUID().ToBytes()
   538  		tlf := kbtest.NewTlfMock(world)
   539  		ctx := newTestContextWithTlfMock(tc, tlf)
   540  
   541  		ni, err := tlf.LookupID(ctx, u.Username, false)
   542  		require.NoError(t, err)
   543  		header := chat1.MessageClientHeader{
   544  			Conv: chat1.ConversationIDTriple{
   545  				Tlfid: ni.ID,
   546  			},
   547  			Sender:    uid,
   548  			TlfPublic: false,
   549  			TlfName:   u.Username,
   550  		}
   551  		text := "hi"
   552  		msg := textMsgWithHeader(t, text, header)
   553  
   554  		signKP := getSigningKeyPairForTest(t, tc, u)
   555  
   556  		origHashFn := boxer.hashV1
   557  		boxer.hashV1 = func(data []byte) chat1.Hash {
   558  			data = append(data, []byte{1, 2, 3}...)
   559  			sum := sha256.Sum256(data)
   560  			return sum[:]
   561  		}
   562  
   563  		boxer.boxVersionForTesting = &mbVersion
   564  		boxed, err := boxer.BoxMessage(ctx, msg, chat1.ConversationMembersType_KBFS, signKP, nil)
   565  		require.NoError(t, err)
   566  
   567  		// need to give it a server header...
   568  		boxed.ServerHeader = &chat1.MessageServerHeader{
   569  			Ctime: gregor1.ToTime(time.Now()),
   570  		}
   571  
   572  		// put original hash fn back
   573  		boxer.hashV1 = origHashFn
   574  
   575  		// NOTE: this is hashing a lot of zero values, and it might break when we add more checks
   576  		convID := header.Conv.ToConversationID([2]byte{0, 0})
   577  		conv := chat1.Conversation{
   578  			Metadata: chat1.ConversationMetadata{
   579  				ConversationID: convID,
   580  			},
   581  		}
   582  
   583  		// This should produce a permanent error. So err will be nil, but the decmsg will be state=error.
   584  		decmsg, err := boxer.UnboxMessage(ctx, boxed, conv, nil)
   585  		require.NoError(t, err)
   586  		require.False(t, decmsg.IsValid())
   587  	})
   588  }
   589  
   590  func TestChatMessageUnboxNoCryptKey(t *testing.T) {
   591  	doWithMBVersions(func(mbVersion chat1.MessageBoxedVersion) {
   592  		tc, boxer := setupChatTest(t, "unbox")
   593  		defer tc.Cleanup()
   594  
   595  		world := NewChatMockWorld(t, "unbox", 4)
   596  		defer world.Cleanup()
   597  		u := world.GetUsers()[0]
   598  		uid := u.User.GetUID().ToBytes()
   599  		tc = world.Tcs[u.Username]
   600  		tlf := kbtest.NewTlfMock(world)
   601  		ctx := newTestContextWithTlfMock(tc, tlf)
   602  
   603  		header := chat1.MessageClientHeader{
   604  			Sender:    uid,
   605  			TlfPublic: false,
   606  			TlfName:   u.Username + "M",
   607  		}
   608  		text := "hi"
   609  		msg := textMsgWithHeader(t, text, header)
   610  
   611  		signKP := getSigningKeyPairForTest(t, tc, u)
   612  
   613  		boxer.boxVersionForTesting = &mbVersion
   614  		_, err := boxer.BoxMessage(ctx, msg, chat1.ConversationMembersType_KBFS, signKP, nil)
   615  		require.Error(t, err)
   616  	})
   617  }
   618  
   619  func TestChatMessageInvalidHeaderSig(t *testing.T) {
   620  	doWithMBVersions(func(mbVersion chat1.MessageBoxedVersion) {
   621  		key := cryptKey(t)
   622  		text := "hi"
   623  		tc, boxer := setupChatTest(t, "unbox")
   624  		defer tc.Cleanup()
   625  
   626  		// need a real user
   627  		u, err := kbtest.CreateAndSignupFakeUser("unbox", tc.G)
   628  		require.NoError(t, err)
   629  		msg := textMsgWithSender(t, text, gregor1.UID(u.User.GetUID().ToBytes()), mbVersion)
   630  
   631  		signKP := getSigningKeyPairForTest(t, tc, u)
   632  
   633  		// flip a bit in the sig
   634  		called := false
   635  		boxer.testingSignatureMangle = func(sig []byte) []byte {
   636  			called = true
   637  			sig[4] ^= 0x10
   638  			return sig
   639  		}
   640  
   641  		boxed, err := boxer.box(context.TODO(), msg, key, nil, signKP, mbVersion, nil)
   642  		require.NoError(t, err)
   643  
   644  		require.True(t, called, "mangle must be called")
   645  
   646  		// need to give it a server header...
   647  		boxed.ServerHeader = &chat1.MessageServerHeader{
   648  			Ctime: gregor1.ToTime(time.Now()),
   649  		}
   650  
   651  		_, ierr := boxer.unbox(context.TODO(), boxed, convInfo, key, nil)
   652  		require.NotNil(t, ierr, "must have unbox error")
   653  		switch mbVersion {
   654  		case chat1.MessageBoxedVersion_V1:
   655  			_, ok := ierr.Inner().(libkb.BadSigError)
   656  			require.True(t, ok)
   657  		case chat1.MessageBoxedVersion_V2:
   658  			_, ok := ierr.Inner().(signencrypt.Error)
   659  			require.True(t, ok)
   660  		default:
   661  			require.Fail(t, "unexpected version: %v", mbVersion)
   662  		}
   663  	})
   664  }
   665  
   666  func TestChatMessageInvalidSenderKey(t *testing.T) {
   667  	doWithMBVersions(func(mbVersion chat1.MessageBoxedVersion) {
   668  		key := cryptKey(t)
   669  		text := "hi"
   670  		tc, boxer := setupChatTest(t, "unbox")
   671  		defer tc.Cleanup()
   672  
   673  		// need a real user
   674  		u, err := kbtest.CreateAndSignupFakeUser("unbox", tc.G)
   675  		require.NoError(t, err)
   676  		msg := textMsgWithSender(t, text, gregor1.UID(u.User.GetUID().ToBytes()), mbVersion)
   677  
   678  		// use a random signing key, not one of u's keys
   679  		signKP, err := libkb.GenerateNaclSigningKeyPair()
   680  		require.NoError(t, err)
   681  
   682  		boxed, err := boxer.box(context.TODO(), msg, key, nil, signKP, mbVersion, nil)
   683  		require.NoError(t, err)
   684  
   685  		boxed.ServerHeader = &chat1.MessageServerHeader{
   686  			Ctime: gregor1.ToTime(time.Now()),
   687  		}
   688  
   689  		_, ierr := boxer.unbox(context.TODO(), boxed, convInfo, key, nil)
   690  		if ierr != nil {
   691  			_, ok := ierr.Inner().(libkb.NoKeyError)
   692  			require.True(t, ok)
   693  		}
   694  	})
   695  }
   696  
   697  // Sent with a revoked sender key after revocation
   698  func TestChatMessageRevokedKeyThenSent(t *testing.T) {
   699  	doWithMBVersions(func(mbVersion chat1.MessageBoxedVersion) {
   700  		key := cryptKey(t)
   701  		text := "hi"
   702  		tc, boxer := setupChatTest(t, "unbox")
   703  		defer tc.Cleanup()
   704  
   705  		// need a real user
   706  		u, err := kbtest.CreateAndSignupFakeUserPaper("unbox", tc.G)
   707  		require.NoError(t, err)
   708  		t.Logf("using username:%+v uid: %+v", u.Username, u.User.GetUID())
   709  
   710  		// pick a device
   711  		devices, _ := getActiveDevicesAndKeys(tc, u)
   712  		var thisDevice *libkb.Device
   713  		for _, device := range devices {
   714  			if device.Type != keybase1.DeviceTypeV2_PAPER {
   715  				thisDevice = device
   716  			}
   717  		}
   718  		require.NotNil(t, thisDevice, "thisDevice should be non-nil")
   719  
   720  		// Find the key
   721  		signingKey, err := engine.GetMySecretKey(context.TODO(), tc.G, libkb.DeviceSigningKeyType, "some chat or something test")
   722  		require.NoError(t, err, "get device signing key")
   723  		signKP, ok := signingKey.(libkb.NaclSigningKeyPair)
   724  		require.Equal(t, true, ok, "signing key must be nacl")
   725  		t.Logf("found signing kp: %+v", signKP.GetKID())
   726  
   727  		// Revoke the key
   728  		t.Logf("revoking device id:%+v", thisDevice.ID)
   729  		err = doRevokeDevice(tc, u, thisDevice.ID, true)
   730  		require.NoError(t, err, "revoke device")
   731  
   732  		// Sleep for a second because revocation timestamps are only second-resolution.
   733  		time.Sleep(1 * time.Second)
   734  
   735  		// Reset the cache
   736  		// tc.G.CachedUserLoader = libkb.NewCachedUserLoader(tc.G, libkb.CachedUserTimeout)
   737  
   738  		// Sign a message using a key of u's that has been revoked
   739  		t.Logf("signing message")
   740  		msg := textMsgWithSender(t, text, gregor1.UID(u.User.GetUID().ToBytes()), mbVersion)
   741  		boxed, err := boxer.box(context.TODO(), msg, key, nil, signKP, mbVersion, nil)
   742  		require.NoError(t, err)
   743  
   744  		boxed.ServerHeader = &chat1.MessageServerHeader{
   745  			Ctime: gregor1.ToTime(time.Now()),
   746  		}
   747  
   748  		// The message should not unbox
   749  		_, ierr := boxer.unbox(context.TODO(), boxed, convInfo, key, nil)
   750  		require.NotNil(t, ierr, "unboxing must err because key was revoked before send")
   751  		require.IsType(t, libkb.NoKeyError{}, ierr.Inner(), "unexpected error for revoked sender key: %v", ierr)
   752  
   753  		// Test key validity
   754  		revoked, err := boxer.ValidSenderKey(context.TODO(), gregor1.UID(u.User.GetUID().ToBytes()), signKP.GetBinaryKID(), boxed.ServerHeader.Ctime)
   755  		require.Error(t, err, "ValidSenderKey")
   756  		require.IsType(t, PermanentUnboxingError{}, err)
   757  		require.Equal(t, "key invalid for sender at message ctime",
   758  			err.(PermanentUnboxingError).Inner().(libkb.NoKeyError).Msg)
   759  		require.NotNil(t, revoked)
   760  
   761  		// test out quick mode and resolve
   762  		ctx := globals.CtxModifyUnboxMode(context.TODO(), types.UnboxModeQuick)
   763  		unboxed, ierr := boxer.unbox(ctx, boxed, convInfo, key, nil)
   764  		require.NoError(t, ierr)
   765  		require.NotNil(t, unboxed)
   766  		resolved, modified, err := boxer.ResolveSkippedUnboxed(ctx,
   767  			chat1.NewMessageUnboxedWithValid(*unboxed))
   768  		require.NoError(t, err)
   769  		require.True(t, resolved.IsError())
   770  		require.True(t, modified)
   771  	})
   772  }
   773  
   774  // Sent with a revoked sender key before revocation
   775  func TestChatMessageSentThenRevokedSenderKey(t *testing.T) {
   776  	doWithMBVersions(func(mbVersion chat1.MessageBoxedVersion) {
   777  		key := cryptKey(t)
   778  		text := "hi"
   779  		tc, boxer := setupChatTest(t, "unbox")
   780  		defer tc.Cleanup()
   781  
   782  		// need a real user
   783  		u, err := kbtest.CreateAndSignupFakeUserPaper("unbox", tc.G)
   784  		require.NoError(t, err)
   785  		t.Logf("using username:%+v uid: %+v", u.Username, u.User.GetUID())
   786  
   787  		// pick a device
   788  		devices, _ := getActiveDevicesAndKeys(tc, u)
   789  		var thisDevice *libkb.Device
   790  		for _, device := range devices {
   791  			if device.Type != keybase1.DeviceTypeV2_PAPER {
   792  				thisDevice = device
   793  			}
   794  		}
   795  		require.NotNil(t, thisDevice, "thisDevice should be non-nil")
   796  
   797  		// Find the key
   798  		signingKey, err := engine.GetMySecretKey(context.TODO(), tc.G, libkb.DeviceSigningKeyType, "some chat or something test")
   799  		require.NoError(t, err, "get device signing key")
   800  		signKP, ok := signingKey.(libkb.NaclSigningKeyPair)
   801  		require.Equal(t, true, ok, "signing key must be nacl")
   802  		t.Logf("found signing kp: %+v", signKP.GetKID())
   803  
   804  		// Sign a message using a key of u's that has not yet been revoked
   805  		t.Logf("signing message")
   806  		msg := textMsgWithSender(t, text, gregor1.UID(u.User.GetUID().ToBytes()), mbVersion)
   807  		boxed, err := boxer.box(context.TODO(), msg, key, nil, signKP, mbVersion, nil)
   808  		require.NoError(t, err)
   809  
   810  		boxed.ServerHeader = &chat1.MessageServerHeader{
   811  			Ctime: gregor1.ToTime(time.Now()),
   812  		}
   813  
   814  		// Sleep for a second because revocation timestamps are only second-resolution.
   815  		time.Sleep(1 * time.Second)
   816  
   817  		// Revoke the key
   818  		t.Logf("revoking device id:%+v", thisDevice.ID)
   819  		err = doRevokeDevice(tc, u, thisDevice.ID, true)
   820  		require.NoError(t, err, "revoke device")
   821  
   822  		// The message should unbox but with senderDeviceRevokedAt set
   823  		unboxed, ierr := boxer.unbox(context.TODO(), boxed, convInfo, key, nil)
   824  		require.Nil(t, ierr, "unboxing err")
   825  		require.NotNil(t, unboxed.SenderDeviceRevokedAt, "message should be noticed as signed by revoked key")
   826  
   827  		// Test key validity
   828  		revoked, err := boxer.ValidSenderKey(context.TODO(), gregor1.UID(u.User.GetUID().ToBytes()), signKP.GetBinaryKID(), boxed.ServerHeader.Ctime)
   829  		require.NoError(t, err, "ValidSenderKey")
   830  		require.NotNil(t, revoked)
   831  
   832  		// test quick mode and resolver
   833  		ctx := globals.CtxModifyUnboxMode(context.TODO(), types.UnboxModeQuick)
   834  		unboxed, ierr = boxer.unbox(ctx, boxed, convInfo, key, nil)
   835  		require.NoError(t, ierr)
   836  		require.Nil(t, unboxed.SenderDeviceRevokedAt)
   837  		resolved, modified, err := boxer.ResolveSkippedUnboxed(ctx,
   838  			chat1.NewMessageUnboxedWithValid(*unboxed))
   839  		require.NoError(t, err)
   840  		require.True(t, resolved.IsValid())
   841  		require.NotNil(t, resolved.Valid().SenderDeviceRevokedAt)
   842  		require.True(t, modified)
   843  	})
   844  }
   845  
   846  func TestChatMessagePublic(t *testing.T) {
   847  	doWithMBVersions(func(mbVersion chat1.MessageBoxedVersion) {
   848  		text := "hi"
   849  		tc, boxer := setupChatTest(t, "unbox")
   850  		defer tc.Cleanup()
   851  
   852  		world := NewChatMockWorld(t, "unbox", 4)
   853  		defer world.Cleanup()
   854  		u := world.GetUsers()[0]
   855  		uid := u.User.GetUID().ToBytes()
   856  		tc = world.Tcs[u.Username]
   857  		tlf := kbtest.NewTlfMock(world)
   858  		ctx := newTestContextWithTlfMock(tc, tlf)
   859  
   860  		ni, err := tlf.LookupID(ctx, u.Username, true)
   861  		require.NoError(t, err)
   862  		header := chat1.MessageClientHeader{
   863  			Conv: chat1.ConversationIDTriple{
   864  				Tlfid: ni.ID,
   865  			},
   866  			Sender:      uid,
   867  			TlfPublic:   true,
   868  			TlfName:     u.Username,
   869  			MessageType: chat1.MessageType_TEXT,
   870  		}
   871  		msg := textMsgWithHeader(t, text, header)
   872  
   873  		signKP := getSigningKeyPairForTest(t, tc, u)
   874  
   875  		boxer.boxVersionForTesting = &mbVersion
   876  		boxed, err := boxer.BoxMessage(ctx, msg, chat1.ConversationMembersType_KBFS, signKP, nil)
   877  		require.NoError(t, err)
   878  
   879  		_ = boxed
   880  
   881  		// need to give it a server header...
   882  		boxed.ServerHeader = &chat1.MessageServerHeader{
   883  			Ctime: gregor1.ToTime(time.Now()),
   884  		}
   885  
   886  		// NOTE: this is hashing a lot of zero values, and it might break when we add more checks
   887  		convID := header.Conv.ToConversationID([2]byte{0, 0})
   888  		conv := chat1.Conversation{
   889  			Metadata: chat1.ConversationMetadata{
   890  				ConversationID: convID,
   891  				Visibility:     keybase1.TLFVisibility_PUBLIC,
   892  			},
   893  		}
   894  
   895  		decmsg, err := boxer.UnboxMessage(ctx, boxed, conv, nil)
   896  		require.NoError(t, err)
   897  		require.True(t, decmsg.IsValid())
   898  
   899  		body := decmsg.Valid().MessageBody
   900  		typ, err := body.MessageType()
   901  		require.NoError(t, err)
   902  		require.Equal(t, typ, chat1.MessageType_TEXT)
   903  		require.Equal(t, body.Text().Body, text)
   904  	})
   905  }
   906  
   907  // Test that you cannot unbox a message whose client header sender does not match.
   908  // This prevents one kind of misattribution within a tlf.
   909  // Device mismatches are probably tolerated.
   910  func TestChatMessageSenderMismatch(t *testing.T) {
   911  
   912  	var allUIDs []keybase1.UID
   913  
   914  	doWithMBVersions(func(mbVersion chat1.MessageBoxedVersion) {
   915  		key := cryptKey(t)
   916  		text := "hi"
   917  		tc, boxer := setupChatTest(t, "unbox")
   918  		defer tc.Cleanup()
   919  
   920  		u2, err := kbtest.CreateAndSignupFakeUser("chat", tc.G)
   921  		require.NoError(t, err)
   922  		allUIDs = append(allUIDs, u2.GetUID())
   923  
   924  		u, err := kbtest.CreateAndSignupFakeUser("unbox", tc.G)
   925  		require.NoError(t, err)
   926  		allUIDs = append(allUIDs, u.GetUID())
   927  
   928  		msg := textMsgWithSender(t, text, gregor1.UID(u.User.GetUID().ToBytes()), mbVersion)
   929  
   930  		signKP := getSigningKeyPairForTest(t, tc, u)
   931  
   932  		boxed, err := boxer.box(context.TODO(), msg, key, nil, signKP, mbVersion, nil)
   933  		require.NoError(t, err)
   934  
   935  		// need to give it a server header...
   936  		boxed.ServerHeader = &chat1.MessageServerHeader{
   937  			Ctime: gregor1.ToTime(time.Now()),
   938  		}
   939  
   940  		// Set the outer sender to something else
   941  		boxed.ClientHeader.Sender = gregor1.UID(u2.User.GetUID().ToBytes())
   942  
   943  		_, err = boxer.unbox(context.TODO(), boxed, convInfo, key, nil)
   944  		require.Error(t, err, "should not unbox with sender mismatch")
   945  	})
   946  
   947  	tc := libkb.SetupTest(t, "batch", 0)
   948  	defer tc.Cleanup()
   949  
   950  	// Just check that batch fetching of device encryption keys work.
   951  	// Use the 4 users we've collected in this test.
   952  	var uvs []keybase1.UserVersion
   953  	for _, uid := range allUIDs {
   954  		uvs = append(uvs, keybase1.UserVersion{Uid: uid})
   955  	}
   956  
   957  	keys, err := batchLoadEncryptionKIDs(context.TODO(), tc.G, uvs)
   958  	require.NoError(t, err, "no error")
   959  	require.Equal(t, len(keys), len(uvs), "one key per user")
   960  }
   961  
   962  // Test a message that deletes
   963  func TestChatMessageDeletes(t *testing.T) {
   964  	doWithMBVersions(func(mbVersion chat1.MessageBoxedVersion) {
   965  		key := cryptKey(t)
   966  		text := "hi"
   967  		tc, boxer := setupChatTest(t, "unbox")
   968  		defer tc.Cleanup()
   969  
   970  		// need a real user
   971  		u, err := kbtest.CreateAndSignupFakeUser("unbox", tc.G)
   972  		require.NoError(t, err)
   973  
   974  		msg := textMsgWithSender(t, text, gregor1.UID(u.User.GetUID().ToBytes()), mbVersion)
   975  		deleteIDs := []chat1.MessageID{5, 6, 7}
   976  		msg.MessageBody = chat1.NewMessageBodyWithDelete(chat1.MessageDelete{MessageIDs: deleteIDs})
   977  		msg.ClientHeader.Supersedes = deleteIDs[0]
   978  		msg.ClientHeader.Deletes = deleteIDs
   979  
   980  		signKP := getSigningKeyPairForTest(t, tc, u)
   981  
   982  		boxed, err := boxer.box(context.TODO(), msg, key, nil, signKP, mbVersion, nil)
   983  		require.NoError(t, err)
   984  
   985  		// need to give it a server header...
   986  		boxed.ServerHeader = &chat1.MessageServerHeader{
   987  			Ctime:        gregor1.ToTime(time.Now()),
   988  			SupersededBy: 4,
   989  		}
   990  
   991  		unboxed, err := boxer.unbox(context.TODO(), boxed, convInfo, key, nil)
   992  		require.NoError(t, err)
   993  		body := unboxed.MessageBody
   994  		typ, err := body.MessageType()
   995  		require.NoError(t, err)
   996  		require.Equal(t, typ, chat1.MessageType_DELETE)
   997  		require.Nil(t, unboxed.SenderDeviceRevokedAt, "message should not be from revoked device")
   998  	})
   999  }
  1000  
  1001  // Test a message with a deleted body
  1002  func TestChatMessageDeleted(t *testing.T) {
  1003  	doWithMBVersions(func(mbVersion chat1.MessageBoxedVersion) {
  1004  		for _, supersededBy := range []chat1.MessageID{0, 4} {
  1005  			key := cryptKey(t)
  1006  			text := "hi"
  1007  			tc, boxer := setupChatTest(t, "unbox")
  1008  			defer tc.Cleanup()
  1009  
  1010  			// need a real user
  1011  			u, err := kbtest.CreateAndSignupFakeUser("unbox", tc.G)
  1012  			require.NoError(t, err)
  1013  
  1014  			msg := textMsgWithSender(t, text, gregor1.UID(u.User.GetUID().ToBytes()), mbVersion)
  1015  
  1016  			signKP := getSigningKeyPairForTest(t, tc, u)
  1017  
  1018  			boxed, err := boxer.box(context.TODO(), msg, key, nil, signKP, mbVersion, nil)
  1019  			require.NoError(t, err)
  1020  
  1021  			// need to give it a server header...
  1022  			boxed.ServerHeader = &chat1.MessageServerHeader{
  1023  				Ctime:        gregor1.ToTime(time.Now()),
  1024  				SupersededBy: supersededBy,
  1025  			}
  1026  
  1027  			// Delete the body
  1028  			boxed.BodyCiphertext = chat1.EncryptedData{}
  1029  
  1030  			unboxed, err := boxer.unbox(context.TODO(), boxed, convInfo, key, nil)
  1031  			require.NoError(t, err, "deleted message should still unbox")
  1032  			body := unboxed.MessageBody
  1033  			typ, err := body.MessageType()
  1034  			require.NoError(t, err)
  1035  			require.Equal(t, typ, chat1.MessageType_NONE)
  1036  			require.Nil(t, unboxed.SenderDeviceRevokedAt, "message should not be from revoked device")
  1037  		}
  1038  	})
  1039  }
  1040  
  1041  // Test a message with a deleted body but missing a supersededby header
  1042  func TestChatMessageDeletedNotSuperseded(t *testing.T) {
  1043  	doWithMBVersions(func(mbVersion chat1.MessageBoxedVersion) {
  1044  		key := cryptKey(t)
  1045  		text := "hi"
  1046  		tc, boxer := setupChatTest(t, "unbox")
  1047  		defer tc.Cleanup()
  1048  
  1049  		// need a real user
  1050  		u, err := kbtest.CreateAndSignupFakeUser("unbox", tc.G)
  1051  		require.NoError(t, err)
  1052  
  1053  		msg := textMsgWithSender(t, text, gregor1.UID(u.User.GetUID().ToBytes()), mbVersion)
  1054  
  1055  		signKP := getSigningKeyPairForTest(t, tc, u)
  1056  
  1057  		boxed, err := boxer.box(context.TODO(), msg, key, nil, signKP, mbVersion, nil)
  1058  		require.NoError(t, err)
  1059  
  1060  		// need to give it a server header...
  1061  		boxed.ServerHeader = &chat1.MessageServerHeader{
  1062  			Ctime: gregor1.ToTime(time.Now()),
  1063  		}
  1064  
  1065  		// Delete the body
  1066  		boxed.BodyCiphertext.E = []byte{}
  1067  
  1068  		unboxed, err := boxer.unbox(context.TODO(), boxed, convInfo, key, nil)
  1069  		// The server was not setting supersededBy on EDITs when their TEXT got deleted.
  1070  		// So there are existing messages which have no supersededBy but are legitimately deleted.
  1071  		// Tracked in CORE-4662
  1072  		require.NoError(t, err, "suprisingly, should be able to unbox with deleted but no supersededby")
  1073  		require.Equal(t, chat1.MessageBody{}, unboxed.MessageBody)
  1074  	})
  1075  }
  1076  
  1077  // Test a DeleteHistory message.
  1078  func TestChatMessageDeleteHistory(t *testing.T) {
  1079  	mbVersion := chat1.MessageBoxedVersion_V2
  1080  	key := cryptKey(t)
  1081  	text := "hi"
  1082  	tc, boxer := setupChatTest(t, "unbox")
  1083  	defer tc.Cleanup()
  1084  
  1085  	// need a real user
  1086  	u, err := kbtest.CreateAndSignupFakeUser("unbox", tc.G)
  1087  	require.NoError(t, err)
  1088  
  1089  	msg := textMsgWithSender(t, text, gregor1.UID(u.User.GetUID().ToBytes()), mbVersion)
  1090  	mdh := chat1.MessageDeleteHistory{Upto: chat1.MessageID(4)}
  1091  	msg.MessageBody = chat1.NewMessageBodyWithDeletehistory(mdh)
  1092  	msg.ClientHeader.DeleteHistory = &mdh
  1093  
  1094  	signKP := getSigningKeyPairForTest(t, tc, u)
  1095  
  1096  	boxed, err := boxer.box(context.TODO(), msg, key, nil, signKP, mbVersion, nil)
  1097  	require.NoError(t, err)
  1098  
  1099  	// need to give it a server header...
  1100  	boxed.ServerHeader = &chat1.MessageServerHeader{
  1101  		Ctime:        gregor1.ToTime(time.Now()),
  1102  		SupersededBy: 4,
  1103  	}
  1104  
  1105  	unboxed, err := boxer.unbox(context.TODO(), boxed, convInfo, key, nil)
  1106  	require.NoError(t, err)
  1107  	body := unboxed.MessageBody
  1108  	typ, err := body.MessageType()
  1109  	require.NoError(t, err)
  1110  	require.Equal(t, typ, chat1.MessageType_DELETEHISTORY)
  1111  	require.Nil(t, unboxed.SenderDeviceRevokedAt, "message should not be from revoked device")
  1112  	require.Equal(t, mdh, unboxed.MessageBody.Deletehistory())
  1113  }
  1114  
  1115  func TestV1Message1(t *testing.T) {
  1116  	// Unbox a canned V1 message from before V2 was thought up.
  1117  
  1118  	tc, boxer := setupChatTest(t, "unbox")
  1119  	defer tc.Cleanup()
  1120  
  1121  	canned := getCannedMessage(t, "alice25-bob25-1")
  1122  	boxed := canned.AsBoxed(t)
  1123  	modifyBoxerForTesting(t, boxer, &canned)
  1124  
  1125  	// Check some features before unboxing
  1126  	require.Equal(t, chat1.MessageBoxedVersion_VNONE, boxed.Version)
  1127  	require.Equal(t, "1fb5a5e7585a43aba1a59520939e2420", boxed.ClientHeader.Conv.TopicID.String())
  1128  	require.Equal(t, canned.encryptionKeyGeneration, boxed.KeyGeneration)
  1129  
  1130  	// Unbox
  1131  	unboxed, err := boxer.unbox(context.TODO(), canned.AsBoxed(t), convInfo,
  1132  		canned.EncryptionKey(t), nil)
  1133  	require.NoError(t, err)
  1134  
  1135  	// Check some features of the unboxed
  1136  	// ClientHeader
  1137  	require.Equal(t, "d1fec1a2287b473206e282f4d4f30116", unboxed.ClientHeader.Conv.Tlfid.String())
  1138  	require.Equal(t, "1fb5a5e7585a43aba1a59520939e2420", unboxed.ClientHeader.Conv.TopicID.String())
  1139  	require.Equal(t, chat1.TopicType_CHAT, unboxed.ClientHeader.Conv.TopicType)
  1140  	require.Equal(t, "alice25,bob25", unboxed.ClientHeader.TlfName)
  1141  	require.Equal(t, false, unboxed.ClientHeader.TlfPublic)
  1142  	require.Equal(t, chat1.MessageType_TLFNAME, unboxed.ClientHeader.MessageType)
  1143  	require.Nil(t, unboxed.ClientHeader.Prev)
  1144  	require.Equal(t, canned.SenderUID(t), unboxed.ClientHeader.Sender)
  1145  	require.Equal(t, canned.SenderDeviceID(t), unboxed.ClientHeader.SenderDevice)
  1146  	// CORE-4540: Uncomment this assertion when MerkleRoot is added to MessageClientHeaderVerified
  1147  	require.Nil(t, unboxed.ClientHeader.MerkleRoot)
  1148  	require.Nil(t, unboxed.ClientHeader.OutboxID)
  1149  	require.Nil(t, unboxed.ClientHeader.OutboxInfo)
  1150  
  1151  	// ServerHeader
  1152  	require.Equal(t, chat1.MessageID(1), unboxed.ServerHeader.MessageID)
  1153  	require.Equal(t, chat1.MessageID(0), unboxed.ServerHeader.SupersededBy)
  1154  
  1155  	// MessageBody
  1156  	mTyp, err2 := unboxed.MessageBody.MessageType()
  1157  	require.NoError(t, err2)
  1158  	// MessageBody has no TLFNAME variant, so the type comes out as 0.
  1159  	require.Equal(t, chat1.MessageType(0), mTyp)
  1160  
  1161  	// Other attributes of unboxed
  1162  	require.Equal(t, canned.senderUsername, unboxed.SenderUsername)
  1163  	require.Equal(t, canned.senderDeviceName, unboxed.SenderDeviceName)
  1164  	require.Equal(t, canned.senderDeviceType, unboxed.SenderDeviceType)
  1165  	require.Equal(t, canned.headerHash, unboxed.HeaderHash.String())
  1166  	require.NotNil(t, unboxed.HeaderSignature)
  1167  	require.Equal(t, canned.VerifyKey(t), unboxed.HeaderSignature.K)
  1168  	require.NotNil(t, unboxed.VerificationKey)
  1169  	require.Nil(t, unboxed.SenderDeviceRevokedAt)
  1170  }
  1171  
  1172  func TestV1Message2(t *testing.T) {
  1173  	// Unbox a canned V1 message from before V2 was thought up.
  1174  
  1175  	tc, boxer := setupChatTest(t, "unbox")
  1176  	defer tc.Cleanup()
  1177  
  1178  	canned := getCannedMessage(t, "alice25-bob25-2")
  1179  	boxed := canned.AsBoxed(t)
  1180  	modifyBoxerForTesting(t, boxer, &canned)
  1181  
  1182  	// Check some features before unboxing
  1183  	require.Equal(t, chat1.MessageBoxedVersion_VNONE, boxed.Version)
  1184  	require.Equal(t, "1fb5a5e7585a43aba1a59520939e2420", boxed.ClientHeader.Conv.TopicID.String())
  1185  	require.Equal(t, canned.encryptionKeyGeneration, boxed.KeyGeneration)
  1186  
  1187  	// Unbox
  1188  	unboxed, err := boxer.unbox(context.TODO(), canned.AsBoxed(t), convInfo,
  1189  		canned.EncryptionKey(t), nil)
  1190  	require.NoError(t, err)
  1191  
  1192  	// Check some features of the unboxed
  1193  	// ClientHeader
  1194  	require.Equal(t, "d1fec1a2287b473206e282f4d4f30116", unboxed.ClientHeader.Conv.Tlfid.String())
  1195  	require.Equal(t, "1fb5a5e7585a43aba1a59520939e2420", unboxed.ClientHeader.Conv.TopicID.String())
  1196  	require.Equal(t, chat1.TopicType_CHAT, unboxed.ClientHeader.Conv.TopicType)
  1197  	require.Equal(t, "alice25,bob25", unboxed.ClientHeader.TlfName)
  1198  	require.Equal(t, false, unboxed.ClientHeader.TlfPublic)
  1199  	require.Equal(t, chat1.MessageType_TEXT, unboxed.ClientHeader.MessageType)
  1200  	expectedPrevs := []chat1.MessagePreviousPointer{{Id: 0x1, Hash: chat1.Hash{0xc9, 0x6e, 0x28, 0x6d, 0x88, 0x2e, 0xfc, 0x44, 0xdb, 0x80, 0xe5, 0x1d, 0x8e, 0x8, 0xf1, 0xde, 0x28, 0xb4, 0x93, 0x4c, 0xc8, 0x49, 0x1f, 0xbe, 0x88, 0x42, 0xf, 0x31, 0x10, 0x65, 0x14, 0xbe}}}
  1201  	require.Equal(t, expectedPrevs, unboxed.ClientHeader.Prev)
  1202  	require.Equal(t, canned.SenderUID(t), unboxed.ClientHeader.Sender)
  1203  	require.Equal(t, canned.SenderDeviceID(t), unboxed.ClientHeader.SenderDevice)
  1204  	// CORE-4540: Uncomment this assertion when MerkleRoot is added to MessageClientHeaderVerified
  1205  	require.Nil(t, unboxed.ClientHeader.MerkleRoot)
  1206  	require.Nil(t, unboxed.ClientHeader.OutboxID)
  1207  	require.Nil(t, unboxed.ClientHeader.OutboxInfo)
  1208  
  1209  	// ServerHeader
  1210  	require.Equal(t, chat1.MessageID(2), unboxed.ServerHeader.MessageID)
  1211  	require.Equal(t, chat1.MessageID(0), unboxed.ServerHeader.SupersededBy)
  1212  
  1213  	// MessageBody
  1214  	require.Equal(t, "test1", unboxed.MessageBody.Text().Body)
  1215  
  1216  	// Other attributes of unboxed
  1217  	require.Equal(t, canned.senderUsername, unboxed.SenderUsername)
  1218  	require.Equal(t, canned.senderDeviceName, unboxed.SenderDeviceName)
  1219  	require.Equal(t, canned.senderDeviceType, unboxed.SenderDeviceType)
  1220  	require.Equal(t, canned.headerHash, unboxed.HeaderHash.String())
  1221  	require.NotNil(t, unboxed.HeaderSignature)
  1222  	require.Equal(t, canned.VerifyKey(t), unboxed.HeaderSignature.K)
  1223  	require.NotNil(t, unboxed.VerificationKey)
  1224  	require.Nil(t, unboxed.SenderDeviceRevokedAt)
  1225  }
  1226  
  1227  func TestV1Message3(t *testing.T) {
  1228  	// Unbox a canned V1 message from before V2 was thought up.
  1229  
  1230  	tc, boxer := setupChatTest(t, "unbox")
  1231  	defer tc.Cleanup()
  1232  
  1233  	canned := getCannedMessage(t, "bob25-alice25-3-deleted")
  1234  	boxed := canned.AsBoxed(t)
  1235  	modifyBoxerForTesting(t, boxer, &canned)
  1236  
  1237  	// Check some features before unboxing
  1238  	require.Equal(t, chat1.MessageBoxedVersion_VNONE, boxed.Version)
  1239  	require.Equal(t, "1fb5a5e7585a43aba1a59520939e2420", boxed.ClientHeader.Conv.TopicID.String())
  1240  	require.Equal(t, canned.encryptionKeyGeneration, boxed.KeyGeneration)
  1241  	require.Equal(t, chat1.MessageID(3), boxed.ServerHeader.MessageID)
  1242  	require.Equal(t, chat1.MessageID(0), boxed.ClientHeader.Supersedes)
  1243  	require.Nil(t, boxed.ClientHeader.Deletes)
  1244  
  1245  	// Unbox
  1246  	unboxed, err := boxer.unbox(context.TODO(), canned.AsBoxed(t), convInfo,
  1247  		canned.EncryptionKey(t), nil)
  1248  	require.NoError(t, err)
  1249  
  1250  	// Check some features of the unboxed
  1251  	// ClientHeader
  1252  	require.Equal(t, "d1fec1a2287b473206e282f4d4f30116", unboxed.ClientHeader.Conv.Tlfid.String())
  1253  	require.Equal(t, "1fb5a5e7585a43aba1a59520939e2420", unboxed.ClientHeader.Conv.TopicID.String())
  1254  	require.Equal(t, chat1.TopicType_CHAT, unboxed.ClientHeader.Conv.TopicType)
  1255  	require.Equal(t, "alice25,bob25", unboxed.ClientHeader.TlfName)
  1256  	require.Equal(t, false, unboxed.ClientHeader.TlfPublic)
  1257  	require.Equal(t, chat1.MessageType_TEXT, unboxed.ClientHeader.MessageType)
  1258  	expectedPrevs := []chat1.MessagePreviousPointer{{Id: 2, Hash: chat1.Hash{0xbe, 0xb2, 0x7c, 0x41, 0xdb, 0xeb, 0x2e, 0x90, 0x04, 0xf2, 0x48, 0xf2, 0x78, 0x24, 0x3a, 0xde, 0x5e, 0x12, 0x0c, 0xb7, 0xc4, 0x1f, 0x40, 0xe8, 0x47, 0xa2, 0xe2, 0x2f, 0xe8, 0x2c, 0xd3, 0xb4}}}
  1259  	require.Equal(t, expectedPrevs, unboxed.ClientHeader.Prev)
  1260  	require.Equal(t, canned.SenderUID(t), unboxed.ClientHeader.Sender)
  1261  	require.Equal(t, canned.SenderDeviceID(t), unboxed.ClientHeader.SenderDevice)
  1262  	// CORE-4540: Uncomment this assertion when MerkleRoot is added to MessageClientHeaderVerified
  1263  	require.Nil(t, unboxed.ClientHeader.MerkleRoot)
  1264  	require.Nil(t, unboxed.ClientHeader.OutboxID)
  1265  	require.Nil(t, unboxed.ClientHeader.OutboxInfo)
  1266  
  1267  	// ServerHeader
  1268  	require.Equal(t, chat1.MessageID(3), unboxed.ServerHeader.MessageID)
  1269  	require.Equal(t, chat1.MessageID(5), unboxed.ServerHeader.SupersededBy)
  1270  
  1271  	// MessageBody
  1272  	require.Equal(t, chat1.MessageBody{}, unboxed.MessageBody)
  1273  
  1274  	// Other attributes of unboxed
  1275  	require.Equal(t, canned.senderUsername, unboxed.SenderUsername)
  1276  	require.Equal(t, canned.senderDeviceName, unboxed.SenderDeviceName)
  1277  	require.Equal(t, canned.senderDeviceType, unboxed.SenderDeviceType)
  1278  	require.Equal(t, canned.headerHash, unboxed.HeaderHash.String())
  1279  	require.NotNil(t, unboxed.HeaderSignature)
  1280  	require.Equal(t, canned.VerifyKey(t), unboxed.HeaderSignature.K)
  1281  	require.NotNil(t, unboxed.VerificationKey)
  1282  	require.Nil(t, unboxed.SenderDeviceRevokedAt)
  1283  }
  1284  
  1285  func TestV1Message4(t *testing.T) {
  1286  	// Unbox a canned V1 message from before V2 was thought up.
  1287  
  1288  	tc, boxer := setupChatTest(t, "unbox")
  1289  	defer tc.Cleanup()
  1290  
  1291  	canned := getCannedMessage(t, "bob25-alice25-4-deleted-edit")
  1292  	boxed := canned.AsBoxed(t)
  1293  	modifyBoxerForTesting(t, boxer, &canned)
  1294  
  1295  	// Check some features before unboxing
  1296  	require.Equal(t, chat1.MessageBoxedVersion_VNONE, boxed.Version)
  1297  	require.Equal(t, "1fb5a5e7585a43aba1a59520939e2420", boxed.ClientHeader.Conv.TopicID.String())
  1298  	require.Equal(t, canned.encryptionKeyGeneration, boxed.KeyGeneration)
  1299  	require.Equal(t, chat1.MessageID(4), boxed.ServerHeader.MessageID)
  1300  	require.Equal(t, chat1.MessageID(3), boxed.ClientHeader.Supersedes)
  1301  	require.Nil(t, boxed.ClientHeader.Deletes)
  1302  
  1303  	// Unbox
  1304  	unboxed, err := boxer.unbox(context.TODO(), canned.AsBoxed(t), convInfo,
  1305  		canned.EncryptionKey(t), nil)
  1306  	require.NoError(t, err)
  1307  
  1308  	// Check some features of the unboxed
  1309  	// ClientHeader
  1310  	require.Equal(t, "d1fec1a2287b473206e282f4d4f30116", unboxed.ClientHeader.Conv.Tlfid.String())
  1311  	require.Equal(t, "1fb5a5e7585a43aba1a59520939e2420", unboxed.ClientHeader.Conv.TopicID.String())
  1312  	require.Equal(t, chat1.TopicType_CHAT, unboxed.ClientHeader.Conv.TopicType)
  1313  	require.Equal(t, "alice25,bob25", unboxed.ClientHeader.TlfName)
  1314  	require.Equal(t, false, unboxed.ClientHeader.TlfPublic)
  1315  	require.Equal(t, chat1.MessageType_EDIT, unboxed.ClientHeader.MessageType)
  1316  
  1317  	expectedPrevs := []chat1.MessagePreviousPointer{{Id: 3, Hash: chat1.Hash{0x3b, 0x54, 0x7a, 0x7a, 0xdd, 0x32, 0x5c, 0xcc, 0x9f, 0x4d, 0x30, 0x12, 0xc5, 0x6e, 0xb1, 0xab, 0xa0, 0x1c, 0xf7, 0x68, 0x7e, 0x26, 0x13, 0x49, 0x3f, 0xf5, 0xc9, 0xb7, 0x16, 0xaf, 0xd5, 0x07}}}
  1318  	require.Equal(t, expectedPrevs, unboxed.ClientHeader.Prev)
  1319  	require.Equal(t, canned.SenderUID(t), unboxed.ClientHeader.Sender)
  1320  	require.Equal(t, canned.SenderDeviceID(t), unboxed.ClientHeader.SenderDevice)
  1321  	// CORE-4540: Uncomment this assertion when MerkleRoot is added to MessageClientHeaderVerified
  1322  	require.Nil(t, unboxed.ClientHeader.MerkleRoot)
  1323  	expectedOutboxID := chat1.OutboxID{0x8e, 0xcc, 0x94, 0xb7, 0xff, 0x50, 0x5c, 0x4}
  1324  	require.Equal(t, &expectedOutboxID, unboxed.ClientHeader.OutboxID)
  1325  	expectedOutboxInfo := &chat1.OutboxInfo{Prev: 0x3, ComposeTime: 1487708373568}
  1326  	require.Equal(t, expectedOutboxInfo, unboxed.ClientHeader.OutboxInfo)
  1327  
  1328  	// ServerHeader
  1329  	require.Equal(t, chat1.MessageID(4), unboxed.ServerHeader.MessageID)
  1330  	// At the time this message was canned, supersededBy was not set deleted edits.
  1331  	require.Equal(t, chat1.MessageID(0), unboxed.ServerHeader.SupersededBy)
  1332  
  1333  	// MessageBody
  1334  	require.Equal(t, chat1.MessageBody{}, unboxed.MessageBody)
  1335  
  1336  	// Other attributes of unboxed
  1337  	require.Equal(t, canned.senderUsername, unboxed.SenderUsername)
  1338  	require.Equal(t, canned.senderDeviceName, unboxed.SenderDeviceName)
  1339  	require.Equal(t, canned.senderDeviceType, unboxed.SenderDeviceType)
  1340  	require.Equal(t, canned.headerHash, unboxed.HeaderHash.String())
  1341  	require.NotNil(t, unboxed.HeaderSignature)
  1342  	require.Equal(t, canned.VerifyKey(t), unboxed.HeaderSignature.K)
  1343  	require.NotNil(t, unboxed.VerificationKey)
  1344  	require.Nil(t, unboxed.SenderDeviceRevokedAt)
  1345  }
  1346  
  1347  func TestV1Message5(t *testing.T) {
  1348  	// Unbox a canned V1 message from before V2 was thought up.
  1349  
  1350  	tc, boxer := setupChatTest(t, "unbox")
  1351  	defer tc.Cleanup()
  1352  
  1353  	canned := getCannedMessage(t, "bob25-alice25-5-delete")
  1354  	boxed := canned.AsBoxed(t)
  1355  	modifyBoxerForTesting(t, boxer, &canned)
  1356  
  1357  	// Check some features before unboxing
  1358  	require.Equal(t, chat1.MessageBoxedVersion_VNONE, boxed.Version)
  1359  	require.Equal(t, "1fb5a5e7585a43aba1a59520939e2420", boxed.ClientHeader.Conv.TopicID.String())
  1360  	require.Equal(t, canned.encryptionKeyGeneration, boxed.KeyGeneration)
  1361  	require.Equal(t, chat1.MessageID(5), boxed.ServerHeader.MessageID)
  1362  	require.Equal(t, chat1.MessageID(3), boxed.ClientHeader.Supersedes)
  1363  	expectedDeletesIDs := []chat1.MessageID{3, 4}
  1364  	require.Equal(t, expectedDeletesIDs, boxed.ClientHeader.Deletes)
  1365  
  1366  	// Unbox
  1367  	unboxed, err := boxer.unbox(context.TODO(), canned.AsBoxed(t), convInfo,
  1368  		canned.EncryptionKey(t), nil)
  1369  	require.NoError(t, err)
  1370  
  1371  	// Check some features of the unboxed
  1372  	// ClientHeader
  1373  	require.Equal(t, "d1fec1a2287b473206e282f4d4f30116", unboxed.ClientHeader.Conv.Tlfid.String())
  1374  	require.Equal(t, "1fb5a5e7585a43aba1a59520939e2420", unboxed.ClientHeader.Conv.TopicID.String())
  1375  	require.Equal(t, chat1.TopicType_CHAT, unboxed.ClientHeader.Conv.TopicType)
  1376  	require.Equal(t, "alice25,bob25", unboxed.ClientHeader.TlfName)
  1377  	require.Equal(t, false, unboxed.ClientHeader.TlfPublic)
  1378  	require.Equal(t, chat1.MessageType_DELETE, unboxed.ClientHeader.MessageType)
  1379  
  1380  	expectedPrevs := []chat1.MessagePreviousPointer{{Id: 4, Hash: chat1.Hash{0xea, 0x68, 0x5e, 0x0f, 0x26, 0xb5, 0xb4, 0xfc, 0x1d, 0xe4, 0x15, 0x11, 0x34, 0x40, 0xcc, 0x3d, 0x54, 0x65, 0xa1, 0x52, 0x42, 0xd6, 0x83, 0xa7, 0xf4, 0x88, 0x96, 0xec, 0xd2, 0xc6, 0xd6, 0x26}}}
  1381  	require.Equal(t, expectedPrevs, unboxed.ClientHeader.Prev)
  1382  	require.Equal(t, canned.SenderUID(t), unboxed.ClientHeader.Sender)
  1383  	require.Equal(t, canned.SenderDeviceID(t), unboxed.ClientHeader.SenderDevice)
  1384  	// CORE-4540: Uncomment this assertion when MerkleRoot is added to MessageClientHeaderVerified
  1385  	require.Nil(t, unboxed.ClientHeader.MerkleRoot)
  1386  	expectedOutboxID := chat1.OutboxID{0xdc, 0x74, 0x6, 0x5d, 0xf9, 0x5f, 0x1c, 0x48}
  1387  	require.Equal(t, &expectedOutboxID, unboxed.ClientHeader.OutboxID)
  1388  	expectedOutboxInfo := &chat1.OutboxInfo{Prev: 0x3, ComposeTime: 1487708384552}
  1389  	require.Equal(t, expectedOutboxInfo, unboxed.ClientHeader.OutboxInfo)
  1390  
  1391  	// ServerHeader
  1392  	require.Equal(t, chat1.MessageID(5), unboxed.ServerHeader.MessageID)
  1393  	require.Equal(t, chat1.MessageID(0), unboxed.ServerHeader.SupersededBy)
  1394  
  1395  	// MessageBody
  1396  	require.Equal(t, chat1.MessageDelete{MessageIDs: expectedDeletesIDs}, unboxed.MessageBody.Delete())
  1397  
  1398  	// Other attributes of unboxed
  1399  	require.Equal(t, canned.senderUsername, unboxed.SenderUsername)
  1400  	require.Equal(t, canned.senderDeviceName, unboxed.SenderDeviceName)
  1401  	require.Equal(t, canned.senderDeviceType, unboxed.SenderDeviceType)
  1402  	require.Equal(t, canned.headerHash, unboxed.HeaderHash.String())
  1403  	require.NotNil(t, unboxed.HeaderSignature)
  1404  	require.Equal(t, canned.VerifyKey(t), unboxed.HeaderSignature.K)
  1405  	require.NotNil(t, unboxed.VerificationKey)
  1406  	require.Nil(t, unboxed.SenderDeviceRevokedAt)
  1407  }
  1408  
  1409  func modifyBoxerForTesting(t *testing.T, boxer *Boxer, canned *cannedMessage) {
  1410  	boxer.testingGetSenderInfoLocal = func(ctx context.Context, uid gregor1.UID, did gregor1.DeviceID) (senderUsername string, senderDeviceName string, senderDeviceType keybase1.DeviceTypeV2) {
  1411  		require.Equal(t, canned.SenderUID(t), uid)
  1412  		require.Equal(t, canned.SenderDeviceID(t), did)
  1413  		return canned.senderUsername, canned.senderDeviceName, canned.senderDeviceType
  1414  	}
  1415  	boxer.testingValidSenderKey = func(ctx context.Context, uid gregor1.UID, verifyKey []byte, ctime gregor1.Time) (revoked *gregor1.Time, unboxingErr types.UnboxingError) {
  1416  		require.Equal(t, canned.SenderUID(t), uid)
  1417  		require.Equal(t, canned.VerifyKey(t), verifyKey)
  1418  		// ignore ctime, always report the key as still valid
  1419  		return nil, nil
  1420  	}
  1421  }
  1422  
  1423  func requireValidMessage(t *testing.T, unboxed chat1.MessageUnboxed, description string) {
  1424  	state, err := unboxed.State()
  1425  	require.NoError(t, err, "failed to get the unboxed message state")
  1426  	require.Equal(t, chat1.MessageUnboxedState_VALID, state, description)
  1427  }
  1428  
  1429  func requireErrorMessage(t *testing.T, unboxed chat1.MessageUnboxed, description string) {
  1430  	state, err := unboxed.State()
  1431  	require.NoError(t, err, "failed to get the unboxed message state")
  1432  	require.Equal(t, chat1.MessageUnboxedState_ERROR, state, description)
  1433  }
  1434  
  1435  func TestChatMessageBodyHashReplay(t *testing.T) {
  1436  	doWithMBVersions(func(mbVersion chat1.MessageBoxedVersion) {
  1437  		text := "hi"
  1438  		tc, boxer := setupChatTest(t, "unbox")
  1439  		defer tc.Cleanup()
  1440  
  1441  		// need a real user
  1442  		u, err := kbtest.CreateAndSignupFakeUser("unbox", tc.G)
  1443  		require.NoError(t, err)
  1444  
  1445  		signKP := getSigningKeyPairForTest(t, tc, u)
  1446  
  1447  		// Generate an encryption key and create a fake finder to fetch it.
  1448  		key := cryptKey(t)
  1449  		g := globals.NewContext(tc.G, tc.ChatG)
  1450  		g.CtxFactory = newMockCtxFactory(g, []keybase1.CryptKey{*key})
  1451  		boxerContext := globals.BackgroundChatCtx(context.TODO(), g)
  1452  
  1453  		// This message has an all zeros ConversationIDTriple, but that's fine. We
  1454  		// can still extract the ConvID from it.
  1455  		msg := textMsgWithSender(t, text, gregor1.UID(u.User.GetUID().ToBytes()), mbVersion)
  1456  		convID := msg.ClientHeader.Conv.ToConversationID([2]byte{0, 0})
  1457  		conv := chat1.Conversation{
  1458  			Metadata: chat1.ConversationMetadata{
  1459  				ConversationID: convID,
  1460  			},
  1461  		}
  1462  		boxed, err := boxer.box(context.TODO(), msg, key, nil, signKP, mbVersion, nil)
  1463  		require.NoError(t, err)
  1464  
  1465  		// Need to give it a server header...
  1466  		boxed.ServerHeader = &chat1.MessageServerHeader{
  1467  			Ctime:     gregor1.ToTime(time.Now()),
  1468  			MessageID: 1,
  1469  		}
  1470  
  1471  		// Unbox the message once.
  1472  		unboxed, err := boxer.UnboxMessage(boxerContext, boxed, conv, nil)
  1473  		require.NoError(t, err)
  1474  		requireValidMessage(t, unboxed, "we expected msg4 to succeed")
  1475  
  1476  		// Unbox it again. This should be fine.
  1477  		unboxed, err = boxer.UnboxMessage(boxerContext, boxed, conv, nil)
  1478  		require.NoError(t, err)
  1479  		requireValidMessage(t, unboxed, "we expected msg4 to succeed the second time too")
  1480  
  1481  		// Now try to unbox it again with a different MessageID. This must fail.
  1482  		boxed.ServerHeader.MessageID = 2
  1483  		unboxed, err = boxer.UnboxMessage(boxerContext, boxed, conv, nil)
  1484  		require.NoError(t, err)
  1485  		requireErrorMessage(t, unboxed, "replay must be detected")
  1486  	})
  1487  }
  1488  
  1489  func TestChatMessagePrevPointerInconsistency(t *testing.T) {
  1490  	doWithMBVersions(func(mbVersion chat1.MessageBoxedVersion) {
  1491  		tc, boxer := setupChatTest(t, "unbox")
  1492  		defer tc.Cleanup()
  1493  
  1494  		// need a real user
  1495  		u, err := kbtest.CreateAndSignupFakeUser("unbox", tc.G)
  1496  		require.NoError(t, err)
  1497  
  1498  		signKP := getSigningKeyPairForTest(t, tc, u)
  1499  
  1500  		// Generate an encryption key and create a fake finder to fetch it.
  1501  		key := cryptKey(t)
  1502  		g := globals.NewContext(tc.G, tc.ChatG)
  1503  		g.CtxFactory = newMockCtxFactory(g, []keybase1.CryptKey{*key})
  1504  		boxerContext := globals.BackgroundChatCtx(context.TODO(), g)
  1505  
  1506  		// Everything below will use the zero convID.
  1507  		convID := chat1.ConversationIDTriple{Tlfid: mockTLFID}.ToConversationID([2]byte{0, 0})
  1508  		conv := chat1.Conversation{
  1509  			Metadata: chat1.ConversationMetadata{
  1510  				ConversationID: convID,
  1511  			},
  1512  		}
  1513  
  1514  		makeMsg := func(id chat1.MessageID, prevs []chat1.MessagePreviousPointer) chat1.MessageBoxed {
  1515  			msg := textMsgWithSender(t, "foo text", gregor1.UID(u.User.GetUID().ToBytes()), mbVersion)
  1516  			msg.ClientHeader.Prev = prevs
  1517  			boxed, err := boxer.box(context.TODO(), msg, key, nil, signKP, mbVersion, nil)
  1518  			require.NoError(t, err)
  1519  			boxed.ServerHeader = &chat1.MessageServerHeader{
  1520  				Ctime:     gregor1.ToTime(time.Now()),
  1521  				MessageID: id,
  1522  			}
  1523  			return boxed
  1524  		}
  1525  
  1526  		// Generate a couple of initial messages, with no prev pointers of their own.
  1527  		boxed1 := makeMsg(1, nil)
  1528  		boxed2 := makeMsg(2, nil)
  1529  
  1530  		// Now unbox the first message. That caches its header hash. Leave the
  1531  		// second one out of the cache for now though. (We'll use it to cause an
  1532  		// error later.)
  1533  		unboxed1, err := boxer.UnboxMessage(boxerContext, boxed1, conv, nil)
  1534  		require.NoError(t, err)
  1535  
  1536  		// Create two more messages, which both have bad prev pointers. Msg3 has a
  1537  		// bad prev for msg1, and must fail to unbox, because we've already unboxed
  1538  		// msg1. Msg4 has a bad prev for msg2 (which we haven't unboxed yet)
  1539  		// and a good prev for msg1. Msg4 will therefore succeed at unboxing now,
  1540  		// and we will check that msg2 fails later.
  1541  		boxed3 := makeMsg(3, []chat1.MessagePreviousPointer{
  1542  			{
  1543  				Id: 1,
  1544  				// Bad pointer for msg1. This will cause an immediate unboxing failure.
  1545  				Hash: []byte("BAD PREV POINTER HERE"),
  1546  			},
  1547  		})
  1548  		boxed4 := makeMsg(4, []chat1.MessagePreviousPointer{
  1549  			{
  1550  				Id: 1,
  1551  				// Good pointer for msg1.
  1552  				Hash: unboxed1.Valid().HeaderHash,
  1553  			},
  1554  			{
  1555  				Id: 2,
  1556  				// Bad pointer for msg2. Because we've never unboxed message 2
  1557  				// before, though, we'll cache this bad prev pointer, and it's msg2
  1558  				// that will fail to unbox.
  1559  				Hash: []byte("ANOTHER BAD PREV POINTER OMG"),
  1560  			},
  1561  		})
  1562  
  1563  		unboxed, err := boxer.UnboxMessage(boxerContext, boxed3, conv, nil)
  1564  		require.NoError(t, err)
  1565  		requireErrorMessage(t, unboxed, "msg3 has a known bad prev pointer and must fail to unbox")
  1566  
  1567  		unboxed, err = boxer.UnboxMessage(boxerContext, boxed4, conv, nil)
  1568  		require.NoError(t, err)
  1569  		requireValidMessage(t, unboxed, "we expected msg4 to succeed")
  1570  
  1571  		// Now try to unbox msg2. Because of msg4's bad pointer, this should fail.
  1572  		unboxed, err = boxer.UnboxMessage(boxerContext, boxed2, conv, nil)
  1573  		require.NoError(t, err)
  1574  		requireErrorMessage(t, unboxed, "msg2 should fail to unbox, because of msg4's bad pointer")
  1575  	})
  1576  }
  1577  
  1578  func TestChatMessageBadConvID(t *testing.T) {
  1579  	doWithMBVersions(func(mbVersion chat1.MessageBoxedVersion) {
  1580  		text := "hi"
  1581  		tc, boxer := setupChatTest(t, "unbox")
  1582  		defer tc.Cleanup()
  1583  
  1584  		// need a real user
  1585  		u, err := kbtest.CreateAndSignupFakeUser("unbox", tc.G)
  1586  		require.NoError(t, err)
  1587  
  1588  		signKP := getSigningKeyPairForTest(t, tc, u)
  1589  
  1590  		// Generate an encryption key and create a fake finder to fetch it.
  1591  		key := cryptKey(t)
  1592  		g := globals.NewContext(tc.G, tc.ChatG)
  1593  		g.CtxFactory = newMockCtxFactory(g, []keybase1.CryptKey{*key})
  1594  		boxerContext := globals.BackgroundChatCtx(context.TODO(), g)
  1595  
  1596  		// This message has an all zeros ConversationIDTriple, but that's fine. We
  1597  		// can still extract the ConvID from it.
  1598  		msg := textMsgWithSender(t, text, gregor1.UID(u.User.GetUID().ToBytes()), mbVersion)
  1599  		boxed, err := boxer.box(context.TODO(), msg, key, nil, signKP, mbVersion, nil)
  1600  		require.NoError(t, err)
  1601  		boxed.ServerHeader = &chat1.MessageServerHeader{
  1602  			Ctime:     gregor1.ToTime(time.Now()),
  1603  			MessageID: 1,
  1604  		}
  1605  
  1606  		// Confirm that this message fails to unbox if we use a convID that doesn't
  1607  		// derive from the same triple.
  1608  		badTriple := chat1.ConversationIDTriple{
  1609  			Tlfid: []byte("random non-matching TLF ID"),
  1610  		}
  1611  		badConvID := badTriple.ToConversationID([2]byte{0, 0})
  1612  		badConv := chat1.Conversation{
  1613  			Metadata: chat1.ConversationMetadata{
  1614  				ConversationID: badConvID,
  1615  			},
  1616  		}
  1617  
  1618  		unboxed, err := boxer.UnboxMessage(boxerContext, boxed, badConv, nil)
  1619  		require.NoError(t, err)
  1620  		requireErrorMessage(t, unboxed, "expected a bad convID to fail the unboxing")
  1621  	})
  1622  }
  1623  
  1624  func remarshalBoxed(t *testing.T, v chat1.MessageBoxed) chat1.MessageBoxed {
  1625  	// encode
  1626  	mh := codec.MsgpackHandle{WriteExt: true}
  1627  	var data []byte
  1628  	enc := codec.NewEncoderBytes(&data, &mh)
  1629  	err := enc.Encode(v)
  1630  	require.NoError(t, err)
  1631  
  1632  	// decode
  1633  	var v2 chat1.MessageBoxed
  1634  	mh = codec.MsgpackHandle{WriteExt: true}
  1635  	dec := codec.NewDecoderBytes(data, &mh)
  1636  	err = dec.Decode(&v2)
  1637  	require.NoError(t, err)
  1638  	return v2
  1639  }
  1640  
  1641  func TestRemarshalBoxed(t *testing.T) {
  1642  	outboxID1 := chat1.OutboxID{0xdc, 0x74, 0x6, 0x5d, 0xf9, 0x5f, 0x1c, 0x48}
  1643  	boxed1 := chat1.MessageBoxed{
  1644  		ClientHeader: chat1.MessageClientHeader{
  1645  			OutboxID: &outboxID1,
  1646  		},
  1647  	}
  1648  
  1649  	boxed2 := remarshalBoxed(t, boxed1)
  1650  
  1651  	require.NotEqual(t, chat1.MessageBoxed{}, boxed2, "second shouldn't be zeroed")
  1652  	require.Equal(t, boxed1.ClientHeader.OutboxID == nil, boxed2.ClientHeader.OutboxID == nil, "obids should have same nility")
  1653  
  1654  	if boxed1.ClientHeader.OutboxID == boxed2.ClientHeader.OutboxID {
  1655  		t.Fatalf("obids should not have same address")
  1656  	}
  1657  
  1658  	require.NotNil(t, boxed1.ClientHeader.OutboxID, "obid1 should not be nil")
  1659  	require.NotNil(t, boxed2.ClientHeader.OutboxID, "obid2 should not be nil")
  1660  
  1661  	require.Equal(t, boxed1.ClientHeader.OutboxID, boxed2.ClientHeader.OutboxID, "obids should have same value")
  1662  }
  1663  
  1664  func randomTeamEK() types.EphemeralCryptKey {
  1665  	randBytes, err := libkb.RandBytes(32)
  1666  	if err != nil {
  1667  		panic(err)
  1668  	}
  1669  	seed := libkb.MakeByte32(randBytes)
  1670  	dhKey := (*ephemeral.TeamEKSeed)(&seed).DeriveDHKey()
  1671  	return keybase1.NewTeamEphemeralKeyWithTeam(keybase1.TeamEk{
  1672  		Seed: seed,
  1673  		Metadata: keybase1.TeamEkMetadata{
  1674  			Kid: dhKey.GetKID(),
  1675  		},
  1676  	})
  1677  }
  1678  
  1679  func TestExplodingMessageUnbox(t *testing.T) {
  1680  	tc, boxer := setupChatTest(t, "exploding")
  1681  	defer tc.Cleanup()
  1682  
  1683  	key := cryptKey(t)
  1684  	ephemeralKey := randomTeamEK()
  1685  	text := "hello exploding"
  1686  	// We need a user for unboxing to work.
  1687  	u, err := kbtest.CreateAndSignupFakeUser("unbox", tc.G)
  1688  	require.NoError(t, err)
  1689  	msg := textMsgWithSender(t, text, gregor1.UID(u.User.GetUID().ToBytes()), chat1.MessageBoxedVersion_V3)
  1690  
  1691  	// Set the ephemeral metadata, to indicate that the messages is exploding.
  1692  	msg.ClientHeader.EphemeralMetadata = &chat1.MsgEphemeralMetadata{
  1693  		Lifetime: 99999,
  1694  	}
  1695  
  1696  	// Box it! Note that we pass in the ephemeral/exploding key, and also set
  1697  	// V3 explicitly.
  1698  	boxed, err := boxer.box(context.TODO(), msg, key, ephemeralKey,
  1699  		getSigningKeyPairForTest(t, tc, u), chat1.MessageBoxedVersion_V3, nil)
  1700  	require.NoError(t, err)
  1701  	require.Equal(t, chat1.MessageBoxedVersion_V3, boxed.Version)
  1702  	require.True(t, len(boxed.BodyCiphertext.E) > 0)
  1703  
  1704  	// We need to give it a server header for unboxing...
  1705  	boxed.ServerHeader = &chat1.MessageServerHeader{
  1706  		Ctime: gregor1.ToTime(time.Now()),
  1707  	}
  1708  
  1709  	// Unbox it!!!
  1710  	unboxed, err := boxer.unbox(context.TODO(), boxed, convInfo,
  1711  		key, ephemeralKey)
  1712  	require.NoError(t, err)
  1713  	body := unboxed.MessageBody
  1714  	typ, err := body.MessageType()
  1715  	require.NoError(t, err)
  1716  	require.Equal(t, typ, chat1.MessageType_TEXT)
  1717  	require.Equal(t, body.Text().Body, text)
  1718  	require.Nil(t, unboxed.SenderDeviceRevokedAt, "message should not be from revoked device")
  1719  	require.NotNil(t, unboxed.BodyHash)
  1720  	require.True(t, unboxed.IsEphemeral())
  1721  	require.NotNil(t, unboxed.EphemeralMetadata())
  1722  	require.Equal(t, msg.EphemeralMetadata().Lifetime, unboxed.EphemeralMetadata().Lifetime)
  1723  }
  1724  
  1725  func TestVersionErrorBasic(t *testing.T) {
  1726  	// Test basic functionality for parsing the error message
  1727  	// TODO remove this when we drop parsing
  1728  	maxMessageBoxedVersion := chat1.MaxMessageBoxedVersion
  1729  	err := NewMessageBoxedVersionError(maxMessageBoxedVersion)
  1730  	e := chat1.MessageUnboxedError{
  1731  		ErrType: err.ExportType(),
  1732  		ErrMsg:  err.Error(),
  1733  	}
  1734  	require.True(t, e.ParseableVersion())
  1735  
  1736  	err2 := NewMessageBoxedVersionError(maxMessageBoxedVersion)
  1737  	e2 := chat1.MessageUnboxedError{
  1738  		ErrType:       err2.ExportType(),
  1739  		ErrMsg:        err2.Error(),
  1740  		VersionKind:   err2.VersionKind(),
  1741  		VersionNumber: err2.VersionNumber(),
  1742  		IsCritical:    err2.IsCritical(),
  1743  	}
  1744  	require.True(t, e2.ParseableVersion())
  1745  
  1746  	// not recoverable until we bump the max
  1747  	err = NewMessageBoxedVersionError(maxMessageBoxedVersion + 1)
  1748  	e = chat1.MessageUnboxedError{
  1749  		ErrType: err.ExportType(),
  1750  		ErrMsg:  err.Error(),
  1751  	}
  1752  	require.False(t, e.ParseableVersion())
  1753  
  1754  	chat1.MaxMessageBoxedVersion = maxMessageBoxedVersion + 1
  1755  	defer func() { chat1.MaxMessageBoxedVersion = maxMessageBoxedVersion }()
  1756  	require.True(t, e.ParseableVersion())
  1757  }
  1758  
  1759  func TestVersionError(t *testing.T) {
  1760  	tc, boxer := setupChatTest(t, "box")
  1761  	defer tc.Cleanup()
  1762  
  1763  	// These tests will fail when we update the boxer code to accept new
  1764  	// maximums. This forces
  1765  	// chat1/extras.go#MessageUnboxedError.ParseableVersion to stay up to date
  1766  	// for it's max accepted versions. Vx__ will also have to be updated in the
  1767  	// checks below
  1768  	assertErr := func(err types.UnboxingError) {
  1769  		require.Error(t, err)
  1770  		typ := err.ExportType()
  1771  		switch typ {
  1772  		case chat1.MessageUnboxedErrorType_BADVERSION, chat1.MessageUnboxedErrorType_BADVERSION_CRITICAL:
  1773  			// pass
  1774  		default:
  1775  			require.Fail(t, "invalid error type (%s) for error: %s", typ, err.Error())
  1776  		}
  1777  
  1778  		e := chat1.MessageUnboxedError{
  1779  			ErrType: err.ExportType(),
  1780  			ErrMsg:  err.Error(),
  1781  		}
  1782  		require.False(t, e.ParseableVersion())
  1783  	}
  1784  	maxMessageBoxedVersion := chat1.MaxMessageBoxedVersion + 1
  1785  	maxHeaderVersion := chat1.MaxHeaderVersion + 1
  1786  	maxBodyVersion := chat1.MaxBodyVersion + 1
  1787  
  1788  	key := cryptKey(t)
  1789  	t.Logf("unbox")
  1790  	_, err := boxer.unbox(context.Background(), chat1.MessageBoxed{Version: maxMessageBoxedVersion},
  1791  		convInfo, key, nil)
  1792  	assertErr(err)
  1793  
  1794  	t.Logf("unversionHeaderMBV2")
  1795  	hv2 := chat1.HeaderPlaintextUnsupported{}
  1796  	hp := chat1.MessageServerHeader{}
  1797  	_, _, err = boxer.unversionHeaderMBV2(context.Background(), &hp, chat1.HeaderPlaintext{Version__: maxHeaderVersion, V2__: &hv2})
  1798  	assertErr(err)
  1799  
  1800  	t.Logf("unversionBody")
  1801  	bv3 := chat1.BodyPlaintextUnsupported{}
  1802  	_, err = boxer.unversionBody(context.Background(), chat1.BodyPlaintext{Version__: maxBodyVersion, V3__: &bv3})
  1803  	assertErr(err)
  1804  }
  1805  
  1806  func TestMakeOnePairwiseMAC(t *testing.T) {
  1807  	var mySecret [32]byte
  1808  	copy(mySecret[:], "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
  1809  	var theirSecret [32]byte
  1810  	copy(theirSecret[:], "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")
  1811  
  1812  	myKey, err := libkb.MakeNaclDHKeyPairFromSecret(mySecret)
  1813  	require.NoError(t, err)
  1814  	theirKey, err := libkb.MakeNaclDHKeyPairFromSecret(theirSecret)
  1815  	require.NoError(t, err)
  1816  
  1817  	mac := makeOnePairwiseMAC(*myKey.Private, theirKey.Public, []byte("hello world"))
  1818  
  1819  	// We used the following Python program to get the expected output of this
  1820  	// test case. If we tweak something about the MAC, please tweak this Python
  1821  	// example to match, rather than just pasting in whatever the new answer
  1822  	// happens to be. This is important for making sure our MAC contains
  1823  	// exactly the inputs its supposed to.
  1824  	//
  1825  	// #! /usr/bin/python3
  1826  	// from hashlib import sha256
  1827  	// import hmac
  1828  	// from nacl.public import PrivateKey, Box  # https://github.com/pyca/pynacl
  1829  	// my_key = PrivateKey(b"a" * 32)
  1830  	// their_key = PrivateKey(b"b" * 32)
  1831  	// raw_shared = Box(my_key, their_key.public_key).shared_key()
  1832  	// context = b"Derived-Chat-Pairwise-HMAC-SHA256-1"
  1833  	// derived_shared = sha256(context + b"\0" + raw_shared).digest()
  1834  	// derived_shared = hmac.new(key=raw_shared, msg=context, digestmod=sha256).digest()
  1835  	// mac = hmac.new(key=derived_shared, msg=b"hello world", digestmod=sha256).digest()
  1836  	// print(mac.hex())
  1837  	expected := "ec6d999902fa02a1e96b0a2d97526999db49843f3e2d961e7a398d53f9a910e0"
  1838  
  1839  	require.Equal(t, expected, hex.EncodeToString(mac))
  1840  }