github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/engine/crypto_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 "fmt" 9 "runtime/debug" 10 "testing" 11 12 "golang.org/x/crypto/nacl/box" 13 "golang.org/x/net/context" 14 15 "github.com/keybase/client/go/kbcrypto" 16 "github.com/keybase/client/go/libkb" 17 keybase1 "github.com/keybase/client/go/protocol/keybase1" 18 ) 19 20 // Test that SignED25519() signs the given message with the device 21 // signing key, and that the signature is verifiable by the returned 22 // public key. 23 // 24 // (For general tests that valid signatures are accepted and invalid 25 // signatures are rejected, see naclwrap_test.go.) 26 func TestCryptoSignED25519(t *testing.T) { 27 tc := SetupEngineTest(t, "crypto") 28 defer tc.Cleanup() 29 30 CreateAndSignupFakeUser(tc, "fu") 31 32 msg := []byte("test message") 33 ret, err := SignED25519(context.TODO(), tc.G, keybase1.SignED25519Arg{ 34 Msg: msg, 35 }) 36 if err != nil { 37 t.Fatal(err) 38 } 39 40 publicKey := kbcrypto.NaclSigningKeyPublic(ret.PublicKey) 41 if !publicKey.Verify(msg, kbcrypto.NaclSignature(ret.Sig)) { 42 t.Error(kbcrypto.VerificationError{}) 43 } 44 } 45 46 // Test that SignToString() signs the given message with the device 47 // signing key and that the signature is verifiable and contains the message. 48 func TestCryptoSignToString(t *testing.T) { 49 tc := SetupEngineTest(t, "crypto") 50 defer tc.Cleanup() 51 52 CreateAndSignupFakeUser(tc, "fu") 53 54 msg := []byte("test message") 55 signature, err := SignToString(context.TODO(), tc.G, keybase1.SignToStringArg{ 56 Msg: msg, 57 }) 58 if err != nil { 59 t.Fatal(err) 60 } 61 62 _, msg2, _, err := kbcrypto.NaclVerifyAndExtract(signature) 63 if err != nil { 64 t.Fatal(err) 65 } 66 if !bytes.Equal(msg, msg2) { 67 t.Fatal(fmt.Errorf("message mismatch, expected: %s, got: %s", 68 string(msg), string(msg2))) 69 } 70 } 71 72 // Test that CryptoHandler.SignED25519() propagates any error 73 // encountered when getting the device signing key. 74 func TestCryptoSignED25519NoSigningKey(t *testing.T) { 75 tc := SetupEngineTest(t, "crypto") 76 defer tc.Cleanup() 77 78 _, err := SignED25519(context.TODO(), tc.G, keybase1.SignED25519Arg{ 79 Msg: []byte("test message"), 80 }) 81 82 if _, ok := err.(libkb.LoginRequiredError); !ok { 83 t.Errorf("expected LoginRequiredError, got %v", err) 84 } 85 } 86 87 func BenchmarkCryptoSignED25519(b *testing.B) { 88 tc := SetupEngineTest(b, "crypto") 89 defer tc.Cleanup() 90 91 CreateAndSignupFakeUser(tc, "fu") 92 93 b.ResetTimer() 94 for i := 0; i < b.N; i++ { 95 msg := []byte("test message") 96 _, err := SignED25519(context.TODO(), tc.G, keybase1.SignED25519Arg{ 97 Msg: msg, 98 }) 99 if err != nil { 100 b.Fatal(err) 101 } 102 } 103 } 104 105 // Test that CryptoHandler.UnboxBytes32() decrypts a boxed 32-byte 106 // array correctly. 107 func TestCryptoUnboxBytes32(t *testing.T) { 108 tc := SetupEngineTest(t, "crypto") 109 defer tc.Cleanup() 110 111 u := CreateAndSignupFakeUser(tc, "fu") 112 f := func() libkb.SecretUI { 113 return &libkb.TestSecretUI{Passphrase: u.Passphrase} 114 } 115 116 key, err := GetMySecretKey( 117 context.TODO(), 118 tc.G, libkb.DeviceEncryptionKeyType, "test") 119 if err != nil { 120 t.Fatal(err) 121 } 122 kp, ok := key.(libkb.NaclDHKeyPair) 123 if !ok || kp.Private == nil { 124 t.Fatalf("unexpected key %v", key) 125 } 126 127 peerKp, err := libkb.GenerateNaclDHKeyPair() 128 if err != nil { 129 t.Fatal(err) 130 } 131 132 expectedBytes32 := keybase1.Bytes32{0, 1, 2, 3, 4, 5} 133 nonce := [24]byte{6, 7, 8, 9, 10} 134 peersPublicKey := keybase1.BoxPublicKey(peerKp.Public) 135 136 encryptedData := box.Seal(nil, expectedBytes32[:], &nonce, (*[32]byte)(&kp.Public), (*[32]byte)(peerKp.Private)) 137 138 var encryptedBytes32 keybase1.EncryptedBytes32 139 if len(encryptedBytes32) != len(encryptedData) { 140 t.Fatalf("Expected %d bytes, got %d", len(encryptedBytes32), len(encryptedData)) 141 } 142 143 copy(encryptedBytes32[:], encryptedData) 144 145 bytes32, err := UnboxBytes32(context.TODO(), tc.G, keybase1.UnboxBytes32Arg{ 146 EncryptedBytes32: encryptedBytes32, 147 Nonce: nonce, 148 PeersPublicKey: peersPublicKey, 149 }) 150 151 if err != nil { 152 t.Fatal(err) 153 } 154 155 if bytes32 != expectedBytes32 { 156 t.Errorf("expected %s, got %s", expectedBytes32, bytes32) 157 } 158 159 // also test UnboxBytes32Any: 160 arg := keybase1.UnboxBytes32AnyArg{ 161 Bundles: []keybase1.CiphertextBundle{ 162 {Kid: kp.GetKID(), Ciphertext: encryptedBytes32, Nonce: nonce, PublicKey: peersPublicKey}, 163 }, 164 } 165 res, err := UnboxBytes32Any(NewMetaContextForTest(tc), f, arg) 166 if err != nil { 167 t.Fatal(err) 168 } 169 if res.Plaintext != expectedBytes32 { 170 t.Errorf("UnboxBytes32Any plaintext: %x, expected %x", res.Plaintext, expectedBytes32) 171 } 172 if res.Kid.IsNil() { 173 t.Errorf("UnboxBytes32Any kid is nil") 174 } 175 } 176 177 // Test that CryptoHandler.UnboxBytes32() propagates any decryption 178 // errors correctly. 179 // 180 // For now, we're assuming that nacl/box works correctly (i.e., we're 181 // not testing the ways in which decryption can fail). 182 func TestCryptoUnboxBytes32DecryptionError(t *testing.T) { 183 tc := SetupEngineTest(t, "crypto") 184 defer tc.Cleanup() 185 186 CreateAndSignupFakeUser(tc, "fu") 187 188 _, err := UnboxBytes32(context.TODO(), tc.G, keybase1.UnboxBytes32Arg{}) 189 if _, ok := err.(libkb.DecryptionError); !ok { 190 t.Errorf("expected libkb.DecryptionError, got %T", err) 191 } 192 } 193 194 // Test that CryptoHandler.UnboxBytes32() propagates any error 195 // encountered when getting the device encryption key. 196 func TestCryptoUnboxBytes32NoEncryptionKey(t *testing.T) { 197 tc := SetupEngineTest(t, "crypto") 198 defer tc.Cleanup() 199 200 _, err := UnboxBytes32(context.TODO(), tc.G, keybase1.UnboxBytes32Arg{}) 201 202 if _, ok := err.(libkb.LoginRequiredError); !ok { 203 t.Errorf("expected LoginRequiredError, got %v", err) 204 } 205 } 206 207 func cachedSecretKey(tc libkb.TestContext, ktype libkb.SecretKeyType) (key libkb.GenericKey, err error) { 208 return tc.G.ActiveDevice.KeyByType(ktype) 209 } 210 211 func assertCachedSecretKey(tc libkb.TestContext, ktype libkb.SecretKeyType) { 212 skey, err := cachedSecretKey(tc, ktype) 213 if err != nil { 214 debug.PrintStack() 215 tc.T.Fatalf("error getting cached secret key: %s", err) 216 } 217 if skey == nil { 218 tc.T.Fatalf("expected cached key, got nil") 219 } 220 } 221 222 func assertNotCachedSecretKey(tc libkb.TestContext, ktype libkb.SecretKeyType) { 223 skey, err := cachedSecretKey(tc, ktype) 224 if err == nil { 225 tc.T.Fatal("expected err getting cached secret key, got nil") 226 } 227 if _, notFound := err.(libkb.NotFoundError); !notFound { 228 tc.T.Fatalf("expected not found error, got %s (%T)", err, err) 229 } 230 if skey != nil { 231 tc.T.Fatalf("expected nil cached key, got %v", skey) 232 } 233 } 234 235 // TestCachedSecretKey tests that secret device keys are cached 236 // properly. 237 func TestCachedSecretKey(t *testing.T) { 238 tc := SetupEngineTest(t, "login") 239 defer tc.Cleanup() 240 241 u := CreateAndSignupFakeUser(tc, "login") 242 243 assertCachedSecretKey(tc, libkb.DeviceSigningKeyType) 244 assertCachedSecretKey(tc, libkb.DeviceEncryptionKeyType) 245 246 Logout(tc) 247 248 assertNotCachedSecretKey(tc, libkb.DeviceSigningKeyType) 249 assertNotCachedSecretKey(tc, libkb.DeviceEncryptionKeyType) 250 251 u.LoginOrBust(tc) 252 253 assertCachedSecretKey(tc, libkb.DeviceSigningKeyType) 254 assertCachedSecretKey(tc, libkb.DeviceEncryptionKeyType) 255 256 msg := []byte("test message") 257 _, err := SignED25519(context.TODO(), tc.G, keybase1.SignED25519Arg{ 258 Msg: msg, 259 }) 260 if err != nil { 261 t.Fatal(err) 262 } 263 264 assertCachedSecretKey(tc, libkb.DeviceSigningKeyType) 265 assertCachedSecretKey(tc, libkb.DeviceEncryptionKeyType) 266 267 Logout(tc) 268 269 assertNotCachedSecretKey(tc, libkb.DeviceSigningKeyType) 270 assertNotCachedSecretKey(tc, libkb.DeviceEncryptionKeyType) 271 272 u.LoginOrBust(tc) 273 274 assertCachedSecretKey(tc, libkb.DeviceSigningKeyType) 275 assertCachedSecretKey(tc, libkb.DeviceEncryptionKeyType) 276 } 277 278 func TestCryptoUnboxBytes32AnyPaper(t *testing.T) { 279 tc := SetupEngineTest(t, "crypto") 280 defer tc.Cleanup() 281 282 u := CreateAndSignupFakeUser(tc, "fu") 283 284 // create a paper key and cache it 285 uis := libkb.UIs{ 286 LogUI: tc.G.UI.GetLogUI(), 287 LoginUI: &libkb.TestLoginUI{}, 288 SecretUI: u.NewSecretUI(), 289 } 290 peng := NewPaperKey(tc.G) 291 m := NewMetaContextForTest(tc).WithUIs(uis) 292 if err := RunEngine2(m, peng); err != nil { 293 t.Fatal(err) 294 } 295 296 m.ActiveDevice().CacheProvisioningKey(m, libkb.NewDeviceWithKeysOnly(peng.SigKey(), peng.EncKey(), libkb.KeychainModeNone)) 297 298 key := peng.EncKey() 299 kp, ok := key.(libkb.NaclDHKeyPair) 300 if !ok { 301 t.Fatalf("paper enc key type: %T, expected libkb.NaclDHKeyPair", key) 302 } 303 if kp.Private == nil { 304 t.Fatalf("paper enc key has nil private key") 305 } 306 307 peerKp, err := libkb.GenerateNaclDHKeyPair() 308 if err != nil { 309 t.Fatal(err) 310 } 311 312 expectedBytes32 := keybase1.Bytes32{0, 1, 2, 3, 4, 5} 313 nonce := [24]byte{6, 7, 8, 9, 10} 314 peersPublicKey := keybase1.BoxPublicKey(peerKp.Public) 315 316 encryptedData := box.Seal(nil, expectedBytes32[:], &nonce, (*[32]byte)(&kp.Public), (*[32]byte)(peerKp.Private)) 317 318 var encryptedBytes32 keybase1.EncryptedBytes32 319 if len(encryptedBytes32) != len(encryptedData) { 320 t.Fatalf("Expected %d bytes, got %d", len(encryptedBytes32), len(encryptedData)) 321 } 322 323 copy(encryptedBytes32[:], encryptedData) 324 325 f := func() libkb.SecretUI { 326 return u.NewSecretUI() 327 } 328 329 _, err = UnboxBytes32(context.TODO(), tc.G, keybase1.UnboxBytes32Arg{ 330 EncryptedBytes32: encryptedBytes32, 331 Nonce: nonce, 332 PeersPublicKey: peersPublicKey, 333 }) 334 335 // this should fail 336 if err == nil { 337 t.Fatal("UnboxBytes32 worked with paper key encrypted data") 338 } 339 if _, ok := err.(libkb.DecryptionError); !ok { 340 t.Fatalf("error %T, expected libkb.DecryptionError", err) 341 } 342 343 // this should work 344 arg := keybase1.UnboxBytes32AnyArg{ 345 Bundles: []keybase1.CiphertextBundle{ 346 {Kid: kp.GetKID(), Ciphertext: encryptedBytes32, Nonce: nonce, PublicKey: peersPublicKey}, 347 }, 348 PromptPaper: true, 349 } 350 res, err := UnboxBytes32Any(NewMetaContextForTest(tc), f, arg) 351 if err != nil { 352 t.Fatal(err) 353 } 354 if res.Plaintext != expectedBytes32 { 355 t.Errorf("UnboxBytes32Any plaintext: %x, expected %x", res.Plaintext, expectedBytes32) 356 } 357 if res.Kid.IsNil() { 358 t.Errorf("UnboxBytes32Any kid is nil") 359 } 360 361 // clear the paper key cache to test getting a paper key via UI 362 clearCaches(tc.G) 363 if err != nil { 364 t.Fatal(err) 365 } 366 367 f = func() libkb.SecretUI { 368 // set the passphrase in the secretUI to the paper key 369 secretUI := u.NewSecretUI() 370 secretUI.Passphrase = peng.Passphrase() 371 return secretUI 372 } 373 374 res, err = UnboxBytes32Any(NewMetaContextForTest(tc), f, arg) 375 if err != nil { 376 t.Fatal(err) 377 } 378 if res.Plaintext != expectedBytes32 { 379 t.Errorf("UnboxBytes32Any plaintext: %x, expected %x", res.Plaintext, expectedBytes32) 380 } 381 if res.Kid.IsNil() { 382 t.Errorf("UnboxBytes32Any kid is nil") 383 } 384 }