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 "io" 22 23 "golang.org/x/crypto/chacha20poly1305" 24 "google.golang.org/protobuf/proto" 25 "github.com/google/tink/go/aead/subtle" 26 "github.com/google/tink/go/core/registry" 27 "github.com/google/tink/go/keyset" 28 "github.com/google/tink/go/subtle/random" 29 30 tpb "github.com/google/tink/go/proto/tink_go_proto" 31 xpb "github.com/google/tink/go/proto/xchacha20_poly1305_go_proto" 32) 33 34const ( 35 xChaCha20Poly1305KeyVersion = 0 36 xChaCha20Poly1305TypeURL = "type.googleapis.com/google.crypto.tink.XChaCha20Poly1305Key" 37) 38 39var ( 40 errInvalidXChaCha20Poly1305Key = fmt.Errorf("xchacha20poly1305_key_manager: invalid key") 41 errInvalidXChaCha20Poly1305KeyFormat = fmt.Errorf("xchacha20poly1305_key_manager: invalid key format") 42) 43 44// xChaCha20Poly1305KeyManager generates XChaCha20Poly1305Key keys and produces 45// instances of XChaCha20Poly1305. 46type xChaCha20Poly1305KeyManager struct{} 47 48// Assert that xChaCha20Poly1305KeyManager implements the KeyManager interface. 49var _ registry.KeyManager = (*xChaCha20Poly1305KeyManager)(nil) 50 51// Primitive constructs a XChaCha20Poly1305 for the given serialized 52// XChaCha20Poly1305Key. 53func (km *xChaCha20Poly1305KeyManager) Primitive(serializedKey []byte) (interface{}, error) { 54 if len(serializedKey) == 0 { 55 return nil, errInvalidXChaCha20Poly1305Key 56 } 57 key := new(xpb.XChaCha20Poly1305Key) 58 if err := proto.Unmarshal(serializedKey, key); err != nil { 59 return nil, errInvalidXChaCha20Poly1305Key 60 } 61 if err := km.validateKey(key); err != nil { 62 return nil, err 63 } 64 ret, err := subtle.NewXChaCha20Poly1305(key.KeyValue) 65 if err != nil { 66 return nil, fmt.Errorf("xchacha20poly1305_key_manager: cannot create new primitive: %v", err) 67 } 68 return ret, nil 69} 70 71// NewKey generates a new XChaCha20Poly1305Key. It ignores serializedKeyFormat 72// because the key size and other params are fixed. 73func (km *xChaCha20Poly1305KeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) { 74 return &xpb.XChaCha20Poly1305Key{ 75 Version: xChaCha20Poly1305KeyVersion, 76 KeyValue: random.GetRandomBytes(chacha20poly1305.KeySize), 77 }, nil 78} 79 80// NewKeyData generates a new KeyData. It ignores serializedKeyFormat because 81// the key size and other params are fixed. This should be used solely by the 82// key management API. 83func (km *xChaCha20Poly1305KeyManager) NewKeyData(serializedKeyFormat []byte) (*tpb.KeyData, error) { 84 key := &xpb.XChaCha20Poly1305Key{ 85 Version: xChaCha20Poly1305KeyVersion, 86 KeyValue: random.GetRandomBytes(chacha20poly1305.KeySize), 87 } 88 serializedKey, err := proto.Marshal(key) 89 if err != nil { 90 return nil, err 91 } 92 return &tpb.KeyData{ 93 TypeUrl: xChaCha20Poly1305TypeURL, 94 Value: serializedKey, 95 KeyMaterialType: km.KeyMaterialType(), 96 }, nil 97} 98 99// DoesSupport checks whether this key manager supports the given key type. 100func (km *xChaCha20Poly1305KeyManager) DoesSupport(typeURL string) bool { 101 return typeURL == xChaCha20Poly1305TypeURL 102} 103 104// TypeURL returns the type URL of keys managed by this key manager. 105func (km *xChaCha20Poly1305KeyManager) TypeURL() string { 106 return xChaCha20Poly1305TypeURL 107} 108 109// KeyMaterialType returns the key material type of this key manager. 110func (km *xChaCha20Poly1305KeyManager) KeyMaterialType() tpb.KeyData_KeyMaterialType { 111 return tpb.KeyData_SYMMETRIC 112} 113 114// DeriveKey derives a new key from serializedKeyFormat and pseudorandomness. 115// Unlike NewKey, DeriveKey validates serializedKeyFormat's version. 116func (km *xChaCha20Poly1305KeyManager) DeriveKey(serializedKeyFormat []byte, pseudorandomness io.Reader) (proto.Message, error) { 117 keyFormat := new(xpb.XChaCha20Poly1305KeyFormat) 118 if err := proto.Unmarshal(serializedKeyFormat, keyFormat); err != nil { 119 return nil, fmt.Errorf("xchacha20poly1305_key_manager: %v", err) 120 } 121 err := keyset.ValidateKeyVersion(keyFormat.Version, xChaCha20Poly1305KeyVersion) 122 if err != nil { 123 return nil, fmt.Errorf("xchacha20poly1305_key_manager: %v", err) 124 } 125 126 keyValue := make([]byte, chacha20poly1305.KeySize) 127 if _, err := io.ReadFull(pseudorandomness, keyValue); err != nil { 128 return nil, fmt.Errorf("xchacha20poly1305_key_manager: not enough pseudorandomness given") 129 } 130 return &xpb.XChaCha20Poly1305Key{ 131 Version: xChaCha20Poly1305KeyVersion, 132 KeyValue: keyValue, 133 }, nil 134} 135 136// validateKey validates the given XChaCha20Poly1305Key. 137func (km *xChaCha20Poly1305KeyManager) validateKey(key *xpb.XChaCha20Poly1305Key) error { 138 err := keyset.ValidateKeyVersion(key.Version, xChaCha20Poly1305KeyVersion) 139 if err != nil { 140 return fmt.Errorf("xchacha20poly1305_key_manager: %v", err) 141 } 142 keySize := uint32(len(key.KeyValue)) 143 if keySize != chacha20poly1305.KeySize { 144 return fmt.Errorf("xchacha20poly1305_key_manager: key size != %d", chacha20poly1305.KeySize) 145 } 146 return nil 147} 148