xref: /aosp_15_r20/external/tink/go/mac/aes_cmac_key_manager.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 mac
18
19import (
20	"errors"
21	"fmt"
22
23	"google.golang.org/protobuf/proto"
24	"github.com/google/tink/go/keyset"
25	"github.com/google/tink/go/mac/subtle"
26	"github.com/google/tink/go/subtle/random"
27	cmacpb "github.com/google/tink/go/proto/aes_cmac_go_proto"
28	tinkpb "github.com/google/tink/go/proto/tink_go_proto"
29)
30
31const (
32	cmacKeyVersion = 0
33	cmacTypeURL    = "type.googleapis.com/google.crypto.tink.AesCmacKey"
34)
35
36var errInvalidCMACKey = errors.New("aes_cmac_key_manager: invalid key")
37var errInvalidCMACKeyFormat = errors.New("aes_cmac_key_manager: invalid key format")
38
39// cmacKeyManager generates new AES-CMAC keys and produces new instances of AES-CMAC.
40type aescmacKeyManager struct{}
41
42// Primitive constructs a AES-CMAC instance for the given serialized CMACKey.
43func (km *aescmacKeyManager) Primitive(serializedKey []byte) (interface{}, error) {
44	if len(serializedKey) == 0 {
45		return nil, errInvalidCMACKey
46	}
47	key := new(cmacpb.AesCmacKey)
48	if err := proto.Unmarshal(serializedKey, key); err != nil {
49		return nil, errInvalidCMACKey
50	}
51	if err := km.validateKey(key); err != nil {
52		return nil, err
53	}
54	cmac, err := subtle.NewAESCMAC(key.KeyValue, key.Params.TagSize)
55	if err != nil {
56		return nil, err
57	}
58	return cmac, nil
59}
60
61// NewKey generates a new AesCmacKey according to specification in the given AesCmacKeyFormat.
62func (km *aescmacKeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) {
63	if len(serializedKeyFormat) == 0 {
64		return nil, errInvalidCMACKeyFormat
65	}
66	keyFormat := new(cmacpb.AesCmacKeyFormat)
67	if err := proto.Unmarshal(serializedKeyFormat, keyFormat); err != nil {
68		return nil, errInvalidCMACKeyFormat
69	}
70	if err := km.validateKeyFormat(keyFormat); err != nil {
71		return nil, fmt.Errorf("aes_cmac_key_manager: invalid key format: %s", err)
72	}
73	keyValue := random.GetRandomBytes(keyFormat.KeySize)
74	return &cmacpb.AesCmacKey{
75		Version:  cmacKeyVersion,
76		Params:   keyFormat.Params,
77		KeyValue: keyValue,
78	}, nil
79}
80
81// NewKeyData generates a new KeyData according to specification in the given
82// serialized AesCmacKeyFormat. This should be used solely by the key management API.
83func (km *aescmacKeyManager) NewKeyData(serializedKeyFormat []byte) (*tinkpb.KeyData, error) {
84	key, err := km.NewKey(serializedKeyFormat)
85	if err != nil {
86		return nil, err
87	}
88	serializedKey, err := proto.Marshal(key)
89	if err != nil {
90		return nil, errInvalidCMACKeyFormat
91	}
92
93	return &tinkpb.KeyData{
94		TypeUrl:         cmacTypeURL,
95		Value:           serializedKey,
96		KeyMaterialType: tinkpb.KeyData_SYMMETRIC,
97	}, nil
98}
99
100// DoesSupport checks whether this KeyManager supports the given key type.
101func (km *aescmacKeyManager) DoesSupport(typeURL string) bool {
102	return typeURL == cmacTypeURL
103}
104
105// TypeURL returns the type URL of keys managed by this KeyManager.
106func (km *aescmacKeyManager) TypeURL() string {
107	return cmacTypeURL
108}
109
110// validateKey validates the given AesCmacKey. It only validates the version of the
111// key because other parameters will be validated in primitive construction.
112func (km *aescmacKeyManager) validateKey(key *cmacpb.AesCmacKey) error {
113	err := keyset.ValidateKeyVersion(key.Version, cmacKeyVersion)
114	if err != nil {
115		return fmt.Errorf("aes_cmac_key_manager: invalid version: %s", err)
116	}
117	keySize := uint32(len(key.KeyValue))
118	return subtle.ValidateCMACParams(keySize, key.Params.TagSize)
119}
120
121// validateKeyFormat validates the given AesCmacKeyFormat
122func (km *aescmacKeyManager) validateKeyFormat(format *cmacpb.AesCmacKeyFormat) error {
123	if format.Params == nil {
124		return fmt.Errorf("null AES-CMAC params")
125	}
126	return subtle.ValidateCMACParams(format.KeySize, format.Params.TagSize)
127}
128