xref: /aosp_15_r20/external/tink/go/prf/subtle/hkdf_test.go (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1// Copyright 2020 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////////////////////////////////////////////////////////////////////////////////
16
17package subtle_test
18
19import (
20	"bytes"
21	"encoding/hex"
22	"fmt"
23	"strings"
24	"testing"
25
26	"github.com/google/tink/go/prf/subtle"
27	"github.com/google/tink/go/testutil"
28)
29
30type rfc5869test struct {
31	hash         string
32	key          string
33	salt         string
34	info         string
35	outputLength uint32
36	okm          string
37}
38
39func TestVectorsRFC5869(t *testing.T) {
40	// Test vectors from RFC 5869.
41	testvectors := []*rfc5869test{
42		{
43			hash:         "SHA256",
44			key:          "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
45			salt:         "000102030405060708090a0b0c",
46			info:         "f0f1f2f3f4f5f6f7f8f9",
47			outputLength: 42,
48			okm:          "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865",
49		},
50		{
51			hash:         "SHA256",
52			key:          "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f",
53			salt:         "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
54			info:         "b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
55			outputLength: 82,
56			okm:          "b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87",
57		},
58		{
59			hash:         "SHA256",
60			key:          "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
61			salt:         "",
62			info:         "",
63			outputLength: 42,
64			okm:          "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8",
65		},
66		{
67			hash:         "SHA1",
68			key:          "0b0b0b0b0b0b0b0b0b0b0b",
69			salt:         "000102030405060708090a0b0c",
70			info:         "f0f1f2f3f4f5f6f7f8f9",
71			outputLength: 42,
72			okm:          "085a01ea1b10f36933068b56efa5ad81a4f14b822f5b091568a9cdd4f155fda2c22e422478d305f3f896",
73		},
74		{
75			hash:         "SHA1",
76			key:          "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f",
77			salt:         "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
78			info:         "b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
79			outputLength: 82,
80			okm:          "0bd770a74d1160f7c9f12cd5912a06ebff6adcae899d92191fe4305673ba2ffe8fa3f1a4e5ad79f3f334b3b202b2173c486ea37ce3d397ed034c7f9dfeb15c5e927336d0441f4c4300e2cff0d0900b52d3b4",
81		},
82		{
83			hash:         "SHA1",
84			key:          "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
85			salt:         "",
86			info:         "",
87			outputLength: 42,
88			okm:          "0ac1af7002b3d761d1e55298da9d0506b9ae52057220a306e07b6b87e8df21d0ea00033de03984d34918",
89		},
90		{
91			hash:         "SHA1",
92			key:          "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c",
93			salt:         "",
94			info:         "",
95			outputLength: 42,
96			okm:          "2c91117204d745f3500d636a62f64f0ab3bae548aa53d423b0d1f27ebba6f5e5673a081d70cce7acfc48",
97		},
98	}
99	for _, v := range testvectors {
100		key, err := hex.DecodeString(v.key)
101		if err != nil {
102			t.Errorf("Could not decode key: %v", err)
103		}
104		salt, err := hex.DecodeString(v.salt)
105		if err != nil {
106			t.Errorf("Could not decode salt: %v", err)
107		}
108		info, err := hex.DecodeString(v.info)
109		if err != nil {
110			t.Errorf("Could not decode info: %v", err)
111		}
112		p, err := subtle.NewHKDFPRF(v.hash, key, salt)
113		if err != nil {
114			t.Errorf("Could not create HKDF object: %v", err)
115		}
116		output, err := p.ComputePRF(info, v.outputLength)
117		if err != nil {
118			t.Errorf("Error computing HKDF: %v", err)
119		}
120		if hex.EncodeToString(output) != v.okm {
121			t.Errorf("Computation and test vector differ. Computation: %q, Test Vector %q", hex.EncodeToString(output), v.okm)
122		}
123	}
124}
125
126func TestHKDFPRFWycheproofCases(t *testing.T) {
127	testutil.SkipTestIfTestSrcDirIsNotSet(t)
128	for _, hash := range []string{"SHA1", "SHA256", "SHA512"} {
129		filename := fmt.Sprintf("hkdf_%s_test.json", strings.ToLower(hash))
130		suite := new(hkdfSuite)
131		if err := testutil.PopulateSuite(suite, filename); err != nil {
132			t.Fatalf("Failed populating suite: %s", err)
133		}
134		for _, group := range suite.TestGroups {
135			for _, test := range group.Tests {
136				caseName := fmt.Sprintf("%s-%s-%s(%d):Case-%d", suite.Algorithm, group.Type, hash, group.KeySize, test.CaseID)
137				t.Run(caseName, func(t *testing.T) {
138					if uint32(len(test.IKM))*8 != group.KeySize {
139						t.Fatal("Invalid key length")
140					}
141
142					hkdfPRF, err := subtle.NewHKDFPRF(hash, test.IKM, test.Salt)
143					switch test.Result {
144					case "valid":
145						if err != nil {
146							t.Fatalf("NewHKDFPRF failed: %v", err)
147						}
148						res, err := hkdfPRF.ComputePRF(test.Info, test.Size)
149						if err != nil {
150							t.Fatalf("ComputePRF() failed: %v", err)
151						}
152						if !bytes.Equal(res, test.OKM) {
153							t.Errorf("ComputePRF() result and expected result do not match:\nComputed: %q\nExpected: %q", hex.EncodeToString(res), test.OKM)
154						}
155
156					case "invalid":
157						if err != nil {
158							return
159						}
160						res, err := hkdfPRF.ComputePRF(test.Info, test.Size)
161						if err != nil {
162							return
163						}
164						if bytes.Equal(res, test.OKM) {
165							t.Errorf("ComputePRF() result and invalid expected result match:\nComputed: %q\nExpected: %q", hex.EncodeToString(res), test.OKM)
166						}
167
168					default:
169						t.Fatalf("Unsupported test result: %q", test.Result)
170					}
171				})
172			}
173		}
174	}
175}
176
177func TestHKDFPRFHash(t *testing.T) {
178	if _, err := subtle.NewHKDFPRF("SHA256", []byte{
179		0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
180		0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}, []byte{}); err != nil {
181		t.Errorf("Expected NewHKDFPRF to work with SHA256: %v", err)
182	}
183	if _, err := subtle.NewHKDFPRF("SHA512", []byte{
184		0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
185		0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}, []byte{}); err != nil {
186		t.Errorf("Expected NewHKDFPRF to work with SHA512: %v", err)
187	}
188	if _, err := subtle.NewHKDFPRF("SHA1", []byte{
189		0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
190		0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}, []byte{}); err != nil {
191		t.Errorf("Expected NewHKDFPRF to work with SHA1: %v", err)
192	}
193	if _, err := subtle.NewHKDFPRF("md5", []byte{
194		0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
195		0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}, []byte{}); err == nil {
196		t.Errorf("Expected NewHKDFPRF to fail with md5")
197	}
198}
199
200func TestHKDFPRFSalt(t *testing.T) {
201	if _, err := subtle.NewHKDFPRF("SHA256", []byte{
202		0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
203		0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}, nil); err != nil {
204		t.Errorf("Expected NewHKDFPRF to work nil salt: %v", err)
205	}
206	if _, err := subtle.NewHKDFPRF("SHA256", []byte{
207		0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
208		0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}, []byte{}); err != nil {
209		t.Errorf("Expected NewHKDFPRF to work empty salt: %v", err)
210	}
211	if _, err := subtle.NewHKDFPRF("SHA256", []byte{
212		0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
213		0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}, []byte{0xaf, 0xfe, 0xc0, 0xff, 0xee}); err != nil {
214		t.Errorf("Expected NewHKDFPRF to work with salt: %v", err)
215	}
216}
217
218func TestHKDFPRFOutputLength(t *testing.T) {
219	for hash, length := range map[string]int{"SHA1": 20, "SHA256": 32, "SHA512": 64} {
220		prf, err := subtle.NewHKDFPRF(hash, []byte{
221			0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
222			0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
223			0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
224			0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}, []byte{})
225		if err != nil {
226			t.Errorf("Expected NewHKDFPRF to work on 32 byte key with hash %s", hash)
227		}
228		for i := 0; i <= length*255; i++ {
229			output, err := prf.ComputePRF([]byte{0x01, 0x02}, uint32(i))
230			if err != nil {
231				t.Errorf("Expected to be able to compute HKDF %s PRF with %d output length", hash, i)
232			}
233			if len(output) != i {
234				t.Errorf("Expected HKDF %s PRF to compute %d bytes, got %d", hash, i, len(output))
235			}
236		}
237		for i := length*255 + 1; i < length*255+100; i++ {
238			_, err := prf.ComputePRF([]byte{0x01, 0x02}, uint32(i))
239			if err == nil {
240				t.Errorf("Expected to not be able to compute HKDF %s PRF with %d output length", hash, i)
241			}
242		}
243	}
244}
245
246func TestValidateHKDFPRFParams(t *testing.T) {
247	if err := subtle.ValidateHKDFPRFParams("SHA256", 32, []byte{}); err != nil {
248		t.Errorf("Unexpected error for valid HKDF PRF params: %v", err)
249	}
250	if err := subtle.ValidateHKDFPRFParams("SHA256", 32, nil); err != nil {
251		t.Errorf("Unexpected error for valid HKDF PRF params: %v", err)
252	}
253	if err := subtle.ValidateHKDFPRFParams("SHA256", 32, []byte{0xaf, 0xfe, 0xc0, 0xff, 0xee}); err != nil {
254		t.Errorf("Unexpected error for salted valid HKDF PRF params: %v", err)
255	}
256	if err := subtle.ValidateHKDFPRFParams("SHA256", 4, []byte{}); err == nil {
257		t.Errorf("Short key size not detected for HKDF PRF params")
258	}
259	if err := subtle.ValidateHKDFPRFParams("md5", 32, []byte{}); err == nil {
260		t.Errorf("Weak hash function not detected for HKDF PRF params")
261	}
262	if err := subtle.ValidateHKDFPRFParams("SHA1", 32, []byte{}); err == nil {
263		t.Errorf("Weak hash function not detected for HKDF PRF params")
264	}
265}
266