github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/libkb/naclwrap_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 libkb 5 6 import ( 7 "encoding/base64" 8 "encoding/hex" 9 "testing" 10 11 "github.com/keybase/client/go/kbcrypto" 12 "github.com/stretchr/testify/require" 13 ) 14 15 // Test that VerifyString accepts the output of SignToString. 16 func TestVerifyStringAccept(t *testing.T) { 17 keyPair, err := GenerateNaclSigningKeyPair() 18 if err != nil { 19 t.Fatal(err) 20 } 21 22 t.Logf("keyPair: Public: %+v, Private: %+v", keyPair.Public, keyPair.Private) 23 24 msg := []byte("test message") 25 sig, _, err := keyPair.SignToString(msg) 26 if err != nil { 27 t.Fatal(err) 28 } 29 30 t.Logf("sig: %+v", sig) 31 32 _, err = keyPair.VerifyString(nil, sig, msg) 33 if err != nil { 34 t.Error(err) 35 } 36 } 37 38 // Test that VerifyString rejects various types of bad signatures. 39 func TestVerifyStringReject(t *testing.T) { 40 keyPair, err := GenerateNaclSigningKeyPair() 41 if err != nil { 42 t.Fatal(err) 43 } 44 45 msg := []byte("test message") 46 sig, _, err := keyPair.SignToString(msg) 47 if err != nil { 48 t.Fatal(err) 49 } 50 51 // Corrupt signature. 52 53 sigBytes, err := base64.StdEncoding.DecodeString(sig) 54 if err != nil { 55 t.Fatal(err) 56 } 57 58 _, err = keyPair.VerifyString(nil, base64.StdEncoding.EncodeToString(append(sigBytes, []byte("corruption")...)), msg) 59 if err == nil { 60 t.Error("Corrupt signature unexpectedly passes") 61 } 62 63 // Corrupt message. 64 65 _, err = keyPair.VerifyString(nil, sig, append(msg, []byte("corruption")...)) 66 if err == nil { 67 t.Error("Signature for corrupt message unexpectedly passes") 68 } 69 70 // Signature with different key. 71 72 keyPair2, err := GenerateNaclSigningKeyPair() 73 if err != nil { 74 t.Fatal(err) 75 } 76 77 sig2, _, err := keyPair2.SignToString(msg) 78 if err != nil { 79 t.Fatal(err) 80 } 81 82 _, err = keyPair.VerifyString(nil, sig2, msg) 83 if err == nil { 84 t.Error("Signature with different key unexpectedly passes") 85 } 86 87 // Append different signature. 88 89 _, err = keyPair.VerifyString(nil, sig+sig2, msg) 90 if err == nil { 91 t.Error("Signature with appended different signature unexpectedly passes") 92 } 93 94 // Prepend invalid signature. 95 96 _, err = keyPair.VerifyString(nil, sig2+sig, msg) 97 if err == nil { 98 t.Error("Signature with prepended invalid signature unexpectedly passes") 99 } 100 } 101 102 // Test that VerifyBytes accepts the output of SignToBytes. 103 func TestVerifyBytesAccept(t *testing.T) { 104 keyPair, err := GenerateNaclSigningKeyPair() 105 if err != nil { 106 t.Fatal(err) 107 } 108 109 msg := []byte("test message") 110 sig := keyPair.Private.Sign(msg) 111 if !keyPair.Public.Verify(msg, sig) { 112 t.Error(kbcrypto.VerificationError{}) 113 } 114 } 115 116 // Test that VerifyBytes rejects various types of bad signatures. 117 func TestVerifyBytesReject(t *testing.T) { 118 keyPair, err := GenerateNaclSigningKeyPair() 119 if err != nil { 120 t.Fatal(err) 121 } 122 123 msg := []byte("test message") 124 sig := keyPair.Private.Sign(msg) 125 126 // Corrupt signature. 127 128 var corruptSig kbcrypto.NaclSignature 129 copy(corruptSig[:], sig[:]) 130 corruptSig[0] = ^sig[0] 131 if keyPair.Public.Verify(msg, corruptSig) { 132 t.Error("Corrupt signature unexpectedly passes") 133 } 134 135 // Corrupt message. 136 137 corruptMsg := msg 138 corruptMsg = append(corruptMsg, []byte("corruption")...) 139 if keyPair.Public.Verify(corruptMsg, sig) { 140 t.Error("Signature for corrupt message unexpectedly passes") 141 } 142 143 // Signature with different key. 144 145 keyPair2, err := GenerateNaclSigningKeyPair() 146 if err != nil { 147 t.Fatal(err) 148 } 149 150 sig2 := keyPair2.Private.Sign(msg) 151 if keyPair.Public.Verify(msg, sig2) { 152 t.Error("Signature with different key unexpectedly passes") 153 } 154 } 155 156 func TestNaclEncryptEphemeral(t *testing.T) { 157 keyPair, err := GenerateNaclDHKeyPair() 158 if err != nil { 159 t.Fatal(err) 160 } 161 msg := []byte("Man hands on misery to man. It deepens like a coastal shelf.") 162 ctext, err := keyPair.EncryptToString(msg, nil) 163 if err != nil { 164 t.Fatalf("encrypt error: %s", err) 165 } 166 out, kid, err := keyPair.DecryptFromString(ctext) 167 if err != nil { 168 t.Fatalf("decrypt error: %s", err) 169 } 170 if !FastByteArrayEq(out, msg) { 171 t.Errorf("Message mismatch: %s != %s", msg, out) 172 } 173 if kid.Equal(keyPair.GetKID()) { 174 t.Error("KID should be an ephemeral key, not ours") 175 } 176 } 177 178 func TestNaclEncryptKnown(t *testing.T) { 179 recvr, err := GenerateNaclDHKeyPair() 180 if err != nil { 181 t.Fatal(err) 182 } 183 sender, err := GenerateNaclDHKeyPair() 184 if err != nil { 185 t.Fatal(err) 186 } 187 msg := []byte("Man hands on misery to man. It deepens like a coastal shelf.") 188 ctext, err := recvr.EncryptToString(msg, &sender) 189 if err != nil { 190 t.Fatal(err) 191 } 192 out, kid, err := recvr.DecryptFromString(ctext) 193 if err != nil { 194 t.Fatal(err) 195 } 196 if !FastByteArrayEq(out, msg) { 197 t.Errorf("Message mismatch: %s != %s", msg, out) 198 } 199 if kid.NotEqual(sender.GetKID()) { 200 t.Error("KID mismatch for sender") 201 } 202 } 203 204 func TestNaclDecryptFromIced(t *testing.T) { 205 seed := "b26ba6f6865b28f9332620c73c2984e2d2a8a83ef5eb59ca47d3b70cfa9f222f" 206 ctext := "g6Rib2R5hapjaXBoZXJ0ZXh0xEw2dXZRKyUI5wbSfQGSv61xVIl/cpD8hFN+Gsc5LGEtuXmGG1+1rUFv4QWizfLgqhywaitotmApYJv07zFTUT5sxOU+i2er43XQkkwmqGVuY190eXBlIaVub25jZcQY/rYiRGjPmmxurm5PMlhJuJwP9jk7UJIFrHJlY2VpdmVyX2tlecQjASHyQFIJdlHbnV1oT3MKne5ob7Rmf0emMciNbkD1IyfCKgqqc2VuZGVyX2tlecQjASFKiKO16sYJaloJ4URJM+pL6BSYJcz8M/Za2MSrKCvqawqjdGFnzQIDp3ZlcnNpb24B" 207 plaintext := []byte("Man hands on misery to man. It deepens like a coastal shelf.") 208 seedBytes, err := hex.DecodeString(seed) 209 if err != nil { 210 t.Fatal(err) 211 } 212 var secret [32]byte 213 copy(secret[:], seedBytes) 214 key, err := MakeNaclDHKeyPairFromSecret(secret) 215 if err != nil { 216 t.Fatal(err) 217 } 218 219 out, _, err := key.DecryptFromString(ctext) 220 if err != nil { 221 t.Fatal(err) 222 } 223 224 if !FastByteArrayEq(out, plaintext) { 225 t.Error("failed to match plaintext") 226 } 227 } 228 229 // In V2, Nacl sigs are prefixed.... 230 func TestNaclPrefixedSigs(t *testing.T) { 231 232 keyPair, err := GenerateNaclSigningKeyPair() 233 if err != nil { 234 t.Fatal(err) 235 } 236 237 t.Logf("keyPair: Public: %+v, Private: %+v", keyPair.Public, keyPair.Private) 238 239 msg := []byte("test message") 240 241 sig, err := keyPair.SignV2(msg, kbcrypto.SignaturePrefixChatMBv1) 242 if err != nil { 243 t.Fatal(err) 244 } 245 246 _, err = sig.Verify() 247 if err != nil { 248 t.Fatal(err) 249 } 250 251 sig.Version = 1 252 _, err = sig.Verify() 253 if err == nil { 254 t.Fatal("expected an error after we jiggled the version to 1") 255 } 256 if _, ok := err.(kbcrypto.VerificationError); !ok { 257 t.Fatal("expected a VerificationError") 258 } 259 260 sig.Version = 2 261 sig.Prefix = kbcrypto.SignaturePrefixKBFS 262 _, err = sig.Verify() 263 if err == nil { 264 t.Fatal("expected an error after we jiggled the prefix to the wrong one") 265 } 266 if _, ok := err.(kbcrypto.VerificationError); !ok { 267 t.Fatal("expected a VerificationError") 268 } 269 270 _, err = keyPair.SignV2(msg, kbcrypto.SignaturePrefix("a\x00b")) 271 if err == nil { 272 t.Fatal("expected a BadSignaturePrefixError") 273 } 274 if _, ok := err.(kbcrypto.BadSignaturePrefixError); !ok { 275 t.Fatal("expected a BadSignaturePrefixError") 276 } 277 _, err = keyPair.SignV2(msg, kbcrypto.SignaturePrefix("")) 278 if err == nil { 279 t.Fatal("expected a BadSignaturePrefixError") 280 } 281 if _, ok := err.(kbcrypto.BadSignaturePrefixError); !ok { 282 t.Fatal("expected a BadSignaturePrefixError") 283 } 284 } 285 286 func TestNaclBadPrefix(t *testing.T) { 287 keyPair, err := GenerateNaclSigningKeyPair() 288 if err != nil { 289 t.Fatal(err) 290 } 291 292 t.Logf("keyPair: Public: %+v, Private: %+v", keyPair.Public, keyPair.Private) 293 294 msg := []byte("test message") 295 296 sig, err := keyPair.Sign(append([]byte("AA\x00"), msg...)) 297 if err != nil { 298 t.Fatal(err) 299 } 300 sig.Version = 2 301 sig.Prefix = kbcrypto.SignaturePrefix("AA") 302 sig.Payload = msg 303 _, err = sig.Verify() 304 if err == nil { 305 t.Fatal("expected a signature verification error") 306 } 307 } 308 309 func TestDeriveSymmetricKeyFromAsymmetricTooShort(t *testing.T) { 310 key1 := generateNaclDHKeyPrivate(t) 311 _, err := deriveSymmetricKeyFromAsymmetric(key1, EncryptionReason("x")) 312 require.Error(t, err, "should error with short reason") 313 require.Contains(t, err.Error(), "must be at least 8 bytes") 314 } 315 316 func TestDeriveSymmetricKeyFromAsymmetricDifferentEquality(t *testing.T) { 317 key1 := generateNaclDHKeyPrivate(t) 318 319 key2, err := deriveSymmetricKeyFromAsymmetric(key1, EncryptionReasonChatLocalStorage) 320 require.NoError(t, err) 321 322 key2_2, err := deriveSymmetricKeyFromAsymmetric(key1, EncryptionReasonChatLocalStorage) 323 require.NoError(t, err) 324 325 key3, err := deriveSymmetricKeyFromAsymmetric(key1, EncryptionReasonChatMessage) 326 require.NoError(t, err) 327 328 require.NotEqual(t, key1, key2, "derived key must be different from original") 329 require.NotEqual(t, key2, key3, "derived keys must differ") 330 require.Equal(t, key2, key2_2, "two derivations must be equivalent") 331 } 332 333 func TestDeriveSymmetricKeyFromAsymmetricKnown(t *testing.T) { 334 bs, err := hex.DecodeString( 335 "aaba52a997cfa11b704c7272e986ad337c8b327baa4265fb024147c97e7b672f") 336 require.NoError(t, err) 337 var key1 NaclDHKeyPrivate 338 require.Equal(t, NaclSecretBoxKeySize, copy(key1[:], bs)) 339 340 key2, err := deriveSymmetricKeyFromAsymmetric(key1, EncryptionReason("testing-testing")) 341 require.NoError(t, err) 342 343 expected := "a637302de8593ca06d652c3dc8df15ae5eecc89f25718a367f24b28decaa916e" 344 require.Equal(t, expected, hex.EncodeToString(key2[:])) 345 } 346 347 func TestDeriveSymmetricKeyTooShort(t *testing.T) { 348 key1 := generateNaclSecretboxKey(t) 349 _, err := DeriveSymmetricKey(key1, EncryptionReason("x")) 350 require.Error(t, err, "should error with short reason") 351 require.Contains(t, err.Error(), "must be at least 8 bytes") 352 } 353 354 func TestDeriveSymmetricKeyDifferentEquality(t *testing.T) { 355 key1 := generateNaclSecretboxKey(t) 356 357 key2, err := DeriveSymmetricKey(key1, EncryptionReasonChatLocalStorage) 358 require.NoError(t, err) 359 360 key2_2, err := DeriveSymmetricKey(key1, EncryptionReasonChatLocalStorage) 361 require.NoError(t, err) 362 363 key3, err := DeriveSymmetricKey(key1, EncryptionReasonChatMessage) 364 require.NoError(t, err) 365 366 require.NotEqual(t, key1, key2, "derived key must be different from original") 367 require.NotEqual(t, key2, key3, "derived keys must differ") 368 require.Equal(t, key2, key2_2, "two derivations must be equivalent") 369 } 370 371 func TestDeriveSymmetricKeyKnown(t *testing.T) { 372 bs, err := hex.DecodeString( 373 "aaba52a997cfa11b704c7272e986ad337c8b327baa4265fb024147c97e7b672f") 374 require.NoError(t, err) 375 var key1 NaclSecretBoxKey 376 require.Equal(t, NaclSecretBoxKeySize, copy(key1[:], bs)) 377 378 key2, err := DeriveSymmetricKey(key1, EncryptionReason("testing-testing")) 379 require.NoError(t, err) 380 381 expected := "b72ed915c99394c24fc609f9eb794e032580d99c5dbb4f3505f8a6fc8fc6b22b" 382 require.Equal(t, expected, hex.EncodeToString(key2[:])) 383 } 384 385 func generateNaclDHKeyPrivate(t *testing.T) NaclDHKeyPrivate { 386 keyPair, err := GenerateNaclDHKeyPair() 387 require.NoError(t, err, "generating key") 388 return *keyPair.Private 389 } 390 391 func generateNaclSecretboxKey(t *testing.T) NaclSecretBoxKey { 392 return NaclSecretBoxKey(generateNaclDHKeyPrivate(t)) 393 }