1// Copyright 2018 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 aead 18 19import ( 20 "fmt" 21 22 "golang.org/x/crypto/chacha20poly1305" 23 "google.golang.org/protobuf/proto" 24 "github.com/google/tink/go/aead/subtle" 25 "github.com/google/tink/go/keyset" 26 "github.com/google/tink/go/subtle/random" 27 28 cppb "github.com/google/tink/go/proto/chacha20_poly1305_go_proto" 29 tinkpb "github.com/google/tink/go/proto/tink_go_proto" 30) 31 32const ( 33 chaCha20Poly1305KeyVersion = 0 34 chaCha20Poly1305TypeURL = "type.googleapis.com/google.crypto.tink.ChaCha20Poly1305Key" 35) 36 37// Common errors. 38var errInvalidChaCha20Poly1305Key = fmt.Errorf("chacha20poly1305_key_manager: invalid key") 39var errInvalidChaCha20Poly1305KeyFormat = fmt.Errorf("chacha20poly1305_key_manager: invalid key format") 40 41// chaCha20Poly1305KeyManager is an implementation of KeyManager interface. 42// It generates new ChaCha20Poly1305Key keys and produces new instances of ChaCha20Poly1305 subtle. 43type chaCha20Poly1305KeyManager struct{} 44 45// Primitive creates an ChaCha20Poly1305 subtle for the given serialized ChaCha20Poly1305Key proto. 46func (km *chaCha20Poly1305KeyManager) Primitive(serializedKey []byte) (interface{}, error) { 47 if len(serializedKey) == 0 { 48 return nil, errInvalidChaCha20Poly1305Key 49 } 50 key := new(cppb.ChaCha20Poly1305Key) 51 if err := proto.Unmarshal(serializedKey, key); err != nil { 52 return nil, errInvalidChaCha20Poly1305Key 53 } 54 if err := km.validateKey(key); err != nil { 55 return nil, err 56 } 57 ret, err := subtle.NewChaCha20Poly1305(key.KeyValue) 58 if err != nil { 59 return nil, fmt.Errorf("chacha20poly1305_key_manager: cannot create new primitive: %s", err) 60 } 61 return ret, nil 62} 63 64// NewKey creates a new key, ignoring the specification in the given serialized key format 65// because the key size and other params are fixed. 66func (km *chaCha20Poly1305KeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) { 67 return km.newChaCha20Poly1305Key(), nil 68} 69 70// NewKeyData creates a new KeyData ignoring the specification in the given serialized key format 71// because the key size and other params are fixed. 72// It should be used solely by the key management API. 73func (km *chaCha20Poly1305KeyManager) NewKeyData(serializedKeyFormat []byte) (*tinkpb.KeyData, error) { 74 key := km.newChaCha20Poly1305Key() 75 serializedKey, err := proto.Marshal(key) 76 if err != nil { 77 return nil, err 78 } 79 return &tinkpb.KeyData{ 80 TypeUrl: chaCha20Poly1305TypeURL, 81 Value: serializedKey, 82 KeyMaterialType: tinkpb.KeyData_SYMMETRIC, 83 }, nil 84} 85 86// DoesSupport indicates if this key manager supports the given key type. 87func (km *chaCha20Poly1305KeyManager) DoesSupport(typeURL string) bool { 88 return typeURL == chaCha20Poly1305TypeURL 89} 90 91// TypeURL returns the key type of keys managed by this key manager. 92func (km *chaCha20Poly1305KeyManager) TypeURL() string { 93 return chaCha20Poly1305TypeURL 94} 95 96func (km *chaCha20Poly1305KeyManager) newChaCha20Poly1305Key() *cppb.ChaCha20Poly1305Key { 97 keyValue := random.GetRandomBytes(chacha20poly1305.KeySize) 98 return &cppb.ChaCha20Poly1305Key{ 99 Version: chaCha20Poly1305KeyVersion, 100 KeyValue: keyValue, 101 } 102} 103 104// validateKey validates the given ChaCha20Poly1305Key. 105func (km *chaCha20Poly1305KeyManager) validateKey(key *cppb.ChaCha20Poly1305Key) error { 106 err := keyset.ValidateKeyVersion(key.Version, chaCha20Poly1305KeyVersion) 107 if err != nil { 108 return fmt.Errorf("chacha20poly1305_key_manager: %s", err) 109 } 110 keySize := uint32(len(key.KeyValue)) 111 if keySize != chacha20poly1305.KeySize { 112 return fmt.Errorf("chacha20poly1305_key_manager: keySize != %d", chacha20poly1305.KeySize) 113 } 114 return nil 115} 116