// DecryptTLFCryptKeyClientHalf implements the Crypto interface for // CryptoClient. func (c *CryptoClient) DecryptTLFCryptKeyClientHalf(ctx context.Context, publicKey TLFEphemeralPublicKey, encryptedClientHalf EncryptedTLFCryptKeyClientHalf) ( clientHalf TLFCryptKeyClientHalf, err error) { c.log.CDebugf(ctx, "Decrypting TLF client key half") defer func() { c.deferLog.CDebugf(ctx, "Decrypted TLF client key half: %v", err) }() encryptedData, nonce, err := c.prepareTLFCryptKeyClientHalf(encryptedClientHalf) if err != nil { return } timer := c.logAboutLongRPCUnlessCancelled(ctx, "UnboxBytes32") defer timer.Stop() decryptedClientHalf, err := c.client.UnboxBytes32(ctx, keybase1.UnboxBytes32Arg{ EncryptedBytes32: encryptedData, Nonce: nonce, PeersPublicKey: keybase1.BoxPublicKey(publicKey.data), Reason: "to use kbfs", }) if err != nil { return } clientHalf = MakeTLFCryptKeyClientHalf(decryptedClientHalf) return }
// Test that CryptoHandler.UnboxBytes32() decrypts a boxed 32-byte // array correctly. func TestCryptoUnboxBytes32(t *testing.T) { tc := SetupEngineTest(t, "crypto") defer tc.Cleanup() u := CreateAndSignupFakeUser(tc, "fu") secretUI := &libkb.TestSecretUI{Passphrase: u.Passphrase} key, err := getMySecretKey( tc.G, secretUI, libkb.DeviceEncryptionKeyType, "test") if err != nil { t.Fatal(err) } kp, ok := key.(libkb.NaclDHKeyPair) if !ok || kp.Private == nil { t.Fatalf("unexpected key %v", key) } peerKp, err := libkb.GenerateNaclDHKeyPair() if err != nil { t.Fatal(err) } expectedBytes32 := keybase1.Bytes32{0, 1, 2, 3, 4, 5} nonce := [24]byte{6, 7, 8, 9, 10} peersPublicKey := keybase1.BoxPublicKey(peerKp.Public) encryptedData := box.Seal(nil, expectedBytes32[:], &nonce, (*[32]byte)(&kp.Public), (*[32]byte)(peerKp.Private)) var encryptedBytes32 keybase1.EncryptedBytes32 if len(encryptedBytes32) != len(encryptedData) { t.Fatalf("Expected %d bytes, got %d", len(encryptedBytes32), len(encryptedData)) } copy(encryptedBytes32[:], encryptedData) bytes32, err := UnboxBytes32(tc.G, secretUI, keybase1.UnboxBytes32Arg{ EncryptedBytes32: encryptedBytes32, Nonce: nonce, PeersPublicKey: peersPublicKey, }) if err != nil { t.Fatal(err) } if bytes32 != expectedBytes32 { t.Errorf("expected %s, got %s", expectedBytes32, bytes32) } }
// DecryptTLFCryptKeyClientHalfAny implements the Crypto interface for // CryptoClient. func (c *CryptoClient) DecryptTLFCryptKeyClientHalfAny(ctx context.Context, keys []EncryptedTLFCryptKeyClientAndEphemeral, promptPaper bool) ( clientHalf TLFCryptKeyClientHalf, index int, err error) { c.log.CDebugf(ctx, "Decrypting TLF client key half with any key") defer func() { c.deferLog.CDebugf(ctx, "Decrypted TLF client key half with any key: %v", err) }() if len(keys) == 0 { return clientHalf, index, NoKeysError{} } bundles := make([]keybase1.CiphertextBundle, 0, len(keys)) errors := make([]error, 0, len(keys)) indexLookup := make([]int, 0, len(keys)) for i, k := range keys { encryptedData, nonce, err := c.prepareTLFCryptKeyClientHalf(k.ClientHalf) if err != nil { errors = append(errors, err) } else { bundles = append(bundles, keybase1.CiphertextBundle{ Kid: k.PubKey.kidContainer.kid, Ciphertext: encryptedData, Nonce: nonce, PublicKey: keybase1.BoxPublicKey(k.EPubKey.data), }) indexLookup = append(indexLookup, i) } } if len(bundles) == 0 { err = errors[0] return } timer := c.logAboutLongRPCUnlessCancelled(ctx, "UnboxBytes32Any") defer timer.Stop() res, err := c.client.UnboxBytes32Any(ctx, keybase1.UnboxBytes32AnyArg{ Bundles: bundles, Reason: "to rekey for kbfs", PromptPaper: promptPaper, }) if err != nil { return } return MakeTLFCryptKeyClientHalf(res.Plaintext), indexLookup[res.Index], nil }
// DecryptTLFCryptKeyClientHalf implements the Crypto interface for // CryptoClient. func (c *CryptoClient) DecryptTLFCryptKeyClientHalf(ctx context.Context, publicKey TLFEphemeralPublicKey, encryptedClientHalf EncryptedTLFCryptKeyClientHalf) ( clientHalf TLFCryptKeyClientHalf, err error) { encryptedData, nonce, err := c.prepareTLFCryptKeyClientHalf(encryptedClientHalf) if err != nil { return } decryptedClientHalf, err := c.client.UnboxBytes32(ctx, keybase1.UnboxBytes32Arg{ EncryptedBytes32: encryptedData, Nonce: nonce, PeersPublicKey: keybase1.BoxPublicKey(publicKey.data), Reason: "to use kbfs", }) if err != nil { return } clientHalf = MakeTLFCryptKeyClientHalf(decryptedClientHalf) return }
// DecryptTLFCryptKeyClientHalfAny implements the Crypto interface for // CryptoClient. func (c *CryptoClient) DecryptTLFCryptKeyClientHalfAny(ctx context.Context, keys []EncryptedTLFCryptKeyClientAndEphemeral) ( clientHalf TLFCryptKeyClientHalf, index int, err error) { if len(keys) == 0 { return clientHalf, index, NoKeysError{} } bundles := make([]keybase1.CiphertextBundle, 0, len(keys)) errors := make([]error, 0, len(keys)) indexLookup := make([]int, 0, len(keys)) for i, k := range keys { encryptedData, nonce, err := c.prepareTLFCryptKeyClientHalf(k.ClientHalf) if err != nil { errors = append(errors, err) } else { bundles = append(bundles, keybase1.CiphertextBundle{ Kid: k.PubKey.kidContainer.kid, Ciphertext: encryptedData, Nonce: nonce, PublicKey: keybase1.BoxPublicKey(k.EPubKey.data), }) indexLookup = append(indexLookup, i) } } if len(bundles) == 0 { err = errors[0] return } res, err := c.client.UnboxBytes32Any(ctx, keybase1.UnboxBytes32AnyArg{ Bundles: bundles, Reason: "to rekey for kbfs", }) if err != nil { return } return MakeTLFCryptKeyClientHalf(res.Plaintext), indexLookup[res.Index], nil }
func TestCryptoUnboxBytes32AnyPaper(t *testing.T) { tc := SetupEngineTest(t, "crypto") defer tc.Cleanup() u := CreateAndSignupFakeUser(tc, "fu") // create a paper key and cache it ctx := &Context{ LogUI: tc.G.UI.GetLogUI(), LoginUI: &libkb.TestLoginUI{}, SecretUI: u.NewSecretUI(), } peng := NewPaperKey(tc.G) if err := RunEngine(peng, ctx); err != nil { t.Fatal(err) } err := tc.G.LoginState().Account(func(a *libkb.Account) { a.SetUnlockedPaperKey(peng.SigKey(), peng.EncKey()) }, "TestCryptoUnboxBytes32AnyPaper") key := peng.EncKey() kp, ok := key.(libkb.NaclDHKeyPair) if !ok { t.Fatalf("paper enc key type: %T, expected libkb.NaclDHKeyPair", key) } if kp.Private == nil { t.Fatalf("paper enc key has nil private key") } peerKp, err := libkb.GenerateNaclDHKeyPair() if err != nil { t.Fatal(err) } expectedBytes32 := keybase1.Bytes32{0, 1, 2, 3, 4, 5} nonce := [24]byte{6, 7, 8, 9, 10} peersPublicKey := keybase1.BoxPublicKey(peerKp.Public) encryptedData := box.Seal(nil, expectedBytes32[:], &nonce, (*[32]byte)(&kp.Public), (*[32]byte)(peerKp.Private)) var encryptedBytes32 keybase1.EncryptedBytes32 if len(encryptedBytes32) != len(encryptedData) { t.Fatalf("Expected %d bytes, got %d", len(encryptedBytes32), len(encryptedData)) } copy(encryptedBytes32[:], encryptedData) _, err = UnboxBytes32(tc.G, u.NewSecretUI(), keybase1.UnboxBytes32Arg{ EncryptedBytes32: encryptedBytes32, Nonce: nonce, PeersPublicKey: peersPublicKey, }) // this should fail if err == nil { t.Fatal("UnboxBytes32 worked with paper key encrypted data") } if _, ok := err.(libkb.DecryptionError); !ok { t.Fatalf("error %T, expected libkb.DecryptionError", err) } // this should work arg := keybase1.UnboxBytes32AnyArg{ Bundles: []keybase1.CiphertextBundle{ {Kid: kp.GetKID(), Ciphertext: encryptedBytes32, Nonce: nonce}, }, PeersPublicKey: peersPublicKey, } res, err := UnboxBytes32Any(tc.G, u.NewSecretUI(), arg) if err != nil { t.Fatal(err) } if res.Plaintext != expectedBytes32 { t.Errorf("UnboxBytes32Any plaintext: %x, expected %x", res.Plaintext, expectedBytes32) } if res.Kid.IsNil() { t.Errorf("UnboxBytes32Any kid is nil") } // clear the paper key cache to test getting a paper key via UI err = tc.G.LoginState().Account(func(a *libkb.Account) { a.ClearCachedSecretKeys() }, "TestCryptoUnboxBytes32AnyPaper") if err != nil { t.Fatal(err) } // set the passphrase in the secretUI to the paper key secretUI := u.NewSecretUI() secretUI.Passphrase = peng.Passphrase() res, err = UnboxBytes32Any(tc.G, secretUI, arg) if err != nil { t.Fatal(err) } if res.Plaintext != expectedBytes32 { t.Errorf("UnboxBytes32Any plaintext: %x, expected %x", res.Plaintext, expectedBytes32) } if res.Kid.IsNil() { t.Errorf("UnboxBytes32Any kid is nil") } }
// Test that CryptoHandler.UnboxBytes32() decrypts a boxed 32-byte // array correctly. func TestCryptoUnboxBytes32(t *testing.T) { tc := SetupEngineTest(t, "crypto") defer tc.Cleanup() u := CreateAndSignupFakeUser(tc, "fu") f := func() libkb.SecretUI { return &libkb.TestSecretUI{Passphrase: u.Passphrase} } key, err := getMySecretKey( tc.G, f, libkb.DeviceEncryptionKeyType, "test") if err != nil { t.Fatal(err) } kp, ok := key.(libkb.NaclDHKeyPair) if !ok || kp.Private == nil { t.Fatalf("unexpected key %v", key) } peerKp, err := libkb.GenerateNaclDHKeyPair() if err != nil { t.Fatal(err) } expectedBytes32 := keybase1.Bytes32{0, 1, 2, 3, 4, 5} nonce := [24]byte{6, 7, 8, 9, 10} peersPublicKey := keybase1.BoxPublicKey(peerKp.Public) encryptedData := box.Seal(nil, expectedBytes32[:], &nonce, (*[32]byte)(&kp.Public), (*[32]byte)(peerKp.Private)) var encryptedBytes32 keybase1.EncryptedBytes32 if len(encryptedBytes32) != len(encryptedData) { t.Fatalf("Expected %d bytes, got %d", len(encryptedBytes32), len(encryptedData)) } copy(encryptedBytes32[:], encryptedData) bytes32, err := UnboxBytes32(tc.G, f, keybase1.UnboxBytes32Arg{ EncryptedBytes32: encryptedBytes32, Nonce: nonce, PeersPublicKey: peersPublicKey, }) if err != nil { t.Fatal(err) } if bytes32 != expectedBytes32 { t.Errorf("expected %s, got %s", expectedBytes32, bytes32) } // also test UnboxBytes32Any: arg := keybase1.UnboxBytes32AnyArg{ Bundles: []keybase1.CiphertextBundle{ {Kid: kp.GetKID(), Ciphertext: encryptedBytes32, Nonce: nonce, PublicKey: peersPublicKey}, }, } res, err := UnboxBytes32Any(tc.G, f, arg) if err != nil { t.Fatal(err) } if res.Plaintext != expectedBytes32 { t.Errorf("UnboxBytes32Any plaintext: %x, expected %x", res.Plaintext, expectedBytes32) } if res.Kid.IsNil() { t.Errorf("UnboxBytes32Any kid is nil") } }