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 "io" 23 24 "google.golang.org/protobuf/proto" 25 subtleaead "github.com/google/tink/go/aead/subtle" 26 "github.com/google/tink/go/keyset" 27 "github.com/google/tink/go/streamingaead/subtle" 28 "github.com/google/tink/go/subtle/random" 29 ghpb "github.com/google/tink/go/proto/aes_gcm_hkdf_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 aesGCMHKDFKeyVersion = 0 36 aesGCMHKDFTypeURL = "type.googleapis.com/google.crypto.tink.AesGcmHkdfStreamingKey" 37) 38 39var ( 40 errInvalidAESGCMHKDFKey = errors.New("aes_gcm_hkdf_key_manager: invalid key") 41 errInvalidAESGCMHKDFKeyFormat = errors.New("aes_gcm_hkdf_key_manager: invalid key format") 42) 43 44// aesGCMHKDFKeyManager is an implementation of KeyManager interface. 45// It generates new AESGCMHKDFKey keys and produces new instances of AESGCMHKDF subtle. 46type aesGCMHKDFKeyManager struct{} 47 48// Primitive creates an AESGCMHKDF subtle for the given serialized AESGCMHKDFKey proto. 49func (km *aesGCMHKDFKeyManager) Primitive(serializedKey []byte) (interface{}, error) { 50 if len(serializedKey) == 0 { 51 return nil, errInvalidAESGCMHKDFKey 52 } 53 key := &ghpb.AesGcmHkdfStreamingKey{} 54 if err := proto.Unmarshal(serializedKey, key); err != nil { 55 return nil, errInvalidAESGCMHKDFKey 56 } 57 if err := km.validateKey(key); err != nil { 58 return nil, err 59 } 60 ret, err := subtle.NewAESGCMHKDF( 61 key.KeyValue, 62 key.Params.HkdfHashType.String(), 63 int(key.Params.DerivedKeySize), 64 int(key.Params.CiphertextSegmentSize), 65 // no first segment offset 66 0) 67 if err != nil { 68 return nil, fmt.Errorf("aes_gcm_hkdf_key_manager: cannot create new primitive: %s", err) 69 } 70 return ret, nil 71} 72 73// NewKey creates a new key according to specification in the given serialized 74// AesGcmHkdfStreamingKeyFormat. 75func (km *aesGCMHKDFKeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) { 76 if len(serializedKeyFormat) == 0 { 77 return nil, errInvalidAESGCMHKDFKeyFormat 78 } 79 keyFormat := &ghpb.AesGcmHkdfStreamingKeyFormat{} 80 if err := proto.Unmarshal(serializedKeyFormat, keyFormat); err != nil { 81 return nil, errInvalidAESGCMHKDFKeyFormat 82 } 83 if err := km.validateKeyFormat(keyFormat); err != nil { 84 return nil, fmt.Errorf("aes_gcm_hkdf_key_manager: invalid key format: %s", err) 85 } 86 return &ghpb.AesGcmHkdfStreamingKey{ 87 Version: aesGCMHKDFKeyVersion, 88 KeyValue: random.GetRandomBytes(keyFormat.KeySize), 89 Params: keyFormat.Params, 90 }, nil 91} 92 93// NewKeyData creates a new KeyData according to specification in the given serialized AesGcmHkdfStreamingKeyFormat. 94// It should be used solely by the key management API. 95func (km *aesGCMHKDFKeyManager) NewKeyData(serializedKeyFormat []byte) (*tinkpb.KeyData, error) { 96 key, err := km.NewKey(serializedKeyFormat) 97 if err != nil { 98 return nil, err 99 } 100 serializedKey, err := proto.Marshal(key) 101 if err != nil { 102 return nil, err 103 } 104 return &tinkpb.KeyData{ 105 TypeUrl: km.TypeURL(), 106 Value: serializedKey, 107 KeyMaterialType: km.KeyMaterialType(), 108 }, nil 109} 110 111// DoesSupport indicates if this key manager supports the given key type. 112func (km *aesGCMHKDFKeyManager) DoesSupport(typeURL string) bool { 113 return typeURL == aesGCMHKDFTypeURL 114} 115 116// TypeURL returns the key type of keys managed by this key manager. 117func (km *aesGCMHKDFKeyManager) TypeURL() string { 118 return aesGCMHKDFTypeURL 119} 120 121// KeyMaterialType returns the key material type of this key manager. 122func (km *aesGCMHKDFKeyManager) KeyMaterialType() tinkpb.KeyData_KeyMaterialType { 123 return tinkpb.KeyData_SYMMETRIC 124} 125 126// DeriveKey derives a new key from serializedKeyFormat and pseudorandomness. 127func (km *aesGCMHKDFKeyManager) DeriveKey(serializedKeyFormat []byte, pseudorandomness io.Reader) (proto.Message, error) { 128 if len(serializedKeyFormat) == 0 { 129 return nil, errInvalidAESGCMHKDFKeyFormat 130 } 131 keyFormat := &ghpb.AesGcmHkdfStreamingKeyFormat{} 132 if err := proto.Unmarshal(serializedKeyFormat, keyFormat); err != nil { 133 return nil, errInvalidAESGCMHKDFKeyFormat 134 } 135 if err := km.validateKeyFormat(keyFormat); err != nil { 136 return nil, fmt.Errorf("aes_gcm_hkdf_key_manager: invalid key format: %v", err) 137 } 138 if err := keyset.ValidateKeyVersion(keyFormat.GetVersion(), aesGCMHKDFKeyVersion); err != nil { 139 return nil, fmt.Errorf("aes_gcm_hkdf_key_manager: invalid key version: %s", err) 140 } 141 142 keyValue := make([]byte, keyFormat.GetKeySize()) 143 if _, err := io.ReadFull(pseudorandomness, keyValue); err != nil { 144 return nil, fmt.Errorf("aes_gcm_hkdf_key_manager: not enough pseudorandomness given") 145 } 146 return &ghpb.AesGcmHkdfStreamingKey{ 147 Version: aesGCMHKDFKeyVersion, 148 KeyValue: keyValue, 149 Params: keyFormat.Params, 150 }, nil 151} 152 153// validateKey validates the given AESGCMHKDFKey. 154func (km *aesGCMHKDFKeyManager) validateKey(key *ghpb.AesGcmHkdfStreamingKey) error { 155 if err := keyset.ValidateKeyVersion(key.Version, aesGCMHKDFKeyVersion); err != nil { 156 return fmt.Errorf("aes_gcm_hkdf_key_manager: %s", err) 157 } 158 keySize := uint32(len(key.KeyValue)) 159 if err := subtleaead.ValidateAESKeySize(keySize); err != nil { 160 return fmt.Errorf("aes_gcm_hkdf_key_manager: %s", err) 161 } 162 if err := km.validateParams(key.Params); err != nil { 163 return fmt.Errorf("aes_gcm_hkdf_key_manager: %s", err) 164 } 165 return nil 166} 167 168// validateKeyFormat validates the given AESGCMHKDFKeyFormat. 169func (km *aesGCMHKDFKeyManager) validateKeyFormat(format *ghpb.AesGcmHkdfStreamingKeyFormat) error { 170 if err := subtleaead.ValidateAESKeySize(format.KeySize); err != nil { 171 return fmt.Errorf("aes_gcm_hkdf_key_manager: %s", err) 172 } 173 if err := km.validateParams(format.Params); err != nil { 174 return fmt.Errorf("aes_gcm_hkdf_key_manager: %s", err) 175 } 176 return nil 177} 178 179// validateKeyFormat validates the given AESGCMHKDFKeyFormat. 180func (km *aesGCMHKDFKeyManager) validateParams(params *ghpb.AesGcmHkdfStreamingParams) error { 181 if err := subtleaead.ValidateAESKeySize(params.DerivedKeySize); err != nil { 182 return fmt.Errorf("aes_gcm_hkdf_key_manager: %s", err) 183 } 184 if params.HkdfHashType != commonpb.HashType_SHA1 && params.HkdfHashType != commonpb.HashType_SHA256 && params.HkdfHashType != commonpb.HashType_SHA512 { 185 return errors.New("unknown HKDF hash type") 186 } 187 if params.CiphertextSegmentSize > 0x7fffffff { 188 return errors.New("CiphertextSegmentSize must be at most 2^31 - 1") 189 } 190 minSegmentSize := params.DerivedKeySize + subtle.AESGCMHKDFNoncePrefixSizeInBytes + subtle.AESGCMHKDFTagSizeInBytes + 2 191 if params.CiphertextSegmentSize < minSegmentSize { 192 return fmt.Errorf("ciphertext segment_size must be at least (derivedKeySize + noncePrefixInBytes + tagSizeInBytes + 2)") 193 } 194 return nil 195} 196