github.com/google/osv-scalibr@v0.4.1/detector/weakcredentials/winlocal/samreg/crypto_test.go (about)

     1  // Copyright 2025 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package samreg
    16  
    17  import (
    18  	"slices"
    19  	"strings"
    20  	"testing"
    21  )
    22  
    23  func TestDecryptRC4Hash(t *testing.T) {
    24  	tests := []struct {
    25  		name         string
    26  		rid          []byte
    27  		syskey       []byte
    28  		hash         []byte
    29  		hashConstant []byte
    30  		want         []byte
    31  		wantErr      bool
    32  		wantErrText  string
    33  	}{
    34  		{
    35  			name:         "valid_input_decrypts",
    36  			rid:          []byte("\xf4\x01\x00\x00"),
    37  			syskey:       []byte("\x3d\x21\x2c\xe8\xa2\xda\x83\x43\xbd\xad\x1e\xf2\xcf\xb6\xb3\x1c"),
    38  			hash:         []byte("\xed\x92\x87\x92\x78\x3b\x69\x2c\x21\x37\x49\xbc\xdb\xe3\x1a\xf5"),
    39  			hashConstant: []byte("\x4e\x54\x50\x41\x53\x53\x57\x4f\x52\x44\x00"),
    40  			want:         []byte("\x58\xa4\x78\x13\x5a\x93\xac\x3b\xf0\x58\xa5\xea\x0e\x8f\xdb\x71"),
    41  		},
    42  		{
    43  			name:         "RID_too_short_returns_error",
    44  			rid:          []byte(""),
    45  			syskey:       []byte("\x3d\x21\x2c\xe8\xa2\xda\x83\x43\xbd\xad\x1e\xf2\xcf\xb6\xb3\x1c"),
    46  			hash:         []byte("\xed\x92\x87\x92\x78\x3b\x69\x2c\x21\x37\x49\xbc\xdb\xe3\x1a\xf5"),
    47  			hashConstant: []byte("\x4e\x54\x50\x41\x53\x53\x57\x4f\x52\x44\x00"),
    48  			wantErr:      true,
    49  			wantErrText:  errInvalidRIDSize.Error(),
    50  		},
    51  	}
    52  
    53  	for _, tc := range tests {
    54  		t.Run(tc.name, func(t *testing.T) {
    55  			hash, err := decryptRC4Hash(tc.rid, tc.syskey, tc.hash, tc.hashConstant)
    56  			if (err != nil) != tc.wantErr {
    57  				t.Errorf("decryptRC4Hash(...): unexpected error: %v", err)
    58  			}
    59  
    60  			if tc.wantErr {
    61  				if !strings.Contains(err.Error(), tc.wantErrText) {
    62  					t.Errorf("decryptRC4Hash(...): unexpected error, got: %v, want: %v", err, tc.wantErrText)
    63  				}
    64  
    65  				return
    66  			}
    67  
    68  			if !slices.Equal(hash, tc.want) {
    69  				t.Errorf("decryptRC4Hash(...): unexpected result, got: %v, want: %v", hash, tc.want)
    70  			}
    71  		})
    72  	}
    73  }
    74  
    75  func TestDecryptAESHash(t *testing.T) {
    76  	tests := []struct {
    77  		name        string
    78  		rid         []byte
    79  		syskey      []byte
    80  		hash        []byte
    81  		salt        []byte
    82  		want        []byte
    83  		wantErr     bool
    84  		wantErrText string
    85  	}{
    86  		{
    87  			name:   "valid_input_decrypts",
    88  			rid:    []byte("\xf4\x01\x00\x00"),
    89  			syskey: []byte("\xfc\xde\xe8\x3a\xc6\xc1\x4b\x28\xf5\x26\x50\x1f\xc6\xe8\xbb\xc3"),
    90  			hash:   []byte("\x48\xf2\xb6\x8b\xd9\x06\xa2\xbd\xb2\xaf\x39\x1c\xe2\x60\x44\x56\x6b\x80\x62\xb6\x55\xf4\x2b\x05\x9d\xfb\x5c\x68\x55\x4a\x5b\xc3"),
    91  			salt:   []byte("\xa3\x28\x48\xec\x7d\x73\x12\xec\x81\xeb\x50\xd0\x65\x09\x55\xd4"),
    92  			want:   []byte("\x58\xa4\x78\x13\x5a\x93\xac\x3b\xf0\x58\xa5\xea\x0e\x8f\xdb\x71"),
    93  		},
    94  		{
    95  			name:   "empty_hash_returns_empty",
    96  			rid:    []byte("\xf4\x01\x00\x00"),
    97  			syskey: []byte("\xfc\xde\xe8\x3a\xc6\xc1\x4b\x28\xf5\x26\x50\x1f\xc6\xe8\xbb\xc3"),
    98  			hash:   []byte(""),
    99  			salt:   []byte("\xa3\x28\x48\xec\x7d\x73\x12\xec\x81\xeb\x50\xd0\x65\x09\x55\xd4"),
   100  			want:   []byte(""),
   101  		},
   102  		{
   103  			name:        "empty_syskey_returns_error",
   104  			rid:         []byte(""),
   105  			syskey:      []byte(""),
   106  			hash:        []byte("\x00"),
   107  			wantErr:     true,
   108  			wantErrText: "hash length not aligned with AES block size",
   109  		},
   110  		{
   111  			name:        "RID_too_short_returns_error",
   112  			rid:         []byte(""),
   113  			syskey:      []byte("\xfc\xde\xe8\x3a\xc6\xc1\x4b\x28\xf5\x26\x50\x1f\xc6\xe8\xbb\xc3"),
   114  			hash:        []byte("\x48\xf2\xb6\x8b\xd9\x06\xa2\xbd\xb2\xaf\x39\x1c\xe2\x60\x44\x56\x6b\x80\x62\xb6\x55\xf4\x2b\x05\x9d\xfb\x5c\x68\x55\x4a\x5b\xc3"),
   115  			salt:        []byte("\xa3\x28\x48\xec\x7d\x73\x12\xec\x81\xeb\x50\xd0\x65\x09\x55\xd4"),
   116  			wantErr:     true,
   117  			wantErrText: errInvalidRIDSize.Error(),
   118  		},
   119  	}
   120  
   121  	for _, tc := range tests {
   122  		t.Run(tc.name, func(t *testing.T) {
   123  			hash, err := decryptAESHash(tc.rid, tc.syskey, tc.hash, tc.salt)
   124  			if (err != nil) != tc.wantErr {
   125  				t.Errorf("decryptAESHash(...): unexpected error: %v", err)
   126  			}
   127  
   128  			if tc.wantErr {
   129  				if !strings.Contains(err.Error(), tc.wantErrText) {
   130  					t.Errorf("decryptAESHash(...): unexpected error, got: %v, want: %v", err, tc.wantErrText)
   131  				}
   132  
   133  				return
   134  			}
   135  
   136  			if !slices.Equal(hash, tc.want) {
   137  				t.Errorf("decryptAESHash(...): unexpected result, got: %v, want: %v", hash, tc.want)
   138  			}
   139  		})
   140  	}
   141  }