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  }