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 streamingaead 18 19import ( 20 "errors" 21 "fmt" 22 23 "google.golang.org/protobuf/proto" 24 subtleaead "github.com/google/tink/go/aead/subtle" 25 "github.com/google/tink/go/keyset" 26 subtlemac "github.com/google/tink/go/mac/subtle" 27 "github.com/google/tink/go/streamingaead/subtle" 28 "github.com/google/tink/go/subtle/random" 29 chpb "github.com/google/tink/go/proto/aes_ctr_hmac_streaming_go_proto" 30 commonpb "github.com/google/tink/go/proto/common_go_proto" 31 tinkpb "github.com/google/tink/go/proto/tink_go_proto" 32) 33 34const ( 35 aesCTRHMACKeyVersion = 0 36 aesCTRHMACTypeURL = "type.googleapis.com/google.crypto.tink.AesCtrHmacStreamingKey" 37) 38 39var ( 40 errInvalidAESCTRHMACKey = errors.New("aes_ctr_hmac_key_manager: invalid key") 41 errInvalidAESCTRHMACKeyFormat = errors.New("aes_ctr_hmac_key_manager: invalid key format") 42) 43 44// aesCTRHMACKeyManager is an implementation of KeyManager interface. 45// 46// It generates new AESCTRHMACKey keys and produces new instances of AESCTRHMAC 47// subtle. 48type aesCTRHMACKeyManager struct{} 49 50// Primitive creates an AESCTRHMAC subtle for the given serialized 51// AESCTRHMACKey proto. 52func (km *aesCTRHMACKeyManager) Primitive(serializedKey []byte) (interface{}, error) { 53 if len(serializedKey) == 0 { 54 return nil, errInvalidAESCTRHMACKey 55 } 56 key := &chpb.AesCtrHmacStreamingKey{} 57 if err := proto.Unmarshal(serializedKey, key); err != nil { 58 return nil, errInvalidAESCTRHMACKey 59 } 60 if err := km.validateKey(key); err != nil { 61 return nil, err 62 } 63 p, err := subtle.NewAESCTRHMAC( 64 key.KeyValue, 65 key.Params.HkdfHashType.String(), 66 int(key.Params.DerivedKeySize), 67 key.Params.HmacParams.Hash.String(), 68 int(key.Params.HmacParams.TagSize), 69 int(key.Params.CiphertextSegmentSize), 70 // No first segment offset. 71 0) 72 if err != nil { 73 return nil, fmt.Errorf("aes_ctr_hmac_key_manager: cannot create new primitive: %s", err) 74 } 75 return p, nil 76} 77 78// NewKey creates a new key according to specification in the given serialized 79// AesCtrHmacStreamingKeyFormat. 80func (km *aesCTRHMACKeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) { 81 if len(serializedKeyFormat) == 0 { 82 return nil, errInvalidAESCTRHMACKeyFormat 83 } 84 keyFormat := &chpb.AesCtrHmacStreamingKeyFormat{} 85 if err := proto.Unmarshal(serializedKeyFormat, keyFormat); err != nil { 86 return nil, errInvalidAESCTRHMACKeyFormat 87 } 88 if err := km.validateKeyFormat(keyFormat); err != nil { 89 return nil, fmt.Errorf("%s: %s", errInvalidAESCTRHMACKeyFormat, err) 90 } 91 return &chpb.AesCtrHmacStreamingKey{ 92 Version: aesCTRHMACKeyVersion, 93 KeyValue: random.GetRandomBytes(keyFormat.KeySize), 94 Params: keyFormat.Params, 95 }, nil 96} 97 98// NewKeyData creates a new KeyData according to specification in the given 99// serialized AesCtrHmacStreamingKeyFormat. 100// 101// It should be used solely by the key management API. 102func (km *aesCTRHMACKeyManager) NewKeyData(serializedKeyFormat []byte) (*tinkpb.KeyData, error) { 103 key, err := km.NewKey(serializedKeyFormat) 104 if err != nil { 105 return nil, err 106 } 107 serializedKey, err := proto.Marshal(key) 108 if err != nil { 109 return nil, err 110 } 111 return &tinkpb.KeyData{ 112 TypeUrl: km.TypeURL(), 113 Value: serializedKey, 114 KeyMaterialType: tinkpb.KeyData_SYMMETRIC, 115 }, nil 116} 117 118// DoesSupport indicates if this key manager supports the given key type. 119func (km *aesCTRHMACKeyManager) DoesSupport(typeURL string) bool { 120 return typeURL == aesCTRHMACTypeURL 121} 122 123// TypeURL returns the key type of keys managed by this key manager. 124func (km *aesCTRHMACKeyManager) TypeURL() string { 125 return aesCTRHMACTypeURL 126} 127 128// validateKey validates the given AESCTRHMACKey. 129func (km *aesCTRHMACKeyManager) validateKey(key *chpb.AesCtrHmacStreamingKey) error { 130 if err := keyset.ValidateKeyVersion(key.Version, aesCTRHMACKeyVersion); err != nil { 131 return err 132 } 133 keySize := uint32(len(key.KeyValue)) 134 if err := subtleaead.ValidateAESKeySize(keySize); err != nil { 135 return err 136 } 137 if err := km.validateParams(key.Params); err != nil { 138 return err 139 } 140 return nil 141} 142 143// validateKeyFormat validates the given AESCTRHMACKeyFormat. 144func (km *aesCTRHMACKeyManager) validateKeyFormat(format *chpb.AesCtrHmacStreamingKeyFormat) error { 145 if err := subtleaead.ValidateAESKeySize(format.KeySize); err != nil { 146 return err 147 } 148 if err := km.validateParams(format.Params); err != nil { 149 return err 150 } 151 return nil 152} 153 154// validateParams validates the given AESCTRHMACStreamingParams. 155func (km *aesCTRHMACKeyManager) validateParams(params *chpb.AesCtrHmacStreamingParams) error { 156 if err := subtleaead.ValidateAESKeySize(params.DerivedKeySize); err != nil { 157 return err 158 } 159 if params.HkdfHashType != commonpb.HashType_SHA1 && params.HkdfHashType != commonpb.HashType_SHA256 && params.HkdfHashType != commonpb.HashType_SHA512 { 160 return fmt.Errorf("Invalid HKDF hash type (%s)", params.HkdfHashType) 161 } 162 if params.HmacParams.Hash != commonpb.HashType_SHA1 && params.HmacParams.Hash != commonpb.HashType_SHA256 && params.HmacParams.Hash != commonpb.HashType_SHA512 { 163 return fmt.Errorf("Invalid tag algorithm (%s)", params.HmacParams.Hash) 164 } 165 hmacHash := commonpb.HashType_name[int32(params.HmacParams.Hash)] 166 if err := subtlemac.ValidateHMACParams(hmacHash, subtle.AESCTRHMACKeySizeInBytes, params.HmacParams.TagSize); err != nil { 167 return err 168 } 169 minSegmentSize := params.DerivedKeySize + subtle.AESCTRHMACNoncePrefixSizeInBytes + params.HmacParams.TagSize + 2 170 if params.CiphertextSegmentSize < minSegmentSize { 171 return fmt.Errorf("ciphertext segment size must be at least (derivedKeySize + noncePrefixInBytes + tagSizeInBytes + 2)") 172 } 173 if params.CiphertextSegmentSize > 0x7fffffff { 174 return fmt.Errorf("ciphertext segment size must be at most 2^31 - 1") 175 } 176 return nil 177} 178