github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/kbfshash/hash_test.go (about)

     1  // Copyright 2016 Keybase Inc. All rights reserved.
     2  // Use of this source code is governed by a BSD
     3  // license that can be found in the LICENSE file.
     4  
     5  package kbfshash
     6  
     7  import (
     8  	"testing"
     9  
    10  	"github.com/keybase/client/go/kbfs/kbfscodec"
    11  	"github.com/pkg/errors"
    12  	"github.com/stretchr/testify/require"
    13  )
    14  
    15  // Make sure Hash encodes and decodes properly with minimal overhead.
    16  func TestHashEncodeDecode(t *testing.T) {
    17  	codec := kbfscodec.NewMsgpack()
    18  	h, err := DefaultHash([]byte{1})
    19  	require.NoError(t, err)
    20  
    21  	encodedH, err := codec.Encode(h)
    22  	require.NoError(t, err)
    23  
    24  	// See
    25  	// https://github.com/msgpack/msgpack/blob/master/spec.md#formats-bin
    26  	// for why there are two bytes of overhead.
    27  	const overhead = 2
    28  	require.Equal(t, DefaultHashByteLength+overhead, len(encodedH))
    29  
    30  	var h2 Hash
    31  	err = codec.Decode(encodedH, &h2)
    32  	require.NoError(t, err)
    33  
    34  	require.Equal(t, h, h2)
    35  }
    36  
    37  // Make sure the zero Hash value encodes and decodes properly.
    38  func TestHashEncodeDecodeZero(t *testing.T) {
    39  	codec := kbfscodec.NewMsgpack()
    40  	encodedH, err := codec.Encode(Hash{})
    41  	require.NoError(t, err)
    42  
    43  	expectedEncodedH := []byte{0xc0}
    44  	require.Equal(t, expectedEncodedH, encodedH)
    45  
    46  	var h Hash
    47  	err = codec.Decode(encodedH, &h)
    48  	require.NoError(t, err)
    49  
    50  	require.Equal(t, Hash{}, h)
    51  }
    52  
    53  // Make sure that default hash gives a valid hash that verifies.
    54  func TestDefaultHash(t *testing.T) {
    55  	data := []byte{1, 2, 3, 4, 5}
    56  	h, err := DefaultHash(data)
    57  	require.NoError(t, err)
    58  
    59  	require.True(t, h.IsValid())
    60  
    61  	err = h.Verify(data)
    62  	require.NoError(t, err)
    63  }
    64  
    65  // hashFromRawNoCheck() is like HashFromRaw() except it doesn't check
    66  // validity.
    67  func hashFromRawNoCheck(hashType HashType, rawHash []byte) Hash {
    68  	return Hash{string(append([]byte{byte(hashType)}, rawHash...))}
    69  }
    70  
    71  // Make sure Hash.IsValid() fails properly.
    72  func TestHashIsValid(t *testing.T) {
    73  	data := []byte{1, 2, 3, 4, 5}
    74  	validH, err := DefaultHash(data)
    75  	require.NoError(t, err)
    76  
    77  	// Zero hash.
    78  	require.False(t, (Hash{}).IsValid())
    79  
    80  	var smallH Hash
    81  	smallH.h = validH.h[:MinHashByteLength-1]
    82  	require.False(t, smallH.IsValid())
    83  
    84  	var largeH Hash
    85  	padding := make([]byte, MaxHashByteLength-len(validH.h)+1)
    86  	largeH.h = string(append([]byte(validH.h), padding...))
    87  	require.False(t, largeH.IsValid())
    88  
    89  	invalidH := hashFromRawNoCheck(InvalidHash, validH.hashData())
    90  	require.False(t, invalidH.IsValid())
    91  
    92  	// A hash with an unknown version is still valid.
    93  	unknownH := hashFromRawNoCheck(validH.hashType()+1, validH.hashData())
    94  	require.True(t, unknownH.IsValid())
    95  }
    96  
    97  // Make sure Hash.Verify() fails properly.
    98  func TestHashVerify(t *testing.T) {
    99  	data := []byte{1, 2, 3, 4, 5}
   100  
   101  	// Zero (invalid) hash.
   102  	err := (Hash{}).Verify(data)
   103  	require.Equal(t, InvalidHashError{Hash{}}, errors.Cause(err))
   104  
   105  	validH, err := DefaultHash(data)
   106  	require.NoError(t, err)
   107  
   108  	corruptData := make([]byte, len(data))
   109  	copy(corruptData, data)
   110  	corruptData[0] ^= 1
   111  	err = validH.Verify(corruptData)
   112  	require.IsType(t, HashMismatchError{}, errors.Cause(err))
   113  
   114  	invalidH := hashFromRawNoCheck(InvalidHash, validH.hashData())
   115  	err = invalidH.Verify(data)
   116  	require.Equal(t, InvalidHashError{invalidH}, errors.Cause(err))
   117  
   118  	// v2 should verify the same way as v1.
   119  	v2ValidH := hashFromRawNoCheck(SHA256HashV2, validH.hashData())
   120  	err = v2ValidH.Verify(data)
   121  	require.NoError(t, err)
   122  
   123  	unknownType := validH.hashType() + 2
   124  	unknownH := hashFromRawNoCheck(unknownType, validH.hashData())
   125  	err = unknownH.Verify(data)
   126  	require.Equal(t, UnknownHashTypeError{unknownType}, errors.Cause(err))
   127  
   128  	hashData := validH.hashData()
   129  	hashData[0] ^= 1
   130  	corruptH := hashFromRawNoCheck(validH.hashType(), hashData)
   131  	err = corruptH.Verify(data)
   132  	require.IsType(t, HashMismatchError{}, errors.Cause(err))
   133  }
   134  
   135  // Make sure HMAC encodes and decodes properly with minimal overhead.
   136  func TestHMACEncodeDecode(t *testing.T) {
   137  	codec := kbfscodec.NewMsgpack()
   138  	hmac, err := DefaultHMAC([]byte{1}, []byte{2})
   139  	require.NoError(t, err)
   140  
   141  	encodedHMAC, err := codec.Encode(hmac)
   142  	require.NoError(t, err)
   143  
   144  	// See
   145  	// https://github.com/msgpack/msgpack/blob/master/spec.md#formats-bin
   146  	// for why there are two bytes of overhead.
   147  	const overhead = 2
   148  	require.Equal(t, DefaultHashByteLength+overhead, len(encodedHMAC))
   149  
   150  	var hmac2 HMAC
   151  	err = codec.Decode(encodedHMAC, &hmac2)
   152  	require.NoError(t, err)
   153  
   154  	require.Equal(t, hmac, hmac2)
   155  }
   156  
   157  // Make sure the zero Hash value encodes and decodes properly.
   158  func TestHMACEncodeDecodeZero(t *testing.T) {
   159  	codec := kbfscodec.NewMsgpack()
   160  	encodedHMAC, err := codec.Encode(HMAC{})
   161  	require.NoError(t, err)
   162  
   163  	expectedEncodedHMAC := []byte{0xc0}
   164  	require.Equal(t, expectedEncodedHMAC, encodedHMAC)
   165  
   166  	var hmac HMAC
   167  	err = codec.Decode(encodedHMAC, &hmac)
   168  	require.NoError(t, err)
   169  
   170  	require.Equal(t, HMAC{}, hmac)
   171  }
   172  
   173  // Make sure that default HMAC gives a valid HMAC that verifies.
   174  func TestDefaultHMAC(t *testing.T) {
   175  	key := []byte{1, 2}
   176  	data := []byte{1, 2, 3, 4, 5}
   177  	hmac, err := DefaultHMAC(key, data)
   178  	require.NoError(t, err)
   179  
   180  	require.True(t, hmac.IsValid())
   181  
   182  	err = hmac.Verify(key, data)
   183  	require.NoError(t, err)
   184  }
   185  
   186  // No need to test HMAC.IsValid().
   187  
   188  // hmacFromRawNoCheck() is like HmacFromRaw() except it doesn't check
   189  // validity.
   190  func hmacFromRawNoCheck(hashType HashType, rawHash []byte) HMAC {
   191  	h := hashFromRawNoCheck(hashType, rawHash)
   192  	return HMAC{h}
   193  }
   194  
   195  // Make sure HMAC.Verify() fails properly.
   196  func TestVerify(t *testing.T) {
   197  	key := []byte{1, 2}
   198  	data := []byte{1, 2, 3, 4, 5}
   199  
   200  	// Zero (invalid) HMAC.
   201  	err := (HMAC{}).Verify(key, data)
   202  	require.Equal(t, InvalidHashError{Hash{}}, errors.Cause(err))
   203  
   204  	validHMAC, err := DefaultHMAC(key, data)
   205  	require.NoError(t, errors.Cause(err))
   206  
   207  	corruptKey := make([]byte, len(key))
   208  	copy(corruptKey, key)
   209  	corruptKey[0] ^= 1
   210  	err = validHMAC.Verify(corruptKey, data)
   211  	require.IsType(t, HashMismatchError{}, errors.Cause(err))
   212  
   213  	corruptData := make([]byte, len(data))
   214  	copy(corruptData, data)
   215  	corruptData[0] ^= 1
   216  	err = validHMAC.Verify(key, corruptData)
   217  	require.IsType(t, HashMismatchError{}, errors.Cause(err))
   218  
   219  	invalidHMAC := hmacFromRawNoCheck(InvalidHash, validHMAC.hashData())
   220  	err = invalidHMAC.Verify(key, data)
   221  	require.Equal(t, InvalidHashError{invalidHMAC.h}, errors.Cause(err))
   222  
   223  	unknownType := validHMAC.hashType() + 1
   224  	unknownHMAC := hmacFromRawNoCheck(unknownType, validHMAC.hashData())
   225  	err = unknownHMAC.Verify(key, data)
   226  	require.Equal(t, UnknownHashTypeError{unknownType}, errors.Cause(err))
   227  
   228  	hashData := validHMAC.hashData()
   229  	hashData[0] ^= 1
   230  	corruptHMAC := hmacFromRawNoCheck(validHMAC.hashType(), hashData)
   231  	err = corruptHMAC.Verify(key, data)
   232  	require.IsType(t, HashMismatchError{}, errors.Cause(err))
   233  }