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