1*e7b1675dSTing-Kang Chang// Copyright 2019 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 "encoding/binary" 21*e7b1675dSTing-Kang Chang "errors" 22*e7b1675dSTing-Kang Chang "fmt" 23*e7b1675dSTing-Kang Chang 24*e7b1675dSTing-Kang Chang "github.com/google/tink/go/core/registry" 25*e7b1675dSTing-Kang Chang "github.com/google/tink/go/tink" 26*e7b1675dSTing-Kang Chang tinkpb "github.com/google/tink/go/proto/tink_go_proto" 27*e7b1675dSTing-Kang Chang) 28*e7b1675dSTing-Kang Chang 29*e7b1675dSTing-Kang Changconst ( 30*e7b1675dSTing-Kang Chang lenDEK = 4 31*e7b1675dSTing-Kang Chang maxUint32Size = 4294967295 32*e7b1675dSTing-Kang Chang) 33*e7b1675dSTing-Kang Chang 34*e7b1675dSTing-Kang Chang// KMSEnvelopeAEAD represents an instance of Envelope AEAD. 35*e7b1675dSTing-Kang Changtype KMSEnvelopeAEAD struct { 36*e7b1675dSTing-Kang Chang dekTemplate *tinkpb.KeyTemplate 37*e7b1675dSTing-Kang Chang remote tink.AEAD 38*e7b1675dSTing-Kang Chang // if err != nil, then the primitive will always fail with this error. 39*e7b1675dSTing-Kang Chang // this is needed because NewKMSEnvelopeAEAD2 doesn't return an error. 40*e7b1675dSTing-Kang Chang err error 41*e7b1675dSTing-Kang Chang} 42*e7b1675dSTing-Kang Chang 43*e7b1675dSTing-Kang Changvar tinkAEADKeyTypes map[string]bool = map[string]bool{ 44*e7b1675dSTing-Kang Chang aesCTRHMACAEADTypeURL: true, 45*e7b1675dSTing-Kang Chang aesGCMTypeURL: true, 46*e7b1675dSTing-Kang Chang chaCha20Poly1305TypeURL: true, 47*e7b1675dSTing-Kang Chang xChaCha20Poly1305TypeURL: true, 48*e7b1675dSTing-Kang Chang aesGCMSIVTypeURL: true, 49*e7b1675dSTing-Kang Chang} 50*e7b1675dSTing-Kang Chang 51*e7b1675dSTing-Kang Changfunc isSupporedKMSEnvelopeDEK(dekKeyTypeURL string) bool { 52*e7b1675dSTing-Kang Chang _, found := tinkAEADKeyTypes[dekKeyTypeURL] 53*e7b1675dSTing-Kang Chang return found 54*e7b1675dSTing-Kang Chang} 55*e7b1675dSTing-Kang Chang 56*e7b1675dSTing-Kang Chang// NewKMSEnvelopeAEAD2 creates an new instance of KMSEnvelopeAEAD. 57*e7b1675dSTing-Kang Chang// 58*e7b1675dSTing-Kang Chang// dekTemplate must be a KeyTemplate for any of these Tink AEAD key types (any 59*e7b1675dSTing-Kang Chang// other key template will be rejected): 60*e7b1675dSTing-Kang Chang// - AesCtrHmacAeadKey 61*e7b1675dSTing-Kang Chang// - AesGcmKey 62*e7b1675dSTing-Kang Chang// - ChaCha20Poly1305Key 63*e7b1675dSTing-Kang Chang// - XChaCha20Poly1305 64*e7b1675dSTing-Kang Chang// - AesGcmSivKey 65*e7b1675dSTing-Kang Changfunc NewKMSEnvelopeAEAD2(dekTemplate *tinkpb.KeyTemplate, remote tink.AEAD) *KMSEnvelopeAEAD { 66*e7b1675dSTing-Kang Chang if !isSupporedKMSEnvelopeDEK(dekTemplate.GetTypeUrl()) { 67*e7b1675dSTing-Kang Chang return &KMSEnvelopeAEAD{ 68*e7b1675dSTing-Kang Chang remote: nil, 69*e7b1675dSTing-Kang Chang dekTemplate: nil, 70*e7b1675dSTing-Kang Chang err: fmt.Errorf("unsupported DEK key type %s", dekTemplate.GetTypeUrl()), 71*e7b1675dSTing-Kang Chang } 72*e7b1675dSTing-Kang Chang } 73*e7b1675dSTing-Kang Chang return &KMSEnvelopeAEAD{ 74*e7b1675dSTing-Kang Chang remote: remote, 75*e7b1675dSTing-Kang Chang dekTemplate: dekTemplate, 76*e7b1675dSTing-Kang Chang err: nil, 77*e7b1675dSTing-Kang Chang } 78*e7b1675dSTing-Kang Chang} 79*e7b1675dSTing-Kang Chang 80*e7b1675dSTing-Kang Chang// Encrypt implements the tink.AEAD interface for encryption. 81*e7b1675dSTing-Kang Changfunc (a *KMSEnvelopeAEAD) Encrypt(pt, aad []byte) ([]byte, error) { 82*e7b1675dSTing-Kang Chang if a.err != nil { 83*e7b1675dSTing-Kang Chang return nil, a.err 84*e7b1675dSTing-Kang Chang } 85*e7b1675dSTing-Kang Chang dekKeyData, err := registry.NewKeyData(a.dekTemplate) 86*e7b1675dSTing-Kang Chang if err != nil { 87*e7b1675dSTing-Kang Chang return nil, err 88*e7b1675dSTing-Kang Chang } 89*e7b1675dSTing-Kang Chang dek := dekKeyData.GetValue() 90*e7b1675dSTing-Kang Chang encryptedDEK, err := a.remote.Encrypt(dek, []byte{}) 91*e7b1675dSTing-Kang Chang if err != nil { 92*e7b1675dSTing-Kang Chang return nil, err 93*e7b1675dSTing-Kang Chang } 94*e7b1675dSTing-Kang Chang p, err := registry.Primitive(a.dekTemplate.TypeUrl, dek) 95*e7b1675dSTing-Kang Chang if err != nil { 96*e7b1675dSTing-Kang Chang return nil, err 97*e7b1675dSTing-Kang Chang } 98*e7b1675dSTing-Kang Chang primitive, ok := p.(tink.AEAD) 99*e7b1675dSTing-Kang Chang if !ok { 100*e7b1675dSTing-Kang Chang return nil, errors.New("kms_envelope_aead: failed to convert AEAD primitive") 101*e7b1675dSTing-Kang Chang } 102*e7b1675dSTing-Kang Chang 103*e7b1675dSTing-Kang Chang payload, err := primitive.Encrypt(pt, aad) 104*e7b1675dSTing-Kang Chang if err != nil { 105*e7b1675dSTing-Kang Chang return nil, err 106*e7b1675dSTing-Kang Chang } 107*e7b1675dSTing-Kang Chang if len(encryptedDEK) > maxUint32Size { 108*e7b1675dSTing-Kang Chang return nil, errors.New("kms_envelope_aead: encrypted dek too large") 109*e7b1675dSTing-Kang Chang } 110*e7b1675dSTing-Kang Chang res := make([]byte, 0, lenDEK+len(encryptedDEK)+len(payload)) 111*e7b1675dSTing-Kang Chang res = binary.BigEndian.AppendUint32(res, uint32(len(encryptedDEK))) 112*e7b1675dSTing-Kang Chang res = append(res, encryptedDEK...) 113*e7b1675dSTing-Kang Chang res = append(res, payload...) 114*e7b1675dSTing-Kang Chang return res, nil 115*e7b1675dSTing-Kang Chang} 116*e7b1675dSTing-Kang Chang 117*e7b1675dSTing-Kang Chang// Decrypt implements the tink.AEAD interface for decryption. 118*e7b1675dSTing-Kang Changfunc (a *KMSEnvelopeAEAD) Decrypt(ct, aad []byte) ([]byte, error) { 119*e7b1675dSTing-Kang Chang if a.err != nil { 120*e7b1675dSTing-Kang Chang return nil, a.err 121*e7b1675dSTing-Kang Chang } 122*e7b1675dSTing-Kang Chang // Verify we have enough bytes for the length of the encrypted DEK. 123*e7b1675dSTing-Kang Chang if len(ct) <= lenDEK { 124*e7b1675dSTing-Kang Chang return nil, errors.New("kms_envelope_aead: invalid ciphertext") 125*e7b1675dSTing-Kang Chang } 126*e7b1675dSTing-Kang Chang 127*e7b1675dSTing-Kang Chang // Extract length of encrypted DEK and advance past that length. 128*e7b1675dSTing-Kang Chang ed := int(binary.BigEndian.Uint32(ct[:lenDEK])) 129*e7b1675dSTing-Kang Chang ct = ct[lenDEK:] 130*e7b1675dSTing-Kang Chang 131*e7b1675dSTing-Kang Chang // Verify we have enough bytes for the encrypted DEK. 132*e7b1675dSTing-Kang Chang if ed <= 0 || len(ct) < ed { 133*e7b1675dSTing-Kang Chang return nil, errors.New("kms_envelope_aead: invalid ciphertext") 134*e7b1675dSTing-Kang Chang } 135*e7b1675dSTing-Kang Chang 136*e7b1675dSTing-Kang Chang // Extract the encrypted DEK and the payload. 137*e7b1675dSTing-Kang Chang encryptedDEK := ct[:ed] 138*e7b1675dSTing-Kang Chang payload := ct[ed:] 139*e7b1675dSTing-Kang Chang ct = nil 140*e7b1675dSTing-Kang Chang 141*e7b1675dSTing-Kang Chang // Decrypt the DEK. 142*e7b1675dSTing-Kang Chang dek, err := a.remote.Decrypt(encryptedDEK, []byte{}) 143*e7b1675dSTing-Kang Chang if err != nil { 144*e7b1675dSTing-Kang Chang return nil, err 145*e7b1675dSTing-Kang Chang } 146*e7b1675dSTing-Kang Chang 147*e7b1675dSTing-Kang Chang // Get an AEAD primitive corresponding to the DEK. 148*e7b1675dSTing-Kang Chang p, err := registry.Primitive(a.dekTemplate.TypeUrl, dek) 149*e7b1675dSTing-Kang Chang if err != nil { 150*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("kms_envelope_aead: %s", err) 151*e7b1675dSTing-Kang Chang } 152*e7b1675dSTing-Kang Chang primitive, ok := p.(tink.AEAD) 153*e7b1675dSTing-Kang Chang if !ok { 154*e7b1675dSTing-Kang Chang return nil, errors.New("kms_envelope_aead: failed to convert AEAD primitive") 155*e7b1675dSTing-Kang Chang } 156*e7b1675dSTing-Kang Chang 157*e7b1675dSTing-Kang Chang // Decrypt the payload. 158*e7b1675dSTing-Kang Chang return primitive.Decrypt(payload, aad) 159*e7b1675dSTing-Kang Chang} 160