github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/engine/pgp_decrypt_test.go (about) 1 // Copyright 2015 Keybase, Inc. All rights reserved. Use of 2 // this source code is governed by the included BSD license. 3 4 package engine 5 6 import ( 7 "bytes" 8 "crypto/rand" 9 "strings" 10 "testing" 11 12 "github.com/stretchr/testify/assert" 13 14 "golang.org/x/net/context" 15 16 "github.com/keybase/client/go/libkb" 17 keybase1 "github.com/keybase/client/go/protocol/keybase1" 18 "github.com/stretchr/testify/require" 19 ) 20 21 func decengctx(fu *FakeUser, tc libkb.TestContext) libkb.MetaContext { 22 return NewMetaContextForTest(tc).WithUIs(libkb.UIs{ 23 IdentifyUI: &FakeIdentifyUI{}, 24 SecretUI: fu.NewSecretUI(), 25 LogUI: tc.G.UI.GetLogUI(), 26 PgpUI: &TestPgpUI{}, 27 }) 28 } 29 30 func TestPGPDecrypt(t *testing.T) { 31 tc := SetupEngineTest(t, "PGPDecrypt") 32 defer tc.Cleanup() 33 fu := createFakeUserWithPGPSibkeyPushed(tc) 34 35 // encrypt a message 36 msg := "10 days in Japan" 37 sink := libkb.NewBufferCloser() 38 ctx := decengctx(fu, tc) 39 arg := &PGPEncryptArg{ 40 Source: strings.NewReader(msg), 41 Sink: sink, 42 NoSign: true, 43 BinaryOutput: true, 44 } 45 enc := NewPGPEncrypt(tc.G, arg) 46 if err := RunEngine2(ctx, enc); err != nil { 47 t.Fatal(err) 48 } 49 out := sink.Bytes() 50 51 t.Logf("encrypted data: %x", out) 52 53 // decrypt it 54 decoded := libkb.NewBufferCloser() 55 decarg := &PGPDecryptArg{ 56 Source: bytes.NewReader(out), 57 Sink: decoded, 58 } 59 dec := NewPGPDecrypt(tc.G, decarg) 60 if err := RunEngine2(ctx, dec); err != nil { 61 t.Fatal(err) 62 } 63 decmsg := decoded.String() 64 if decmsg != msg { 65 t.Errorf("decoded: %q, expected: %q", decmsg, msg) 66 } 67 68 if dec.Signer() != nil { 69 t.Errorf("signer exists, but NoSign flag was true") 70 } 71 } 72 73 func TestPGPDecryptArmored(t *testing.T) { 74 tc := SetupEngineTest(t, "PGPDecrypt") 75 defer tc.Cleanup() 76 fu := createFakeUserWithPGPSibkeyPushed(tc) 77 78 // encrypt a message 79 msg := "10 days in Japan" 80 ctx := decengctx(fu, tc) 81 sink := libkb.NewBufferCloser() 82 arg := &PGPEncryptArg{ 83 Source: strings.NewReader(msg), 84 Sink: sink, 85 NoSign: true, 86 } 87 enc := NewPGPEncrypt(tc.G, arg) 88 if err := RunEngine2(ctx, enc); err != nil { 89 t.Fatal(err) 90 } 91 out := sink.Bytes() 92 93 t.Logf("encrypted data: %x", out) 94 95 // decrypt it 96 decoded := libkb.NewBufferCloser() 97 decarg := &PGPDecryptArg{ 98 Source: bytes.NewReader(out), 99 Sink: decoded, 100 } 101 dec := NewPGPDecrypt(tc.G, decarg) 102 if err := RunEngine2(ctx, dec); err != nil { 103 t.Fatal(err) 104 } 105 decmsg := decoded.String() 106 if decmsg != msg { 107 t.Errorf("decoded: %q, expected: %q", decmsg, msg) 108 } 109 110 // A saltpack message 111 saltpack := `BEGIN KEYBASE SALTPACK ENCRYPTED MESSAGE. 112 kiOUtMhcc4NXXRb XMxIeCbf5rGHq6R lPA7tN3yNXtviMm fQULSIc4k93xPgP ranhF1KYLsndSXH 5hK5WHvPJYOvN3G XLzn8MQ3Q5nwFfY K81cz83VtMGh4CC QnNDeIWVZawH75I jFf8SlDWsdj139W FeS69yb9b7Mo5fA rusOzT3JaydVWgf qC7hU3CUvYR65nP xUpmT2HdHPG5MQu XsOhrf5Zv39u9BB AOkyDAgD7hVSSl9 JQ3eYiduTli4Bqh Ri3uJyBayvkWZTF PSOdMhIbjCptBQ3 oTdvh6pOaUPQeoJ ENL1iuVK04KCOy9 xFekloWTI94hkgt gZakcYbimhmzhea Dsgl2mVqgIwmHgv hp5Indezz4TNtOh VJ8c4BBt1NEzIDg ZfFUiAALL0jRfrB cz7tQc1ussnYzrI IfHSFPDe9Cvz9lp gb1BBogunZOkoNW skfxofDP2lX3Qx7 QP5ah5zm8VV0iw1 zfQaNoxicwkqrM8 tfxyKUWZAypOKoF wUIaC1CQIkTZANa bIJyCxs9g6WceUE jLhh4PazAPCMOU9 M3zOBPP1ieDvc0M OzBLKtBWwz0J1nU 0wtMiADTMKMV. 113 END KEYBASE SALTPACK ENCRYPTED MESSAGE.` 114 115 decoded = libkb.NewBufferCloser() 116 decarg = &PGPDecryptArg{ 117 Source: strings.NewReader(saltpack), 118 Sink: decoded, 119 } 120 dec = NewPGPDecrypt(tc.G, decarg) 121 err := RunEngine2(ctx, dec) 122 if wse, ok := err.(libkb.WrongCryptoFormatError); !ok { 123 t.Fatalf("Wanted a WrongCryptoFormat error, but got %T (%v)", err, err) 124 } else if wse.Wanted != libkb.CryptoMessageFormatPGP || 125 wse.Received != libkb.CryptoMessageFormatSaltpack || 126 wse.Operation != "decrypt" { 127 t.Fatalf("Bad error: %v", wse) 128 } 129 } 130 131 // TestPGPDecryptSignedSelf tests that the user who signed the 132 // message can decrypt it. 133 func TestPGPDecryptSignedSelf(t *testing.T) { 134 tc := SetupEngineTest(t, "PGPDecrypt") 135 defer tc.Cleanup() 136 fu := createFakeUserWithPGPSibkeyPushed(tc) 137 138 // encrypt a message 139 msg := "We pride ourselves on being meticulous; no issue is too small." 140 ctx := decengctx(fu, tc) 141 sink := libkb.NewBufferCloser() 142 arg := &PGPEncryptArg{ 143 Source: strings.NewReader(msg), 144 Sink: sink, 145 BinaryOutput: true, 146 } 147 enc := NewPGPEncrypt(tc.G, arg) 148 if err := RunEngine2(ctx, enc); err != nil { 149 t.Fatal(err) 150 } 151 out := sink.Bytes() 152 153 t.Logf("encrypted data: %x", out) 154 155 // decrypt it 156 decoded := libkb.NewBufferCloser() 157 decarg := &PGPDecryptArg{ 158 Source: bytes.NewReader(out), 159 Sink: decoded, 160 AssertSigned: true, 161 } 162 dec := NewPGPDecrypt(tc.G, decarg) 163 if err := RunEngine2(ctx, dec); err != nil { 164 t.Fatal(err) 165 } 166 decmsg := decoded.String() 167 if decmsg != msg { 168 t.Errorf("decoded: %q, expected: %q", decmsg, msg) 169 } 170 } 171 172 // TestPGPDecryptSignedOther tests that a user who didn't sign the 173 // message can verify the signature. 174 func TestPGPDecryptSignedOther(t *testing.T) { 175 tcRecipient := SetupEngineTest(t, "PGPDecrypt - Recipient") 176 defer tcRecipient.Cleanup() 177 recipient := createFakeUserWithPGPSibkey(tcRecipient) 178 Logout(tcRecipient) 179 180 tcSigner := SetupEngineTest(t, "PGPDecrypt - Signer") 181 defer tcSigner.Cleanup() 182 signer := createFakeUserWithPGPSibkey(tcSigner) 183 184 // encrypt a message 185 msg := "We pride ourselves on being meticulous; no issue is too small." 186 ctx := decengctx(signer, tcSigner) 187 sink := libkb.NewBufferCloser() 188 arg := &PGPEncryptArg{ 189 Recips: []string{recipient.Username}, 190 Source: strings.NewReader(msg), 191 Sink: sink, 192 BinaryOutput: true, 193 } 194 enc := NewPGPEncrypt(tcSigner.G, arg) 195 if err := RunEngine2(ctx, enc); err != nil { 196 t.Fatal(err) 197 } 198 out := sink.Bytes() 199 200 t.Logf("encrypted data: %x", out) 201 202 // signer logs out, recipient logs in: 203 t.Logf("signer (%q) logging out", signer.Username) 204 Logout(tcSigner) 205 // G = libkb.G 206 t.Logf("recipient (%q) logging in", recipient.Username) 207 recipient.LoginOrBust(tcRecipient) 208 209 rtrackUI := &FakeIdentifyUI{} 210 uis := libkb.UIs{ 211 IdentifyUI: rtrackUI, 212 SecretUI: recipient.NewSecretUI(), 213 LogUI: tcRecipient.G.UI.GetLogUI(), 214 PgpUI: &TestPgpUI{}, 215 } 216 217 // decrypt it 218 decoded := libkb.NewBufferCloser() 219 decarg := &PGPDecryptArg{ 220 Source: bytes.NewReader(out), 221 Sink: decoded, 222 AssertSigned: true, 223 } 224 dec := NewPGPDecrypt(tcRecipient.G, decarg) 225 m := NewMetaContextForTest(tcRecipient).WithUIs(uis) 226 if err := RunEngine2(m, dec); err != nil { 227 t.Fatal(err) 228 } 229 decmsg := decoded.String() 230 if decmsg != msg { 231 t.Errorf("decoded: %q, expected: %q", decmsg, msg) 232 } 233 } 234 235 // TestPGPDecryptSignedIdentify tests that the signer is 236 // identified regardless of AssertSigned, SignedBy args. 237 func TestPGPDecryptSignedIdentify(t *testing.T) { 238 tcRecipient := SetupEngineTest(t, "PGPDecrypt - Recipient") 239 defer tcRecipient.Cleanup() 240 recipient := createFakeUserWithPGPSibkey(tcRecipient) 241 Logout(tcRecipient) 242 243 tcSigner := SetupEngineTest(t, "PGPDecrypt - Signer") 244 defer tcSigner.Cleanup() 245 signer := createFakeUserWithPGPSibkey(tcSigner) 246 247 // encrypt a message 248 msg := "We pride ourselves on being meticulous; no issue is too small." 249 ctx := decengctx(signer, tcSigner) 250 sink := libkb.NewBufferCloser() 251 arg := &PGPEncryptArg{ 252 Recips: []string{recipient.Username}, 253 Source: strings.NewReader(msg), 254 Sink: sink, 255 BinaryOutput: true, 256 } 257 enc := NewPGPEncrypt(tcSigner.G, arg) 258 if err := RunEngine2(ctx, enc); err != nil { 259 t.Fatal(err) 260 } 261 out := sink.Bytes() 262 263 t.Logf("encrypted data: %x", out) 264 265 // signer logs out, recipient logs in: 266 t.Logf("signer (%q) logging out", signer.Username) 267 Logout(tcSigner) 268 t.Logf("recipient (%q) logging in", recipient.Username) 269 recipient.LoginOrBust(tcRecipient) 270 271 idUI := &FakeIdentifyUI{} 272 pgpUI := &TestPgpUI{} 273 uis := libkb.UIs{ 274 IdentifyUI: idUI, 275 SecretUI: recipient.NewSecretUI(), 276 LogUI: tcRecipient.G.UI.GetLogUI(), 277 PgpUI: pgpUI, 278 } 279 280 // decrypt it 281 decoded := libkb.NewBufferCloser() 282 decarg := &PGPDecryptArg{ 283 Source: bytes.NewReader(out), 284 Sink: decoded, 285 AssertSigned: false, 286 } 287 dec := NewPGPDecrypt(tcRecipient.G, decarg) 288 m := NewMetaContextForTest(tcRecipient).WithUIs(uis) 289 if err := RunEngine2(m, dec); err != nil { 290 t.Fatal(err) 291 } 292 293 if idUI.User == nil { 294 t.Fatal("identify ui user is nil") 295 } 296 if idUI.User.Username != signer.Username { 297 t.Errorf("idUI username: %q, expected %q", idUI.User.Username, signer.Username) 298 } 299 if pgpUI.OutputCount != 1 { 300 t.Errorf("PgpUI output called %d times, expected 1", pgpUI.OutputCount) 301 } 302 } 303 304 func TestPGPDecryptLong(t *testing.T) { 305 tc := SetupEngineTest(t, "PGPDecrypt") 306 defer tc.Cleanup() 307 fu := createFakeUserWithPGPSibkey(tc) 308 309 // encrypt a message 310 msg := make([]byte, 1024*1024) 311 312 if _, err := rand.Read(msg); err != nil { 313 t.Fatal(err) 314 } 315 316 sink := libkb.NewBufferCloser() 317 ctx := decengctx(fu, tc) 318 arg := &PGPEncryptArg{ 319 Source: bytes.NewReader(msg), 320 Sink: sink, 321 NoSign: true, 322 BinaryOutput: true, 323 } 324 enc := NewPGPEncrypt(tc.G, arg) 325 if err := RunEngine2(ctx, enc); err != nil { 326 t.Fatal(err) 327 } 328 out := sink.Bytes() 329 330 // decrypt it 331 decoded := libkb.NewBufferCloser() 332 decarg := &PGPDecryptArg{ 333 Source: bytes.NewReader(out), 334 Sink: decoded, 335 } 336 dec := NewPGPDecrypt(tc.G, decarg) 337 if err := RunEngine2(ctx, dec); err != nil { 338 t.Fatal(err) 339 } 340 decmsg := decoded.Bytes() 341 if len(decmsg) != len(msg) { 342 t.Fatalf("decoded msg size: %d, expected %d", len(decmsg), len(msg)) 343 } 344 345 for i, b := range msg { 346 if decmsg[i] != b { 347 t.Errorf("decode msg differs at byte %d: %x, expected %x", i, decmsg[i], b) 348 } 349 } 350 351 if dec.Signer() != nil { 352 t.Errorf("signer exists, but NoSign flag set to true") 353 } 354 } 355 356 type cstest struct { 357 name string 358 msg string 359 } 360 361 var cstests = []cstest{ 362 {name: "ascii", msg: "hello"}, 363 {name: "emoji", msg: "😓😕😙"}, 364 } 365 366 func TestPGPDecryptClearsign(t *testing.T) { 367 tc := SetupEngineTest(t, "PGPDecrypt") 368 defer tc.Cleanup() 369 370 fu := createFakeUserWithPGPSibkey(tc) 371 ctx := decengctx(fu, tc) 372 373 for _, test := range cstests { 374 signedMsg := sign(ctx, tc, test.msg, keybase1.SignMode_CLEAR) 375 t.Logf("%s: signed message:\n\n%s\n", test.name, signedMsg) 376 377 decoded := libkb.NewBufferCloser() 378 arg := &PGPDecryptArg{ 379 Source: strings.NewReader(signedMsg), 380 Sink: decoded, 381 } 382 eng := NewPGPDecrypt(tc.G, arg) 383 if err := RunEngine2(ctx, eng); err != nil { 384 t.Errorf("%s: decrypt error: %q", test.name, err) 385 continue 386 } 387 msg := decoded.Bytes() 388 trimmed := strings.TrimSpace(string(msg)) 389 t.Logf("clearsign test %q decoded message: %s\n", test.name, trimmed) 390 if trimmed != test.msg { 391 t.Errorf("%s: expected msg %q, got %q", test.name, test.msg, trimmed) 392 } 393 394 status := eng.SignatureStatus() 395 if !status.IsSigned { 396 t.Errorf("%s: expected IsSigned", test.name) 397 } 398 if !status.Verified { 399 t.Errorf("%s: expected Verified", test.name) 400 } 401 if status.Entity == nil { 402 t.Errorf("%s: signature status entity is nil", test.name) 403 } 404 } 405 } 406 407 // TestPGPDecryptNonKeybase tests decrypt on a message 408 // created with a key unknown to keybase. 409 func TestPGPDecryptNonKeybase(t *testing.T) { 410 tcRecipient := SetupEngineTest(t, "PGPDecrypt - Recipient") 411 defer tcRecipient.Cleanup() 412 recipient := createFakeUserWithPGPSibkey(tcRecipient) 413 414 tcSigner := SetupEngineTest(t, "PGPDecrypt - Signer") 415 defer tcSigner.Cleanup() 416 keyA, err := tcSigner.MakePGPKey("keya@keybase.io") 417 require.NoError(t, err) 418 419 // find recipient key 420 ur, err := libkb.LoadUser(libkb.NewLoadUserByNameArg(tcSigner.G, recipient.Username)) 421 if err != nil { 422 t.Fatal(err) 423 } 424 rkeys := ur.GetActivePGPKeys(false) 425 if len(rkeys) == 0 { 426 t.Fatal("recipient has no active pgp keys") 427 } 428 429 // encrypt and sign a message with keyA 430 mid := libkb.NewBufferCloser() 431 msg := "Is it time for lunch?" 432 recipients := []*libkb.PGPKeyBundle{keyA, rkeys[0]} 433 if err := libkb.PGPEncrypt(strings.NewReader(msg), mid, keyA, recipients); err != nil { 434 t.Fatal(err) 435 } 436 437 t.Logf("encrypted data: %x", mid.Bytes()) 438 439 idUI := &FakeIdentifyUI{} 440 pgpUI := &TestPgpUI{} 441 uis := libkb.UIs{ 442 IdentifyUI: idUI, 443 SecretUI: recipient.NewSecretUI(), 444 LogUI: tcRecipient.G.UI.GetLogUI(), 445 PgpUI: pgpUI, 446 } 447 448 // decrypt it 449 decoded := libkb.NewBufferCloser() 450 decarg := &PGPDecryptArg{ 451 Source: bytes.NewReader(mid.Bytes()), 452 Sink: decoded, 453 AssertSigned: false, 454 } 455 dec := NewPGPDecrypt(tcRecipient.G, decarg) 456 m := NewMetaContextForTest(tcRecipient).WithUIs(uis) 457 err = RunEngine2(m, dec) 458 assert.IsType(t, libkb.BadSigError{}, err, "expected a bad sig error") 459 assert.Contains(t, err.Error(), "Message signed by an unknown key", "bad sig error text") 460 461 if idUI.User != nil { 462 if idUI.User.Username == recipient.Username { 463 t.Errorf("pgp decrypt identified recipient") 464 } else { 465 t.Errorf("identify ui user is not nil: %s", idUI.User.Username) 466 } 467 } 468 if pgpUI.OutputCount != 0 { 469 t.Errorf("PgpUI OutputSignatureSuccess called %d times, expected 0", pgpUI.OutputCount) 470 } 471 if pgpUI.OutputNonKeybaseCount != 1 { 472 t.Errorf("PgpUI OutputSignatureNonKeybase called %d times, expected 0", pgpUI.OutputNonKeybaseCount) 473 } 474 } 475 476 type TestPgpUI struct { 477 OutputWarnings int 478 OutputCount int 479 OutputNonKeybaseCount int 480 ShouldPush bool 481 Generated keybase1.KeyGeneratedArg 482 } 483 484 func (t *TestPgpUI) OutputPGPWarning(context.Context, keybase1.OutputPGPWarningArg) error { 485 t.OutputWarnings++ 486 return nil 487 } 488 489 func (t *TestPgpUI) OutputSignatureSuccess(context.Context, keybase1.OutputSignatureSuccessArg) error { 490 t.OutputCount++ 491 return nil 492 } 493 494 func (t *TestPgpUI) OutputSignatureNonKeybase(context.Context, keybase1.OutputSignatureNonKeybaseArg) error { 495 t.OutputNonKeybaseCount++ 496 return nil 497 } 498 499 func (t *TestPgpUI) KeyGenerated(ctx context.Context, arg keybase1.KeyGeneratedArg) error { 500 t.Generated = arg 501 return nil 502 } 503 504 func (t *TestPgpUI) ShouldPushPrivate(context.Context, keybase1.ShouldPushPrivateArg) (bool, error) { 505 return t.ShouldPush, nil 506 } 507 508 func (t *TestPgpUI) Finished(context.Context, int) error { 509 return nil 510 } 511 512 func TestPGPDecryptWithSyncedKey(t *testing.T) { 513 tc0 := SetupEngineTest(t, "pgpg") 514 defer tc0.Cleanup() 515 516 u := createFakeUserWithPGPOnly(t, tc0) 517 t.Log("Created fake user with PGP synced only") 518 519 // find recipient key 520 ur, err := libkb.LoadUser(libkb.NewLoadUserByNameArg(tc0.G, u.Username)) 521 require.NoError(t, err, "loaded the user") 522 rkeys := ur.GetActivePGPKeys(false) 523 require.True(t, len(rkeys) > 0, "recipient has no active pgp keys") 524 525 // encrypt and message with rkeys[0] 526 mid := libkb.NewBufferCloser() 527 msg := "Is it time for lunch?" 528 recipients := []*libkb.PGPKeyBundle{rkeys[0]} 529 err = libkb.PGPEncrypt(strings.NewReader(msg), mid, nil, recipients) 530 require.NoError(t, err, "pgp encryption failed") 531 t.Logf("encrypted data: %x", mid.Bytes()) 532 533 Logout(tc0) 534 535 // redo SetupEngineTest to get a new home directory...should look like a new device. 536 tc := SetupEngineTest(t, "login") 537 defer tc.Cleanup() 538 539 uis := libkb.UIs{ 540 ProvisionUI: newTestProvisionUIPassphrase(), 541 LoginUI: &libkb.TestLoginUI{Username: u.Username}, 542 LogUI: tc.G.UI.GetLogUI(), 543 SecretUI: u.NewSecretUI(), 544 GPGUI: &gpgtestui{}, 545 } 546 eng := NewLogin(tc.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 547 m := NewMetaContextForTest(tc).WithUIs(uis) 548 err = RunEngine2(m, eng) 549 require.NoError(t, err, "no error when checking login") 550 551 // decrypt it 552 decryptIt := func() bool { 553 decoded := libkb.NewBufferCloser() 554 decarg := &PGPDecryptArg{ 555 Source: bytes.NewReader(mid.Bytes()), 556 Sink: decoded, 557 AssertSigned: false, 558 } 559 idUI := &FakeIdentifyUI{} 560 pgpUI := &TestPgpUI{} 561 secretUI := u.NewSecretUI() 562 uis = libkb.UIs{ 563 IdentifyUI: idUI, 564 SecretUI: secretUI, 565 LogUI: tc.G.UI.GetLogUI(), 566 PgpUI: pgpUI, 567 } 568 dec := NewPGPDecrypt(tc.G, decarg) 569 m = NewMetaContextForTest(tc).WithUIs(uis) 570 err = RunEngine2(m, dec) 571 require.NoError(t, err, "no error for PGP decrypt") 572 573 decryptedMsg := decoded.Bytes() 574 trimmed := strings.TrimSpace(string(decryptedMsg)) 575 t.Logf("decrypted msg: %s", trimmed) 576 require.Equal(t, trimmed, msg, "msg equality failed") 577 return secretUI.CalledGetPassphrase 578 } 579 580 decryptCalledPassphrase := decryptIt() 581 // No need to get a passphrase, since we just logged in. 582 require.False(t, decryptCalledPassphrase, "passphrase get wasn't called") 583 584 clearCaches(m.G()) 585 586 decryptCalledPassphrase = decryptIt() 587 require.True(t, decryptCalledPassphrase, "passphrase get was called") 588 589 decryptCalledPassphrase = decryptIt() 590 require.False(t, decryptCalledPassphrase, "passphrase get wasn't called") 591 592 }