• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2024 The BoringSSL Authors
2//
3// Permission to use, copy, modify, and/or distribute this software for any
4// purpose with or without fee is hereby granted, provided that the above
5// copyright notice and this permission notice appear in all copies.
6//
7// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
15package subprocess
16
17import (
18	"encoding/hex"
19	"encoding/json"
20	"fmt"
21)
22
23// The following structures reflect the JSON of ACVP PBKDF tests. See
24// https://pages.nist.gov/ACVP/draft-celi-acvp-pbkdf.html#name-test-vectors
25
26type pbkdfTestVectorSet struct {
27	Groups []pbkdfTestGroup `json:"testGroups"`
28	Mode   string           `json:"mode"`
29}
30
31type pbkdfTestGroup struct {
32	ID       uint64 `json:"tgId"`
33	Type     string `json:"testType"`
34	HmacAlgo string `json:"hmacAlg"`
35	Tests    []struct {
36		ID             uint64 `json:"tcId"`
37		KeyLen         uint32 `json:"keyLen,omitempty"`
38		Salt           string `json:"salt,omitempty"`
39		Password       string `json:"password,omitempty"`
40		IterationCount uint32 `json:"iterationCount,omitempty"`
41	} `json:"tests"`
42}
43
44type pbkdfTestGroupResponse struct {
45	ID    uint64              `json:"tgId"`
46	Tests []pbkdfTestResponse `json:"tests"`
47}
48
49type pbkdfTestResponse struct {
50	ID         uint64 `json:"tcId"`
51	DerivedKey string `json:"derivedKey,omitempty"`
52}
53
54// pbkdf implements an ACVP algorithm by making requests to the
55// subprocess to generate PBKDF2 keys.
56type pbkdf struct{}
57
58func (p *pbkdf) Process(vectorSet []byte, m Transactable) (any, error) {
59	var parsed pbkdfTestVectorSet
60	if err := json.Unmarshal(vectorSet, &parsed); err != nil {
61		return nil, err
62	}
63
64	var ret []pbkdfTestGroupResponse
65	// See
66	// https://pages.nist.gov/ACVP/draft-celi-acvp-pbkdf.html#name-test-vectors
67	// for details about the tests.
68	for _, group := range parsed.Groups {
69		group := group
70
71		// "There is only one test type: functional tests."
72		// https://pages.nist.gov/ACVP/draft-celi-acvp-pbkdf.html#section-6.1
73		if group.Type != "AFT" {
74			return nil, fmt.Errorf("test type %q in test group %d not supported", group.Type, group.ID)
75		}
76
77		response := pbkdfTestGroupResponse{
78			ID: group.ID,
79		}
80
81		for _, test := range group.Tests {
82			test := test
83
84			if test.KeyLen < 8 {
85				return nil, fmt.Errorf("key length must be at least 8 bits in test case %d/%d", group.ID, test.ID)
86			}
87			keyLen := uint32le(test.KeyLen)
88
89			salt, err := hex.DecodeString(test.Salt)
90			if err != nil {
91				return nil, fmt.Errorf("failed to decode hex salt in test case %d/%d: %s", group.ID, test.ID, err)
92			}
93
94			if test.IterationCount < 1 {
95				return nil, fmt.Errorf("iteration count must be at least 1 in test case %d/%d", group.ID, test.ID)
96			}
97			iterationCount := uint32le(test.IterationCount)
98
99			msg := [][]byte{[]byte(group.HmacAlgo), keyLen, salt, []byte(test.Password), iterationCount}
100			m.TransactAsync("PBKDF", 1, msg, func(result [][]byte) error {
101				response.Tests = append(response.Tests, pbkdfTestResponse{
102					ID:         test.ID,
103					DerivedKey: hex.EncodeToString(result[0]),
104				})
105				return nil
106			})
107		}
108
109		m.Barrier(func() {
110			ret = append(ret, response)
111		})
112	}
113
114	if err := m.Flush(); err != nil {
115		return nil, err
116	}
117
118	return ret, nil
119}
120