github.com/trustbloc/kms-go@v1.1.2/secretlock/local/masterlock/pbkdf2/master_secret_lock_test.go (about)

     1  /*
     2  Copyright SecureKey Technologies Inc. All Rights Reserved.
     3  SPDX-License-Identifier: Apache-2.0
     4  */
     5  
     6  package pbkdf2
     7  
     8  import (
     9  	"crypto/rand"
    10  	"crypto/sha256"
    11  	"crypto/sha512"
    12  	"hash"
    13  	"testing"
    14  
    15  	"github.com/google/tink/go/subtle/random"
    16  	"github.com/stretchr/testify/require"
    17  
    18  	"github.com/trustbloc/kms-go/spi/secretlock"
    19  )
    20  
    21  func TestMasterLock(t *testing.T) {
    22  	keySize := sha256.New().Size()
    23  	testKey := random.GetRandomBytes(uint32(keySize))
    24  	goodPassphrase := "somepassphrase"
    25  	defIter := 4096
    26  
    27  	salt := make([]byte, keySize)
    28  	_, err := rand.Read(salt)
    29  	require.NoError(t, err)
    30  
    31  	mkLock, err := NewMasterLock(goodPassphrase, sha256.New, defIter, salt)
    32  	require.NoError(t, err)
    33  
    34  	// try to create a bad master key lock (unsupported hash)
    35  	mkLockBad, err := NewMasterLock(goodPassphrase, sha512.New, defIter, salt)
    36  	require.Error(t, err)
    37  	require.Empty(t, mkLockBad)
    38  
    39  	encryptedMk, err := mkLock.Encrypt("", &secretlock.EncryptRequest{Plaintext: string(testKey)})
    40  	require.NoError(t, err)
    41  	require.NotEmpty(t, encryptedMk)
    42  
    43  	decryptedMk, err := mkLock.Decrypt("", &secretlock.DecryptRequest{Ciphertext: encryptedMk.Ciphertext})
    44  	require.NoError(t, err)
    45  	require.Equal(t, testKey, []byte(decryptedMk.Plaintext))
    46  
    47  	// try decrypting a non valid base64URL string
    48  	decryptedMk, err = mkLock.Decrypt("", &secretlock.DecryptRequest{Ciphertext: "bad{}base64URLstring[]"})
    49  	require.Error(t, err)
    50  	require.Empty(t, decryptedMk)
    51  
    52  	// create a new lock instance with the same passphrase, hash, salt
    53  	mkLock2, err := NewMasterLock(goodPassphrase, sha256.New, defIter, salt)
    54  	require.NoError(t, err)
    55  
    56  	// ensure Decrypt() is successful and returns the same result as the original lock
    57  	decryptedMk2, err := mkLock2.Decrypt("", &secretlock.DecryptRequest{Ciphertext: encryptedMk.Ciphertext})
    58  	require.NoError(t, err)
    59  	require.Equal(t, testKey, []byte(decryptedMk2.Plaintext))
    60  
    61  	// recreate new lock with empty salt
    62  	mkLock2, err = NewMasterLock(goodPassphrase, sha256.New, defIter, nil)
    63  	require.NoError(t, err)
    64  
    65  	decryptedMk2, err = mkLock2.Decrypt("", &secretlock.DecryptRequest{Ciphertext: encryptedMk.Ciphertext})
    66  	require.Error(t, err)
    67  	require.Empty(t, decryptedMk2)
    68  
    69  	// recreate new lock with a different salt
    70  	salt2 := make([]byte, keySize)
    71  	_, err = rand.Read(salt2)
    72  	require.NoError(t, err)
    73  
    74  	mkLock2, err = NewMasterLock(goodPassphrase, sha256.New, defIter, salt2)
    75  	require.NoError(t, err)
    76  
    77  	decryptedMk2, err = mkLock2.Decrypt("", &secretlock.DecryptRequest{Ciphertext: encryptedMk.Ciphertext})
    78  	require.Error(t, err)
    79  	require.Empty(t, decryptedMk2)
    80  
    81  	// try with a bad passhrase
    82  	mkLock2, err = NewMasterLock("badPassphrase", sha256.New, defIter, salt)
    83  	require.NoError(t, err)
    84  
    85  	decryptedMk2, err = mkLock2.Decrypt("", &secretlock.DecryptRequest{Ciphertext: encryptedMk.Ciphertext})
    86  	require.Error(t, err)
    87  	require.Empty(t, decryptedMk2)
    88  
    89  	// try creating a lock with a nil hash
    90  	mkLock2, err = NewMasterLock(goodPassphrase, nil, defIter, salt)
    91  	require.Error(t, err)
    92  	require.Empty(t, mkLock2)
    93  
    94  	// try creating a lock with an empty passphrase
    95  	mkLock2, err = NewMasterLock("", sha256.New, defIter, salt)
    96  	require.Error(t, err)
    97  	require.Empty(t, mkLock2)
    98  }
    99  
   100  func benchmark(b *testing.B, h func() hash.Hash, iter int) {
   101  	b.Helper()
   102  
   103  	var (
   104  		sink uint8
   105  		lck  secretlock.Service
   106  	)
   107  
   108  	password := "somepassphrase"
   109  	salt := make([]byte, h().Size())
   110  	_, err := rand.Read(salt)
   111  	require.NoError(b, err)
   112  
   113  	b.ResetTimer()
   114  
   115  	for i := 0; i < b.N; i++ {
   116  		lck, err = NewMasterLock(password, h, iter, salt)
   117  		require.NoError(b, err)
   118  
   119  		mlck, ok := lck.(*masterLockPBKDF2)
   120  		require.True(b, ok)
   121  
   122  		sink += uint8(mlck.aead.Overhead())
   123  	}
   124  
   125  	MajorSink = sink
   126  }
   127  
   128  // nolint:gochecknoglobals // needed to avoid Go compiler perf optimizations for benchmarks (avoid optimize loop body).
   129  var MajorSink uint8
   130  
   131  func BenchmarkHMACSHA256_4k(b *testing.B) {
   132  	benchmark(b, sha256.New, 4096)
   133  }
   134  
   135  func BenchmarkHMACSHA256_8k(b *testing.B) {
   136  	benchmark(b, sha256.New, 8192)
   137  }
   138  
   139  func BenchmarkHMACSHA256_64k(b *testing.B) {
   140  	benchmark(b, sha256.New, 65536)
   141  }