1*e7b1675dSTing-Kang Chang// Copyright 2018 Google LLC 2*e7b1675dSTing-Kang Chang// 3*e7b1675dSTing-Kang Chang// Licensed under the Apache License, Version 2.0 (the "License"); 4*e7b1675dSTing-Kang Chang// you may not use this file except in compliance with the License. 5*e7b1675dSTing-Kang Chang// You may obtain a copy of the License at 6*e7b1675dSTing-Kang Chang// 7*e7b1675dSTing-Kang Chang// http://www.apache.org/licenses/LICENSE-2.0 8*e7b1675dSTing-Kang Chang// 9*e7b1675dSTing-Kang Chang// Unless required by applicable law or agreed to in writing, software 10*e7b1675dSTing-Kang Chang// distributed under the License is distributed on an "AS IS" BASIS, 11*e7b1675dSTing-Kang Chang// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*e7b1675dSTing-Kang Chang// See the License for the specific language governing permissions and 13*e7b1675dSTing-Kang Chang// limitations under the License. 14*e7b1675dSTing-Kang Chang// 15*e7b1675dSTing-Kang Chang//////////////////////////////////////////////////////////////////////////////// 16*e7b1675dSTing-Kang Chang 17*e7b1675dSTing-Kang Changpackage aead 18*e7b1675dSTing-Kang Chang 19*e7b1675dSTing-Kang Changimport ( 20*e7b1675dSTing-Kang Chang "fmt" 21*e7b1675dSTing-Kang Chang "io" 22*e7b1675dSTing-Kang Chang 23*e7b1675dSTing-Kang Chang "golang.org/x/crypto/chacha20poly1305" 24*e7b1675dSTing-Kang Chang "google.golang.org/protobuf/proto" 25*e7b1675dSTing-Kang Chang "github.com/google/tink/go/aead/subtle" 26*e7b1675dSTing-Kang Chang "github.com/google/tink/go/core/registry" 27*e7b1675dSTing-Kang Chang "github.com/google/tink/go/keyset" 28*e7b1675dSTing-Kang Chang "github.com/google/tink/go/subtle/random" 29*e7b1675dSTing-Kang Chang 30*e7b1675dSTing-Kang Chang tpb "github.com/google/tink/go/proto/tink_go_proto" 31*e7b1675dSTing-Kang Chang xpb "github.com/google/tink/go/proto/xchacha20_poly1305_go_proto" 32*e7b1675dSTing-Kang Chang) 33*e7b1675dSTing-Kang Chang 34*e7b1675dSTing-Kang Changconst ( 35*e7b1675dSTing-Kang Chang xChaCha20Poly1305KeyVersion = 0 36*e7b1675dSTing-Kang Chang xChaCha20Poly1305TypeURL = "type.googleapis.com/google.crypto.tink.XChaCha20Poly1305Key" 37*e7b1675dSTing-Kang Chang) 38*e7b1675dSTing-Kang Chang 39*e7b1675dSTing-Kang Changvar ( 40*e7b1675dSTing-Kang Chang errInvalidXChaCha20Poly1305Key = fmt.Errorf("xchacha20poly1305_key_manager: invalid key") 41*e7b1675dSTing-Kang Chang errInvalidXChaCha20Poly1305KeyFormat = fmt.Errorf("xchacha20poly1305_key_manager: invalid key format") 42*e7b1675dSTing-Kang Chang) 43*e7b1675dSTing-Kang Chang 44*e7b1675dSTing-Kang Chang// xChaCha20Poly1305KeyManager generates XChaCha20Poly1305Key keys and produces 45*e7b1675dSTing-Kang Chang// instances of XChaCha20Poly1305. 46*e7b1675dSTing-Kang Changtype xChaCha20Poly1305KeyManager struct{} 47*e7b1675dSTing-Kang Chang 48*e7b1675dSTing-Kang Chang// Assert that xChaCha20Poly1305KeyManager implements the KeyManager interface. 49*e7b1675dSTing-Kang Changvar _ registry.KeyManager = (*xChaCha20Poly1305KeyManager)(nil) 50*e7b1675dSTing-Kang Chang 51*e7b1675dSTing-Kang Chang// Primitive constructs a XChaCha20Poly1305 for the given serialized 52*e7b1675dSTing-Kang Chang// XChaCha20Poly1305Key. 53*e7b1675dSTing-Kang Changfunc (km *xChaCha20Poly1305KeyManager) Primitive(serializedKey []byte) (interface{}, error) { 54*e7b1675dSTing-Kang Chang if len(serializedKey) == 0 { 55*e7b1675dSTing-Kang Chang return nil, errInvalidXChaCha20Poly1305Key 56*e7b1675dSTing-Kang Chang } 57*e7b1675dSTing-Kang Chang key := new(xpb.XChaCha20Poly1305Key) 58*e7b1675dSTing-Kang Chang if err := proto.Unmarshal(serializedKey, key); err != nil { 59*e7b1675dSTing-Kang Chang return nil, errInvalidXChaCha20Poly1305Key 60*e7b1675dSTing-Kang Chang } 61*e7b1675dSTing-Kang Chang if err := km.validateKey(key); err != nil { 62*e7b1675dSTing-Kang Chang return nil, err 63*e7b1675dSTing-Kang Chang } 64*e7b1675dSTing-Kang Chang ret, err := subtle.NewXChaCha20Poly1305(key.KeyValue) 65*e7b1675dSTing-Kang Chang if err != nil { 66*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("xchacha20poly1305_key_manager: cannot create new primitive: %v", err) 67*e7b1675dSTing-Kang Chang } 68*e7b1675dSTing-Kang Chang return ret, nil 69*e7b1675dSTing-Kang Chang} 70*e7b1675dSTing-Kang Chang 71*e7b1675dSTing-Kang Chang// NewKey generates a new XChaCha20Poly1305Key. It ignores serializedKeyFormat 72*e7b1675dSTing-Kang Chang// because the key size and other params are fixed. 73*e7b1675dSTing-Kang Changfunc (km *xChaCha20Poly1305KeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) { 74*e7b1675dSTing-Kang Chang return &xpb.XChaCha20Poly1305Key{ 75*e7b1675dSTing-Kang Chang Version: xChaCha20Poly1305KeyVersion, 76*e7b1675dSTing-Kang Chang KeyValue: random.GetRandomBytes(chacha20poly1305.KeySize), 77*e7b1675dSTing-Kang Chang }, nil 78*e7b1675dSTing-Kang Chang} 79*e7b1675dSTing-Kang Chang 80*e7b1675dSTing-Kang Chang// NewKeyData generates a new KeyData. It ignores serializedKeyFormat because 81*e7b1675dSTing-Kang Chang// the key size and other params are fixed. This should be used solely by the 82*e7b1675dSTing-Kang Chang// key management API. 83*e7b1675dSTing-Kang Changfunc (km *xChaCha20Poly1305KeyManager) NewKeyData(serializedKeyFormat []byte) (*tpb.KeyData, error) { 84*e7b1675dSTing-Kang Chang key := &xpb.XChaCha20Poly1305Key{ 85*e7b1675dSTing-Kang Chang Version: xChaCha20Poly1305KeyVersion, 86*e7b1675dSTing-Kang Chang KeyValue: random.GetRandomBytes(chacha20poly1305.KeySize), 87*e7b1675dSTing-Kang Chang } 88*e7b1675dSTing-Kang Chang serializedKey, err := proto.Marshal(key) 89*e7b1675dSTing-Kang Chang if err != nil { 90*e7b1675dSTing-Kang Chang return nil, err 91*e7b1675dSTing-Kang Chang } 92*e7b1675dSTing-Kang Chang return &tpb.KeyData{ 93*e7b1675dSTing-Kang Chang TypeUrl: xChaCha20Poly1305TypeURL, 94*e7b1675dSTing-Kang Chang Value: serializedKey, 95*e7b1675dSTing-Kang Chang KeyMaterialType: km.KeyMaterialType(), 96*e7b1675dSTing-Kang Chang }, nil 97*e7b1675dSTing-Kang Chang} 98*e7b1675dSTing-Kang Chang 99*e7b1675dSTing-Kang Chang// DoesSupport checks whether this key manager supports the given key type. 100*e7b1675dSTing-Kang Changfunc (km *xChaCha20Poly1305KeyManager) DoesSupport(typeURL string) bool { 101*e7b1675dSTing-Kang Chang return typeURL == xChaCha20Poly1305TypeURL 102*e7b1675dSTing-Kang Chang} 103*e7b1675dSTing-Kang Chang 104*e7b1675dSTing-Kang Chang// TypeURL returns the type URL of keys managed by this key manager. 105*e7b1675dSTing-Kang Changfunc (km *xChaCha20Poly1305KeyManager) TypeURL() string { 106*e7b1675dSTing-Kang Chang return xChaCha20Poly1305TypeURL 107*e7b1675dSTing-Kang Chang} 108*e7b1675dSTing-Kang Chang 109*e7b1675dSTing-Kang Chang// KeyMaterialType returns the key material type of this key manager. 110*e7b1675dSTing-Kang Changfunc (km *xChaCha20Poly1305KeyManager) KeyMaterialType() tpb.KeyData_KeyMaterialType { 111*e7b1675dSTing-Kang Chang return tpb.KeyData_SYMMETRIC 112*e7b1675dSTing-Kang Chang} 113*e7b1675dSTing-Kang Chang 114*e7b1675dSTing-Kang Chang// DeriveKey derives a new key from serializedKeyFormat and pseudorandomness. 115*e7b1675dSTing-Kang Chang// Unlike NewKey, DeriveKey validates serializedKeyFormat's version. 116*e7b1675dSTing-Kang Changfunc (km *xChaCha20Poly1305KeyManager) DeriveKey(serializedKeyFormat []byte, pseudorandomness io.Reader) (proto.Message, error) { 117*e7b1675dSTing-Kang Chang keyFormat := new(xpb.XChaCha20Poly1305KeyFormat) 118*e7b1675dSTing-Kang Chang if err := proto.Unmarshal(serializedKeyFormat, keyFormat); err != nil { 119*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("xchacha20poly1305_key_manager: %v", err) 120*e7b1675dSTing-Kang Chang } 121*e7b1675dSTing-Kang Chang err := keyset.ValidateKeyVersion(keyFormat.Version, xChaCha20Poly1305KeyVersion) 122*e7b1675dSTing-Kang Chang if err != nil { 123*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("xchacha20poly1305_key_manager: %v", err) 124*e7b1675dSTing-Kang Chang } 125*e7b1675dSTing-Kang Chang 126*e7b1675dSTing-Kang Chang keyValue := make([]byte, chacha20poly1305.KeySize) 127*e7b1675dSTing-Kang Chang if _, err := io.ReadFull(pseudorandomness, keyValue); err != nil { 128*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("xchacha20poly1305_key_manager: not enough pseudorandomness given") 129*e7b1675dSTing-Kang Chang } 130*e7b1675dSTing-Kang Chang return &xpb.XChaCha20Poly1305Key{ 131*e7b1675dSTing-Kang Chang Version: xChaCha20Poly1305KeyVersion, 132*e7b1675dSTing-Kang Chang KeyValue: keyValue, 133*e7b1675dSTing-Kang Chang }, nil 134*e7b1675dSTing-Kang Chang} 135*e7b1675dSTing-Kang Chang 136*e7b1675dSTing-Kang Chang// validateKey validates the given XChaCha20Poly1305Key. 137*e7b1675dSTing-Kang Changfunc (km *xChaCha20Poly1305KeyManager) validateKey(key *xpb.XChaCha20Poly1305Key) error { 138*e7b1675dSTing-Kang Chang err := keyset.ValidateKeyVersion(key.Version, xChaCha20Poly1305KeyVersion) 139*e7b1675dSTing-Kang Chang if err != nil { 140*e7b1675dSTing-Kang Chang return fmt.Errorf("xchacha20poly1305_key_manager: %v", err) 141*e7b1675dSTing-Kang Chang } 142*e7b1675dSTing-Kang Chang keySize := uint32(len(key.KeyValue)) 143*e7b1675dSTing-Kang Chang if keySize != chacha20poly1305.KeySize { 144*e7b1675dSTing-Kang Chang return fmt.Errorf("xchacha20poly1305_key_manager: key size != %d", chacha20poly1305.KeySize) 145*e7b1675dSTing-Kang Chang } 146*e7b1675dSTing-Kang Chang return nil 147*e7b1675dSTing-Kang Chang} 148