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 daead 18*e7b1675dSTing-Kang Chang 19*e7b1675dSTing-Kang Changimport ( 20*e7b1675dSTing-Kang Chang "fmt" 21*e7b1675dSTing-Kang Chang 22*e7b1675dSTing-Kang Chang "github.com/google/tink/go/core/cryptofmt" 23*e7b1675dSTing-Kang Chang "github.com/google/tink/go/core/primitiveset" 24*e7b1675dSTing-Kang Chang "github.com/google/tink/go/internal/internalregistry" 25*e7b1675dSTing-Kang Chang "github.com/google/tink/go/internal/monitoringutil" 26*e7b1675dSTing-Kang Chang "github.com/google/tink/go/keyset" 27*e7b1675dSTing-Kang Chang "github.com/google/tink/go/monitoring" 28*e7b1675dSTing-Kang Chang "github.com/google/tink/go/tink" 29*e7b1675dSTing-Kang Chang) 30*e7b1675dSTing-Kang Chang 31*e7b1675dSTing-Kang Chang// New returns a DeterministicAEAD primitive from the given keyset handle. 32*e7b1675dSTing-Kang Changfunc New(handle *keyset.Handle) (tink.DeterministicAEAD, error) { 33*e7b1675dSTing-Kang Chang ps, err := handle.Primitives() 34*e7b1675dSTing-Kang Chang if err != nil { 35*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("daead_factory: cannot obtain primitive set: %s", err) 36*e7b1675dSTing-Kang Chang } 37*e7b1675dSTing-Kang Chang return newWrappedDeterministicAEAD(ps) 38*e7b1675dSTing-Kang Chang} 39*e7b1675dSTing-Kang Chang 40*e7b1675dSTing-Kang Chang// wrappedDeterministicAEAD is a DeterministicAEAD implementation that uses an underlying primitive set 41*e7b1675dSTing-Kang Chang// for deterministic encryption and decryption. 42*e7b1675dSTing-Kang Changtype wrappedDeterministicAEAD struct { 43*e7b1675dSTing-Kang Chang ps *primitiveset.PrimitiveSet 44*e7b1675dSTing-Kang Chang encLogger monitoring.Logger 45*e7b1675dSTing-Kang Chang decLogger monitoring.Logger 46*e7b1675dSTing-Kang Chang} 47*e7b1675dSTing-Kang Chang 48*e7b1675dSTing-Kang Chang// Asserts that wrappedDeterministicAEAD implements the DeterministicAEAD interface. 49*e7b1675dSTing-Kang Changvar _ tink.DeterministicAEAD = (*wrappedDeterministicAEAD)(nil) 50*e7b1675dSTing-Kang Chang 51*e7b1675dSTing-Kang Changfunc newWrappedDeterministicAEAD(ps *primitiveset.PrimitiveSet) (*wrappedDeterministicAEAD, error) { 52*e7b1675dSTing-Kang Chang if _, ok := (ps.Primary.Primitive).(tink.DeterministicAEAD); !ok { 53*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("daead_factory: not a DeterministicAEAD primitive") 54*e7b1675dSTing-Kang Chang } 55*e7b1675dSTing-Kang Chang 56*e7b1675dSTing-Kang Chang for _, primitives := range ps.Entries { 57*e7b1675dSTing-Kang Chang for _, p := range primitives { 58*e7b1675dSTing-Kang Chang if _, ok := (p.Primitive).(tink.DeterministicAEAD); !ok { 59*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("daead_factory: not a DeterministicAEAD primitive") 60*e7b1675dSTing-Kang Chang } 61*e7b1675dSTing-Kang Chang } 62*e7b1675dSTing-Kang Chang } 63*e7b1675dSTing-Kang Chang encLogger, decLogger, err := createLoggers(ps) 64*e7b1675dSTing-Kang Chang if err != nil { 65*e7b1675dSTing-Kang Chang return nil, err 66*e7b1675dSTing-Kang Chang } 67*e7b1675dSTing-Kang Chang return &wrappedDeterministicAEAD{ 68*e7b1675dSTing-Kang Chang ps: ps, 69*e7b1675dSTing-Kang Chang encLogger: encLogger, 70*e7b1675dSTing-Kang Chang decLogger: decLogger, 71*e7b1675dSTing-Kang Chang }, nil 72*e7b1675dSTing-Kang Chang} 73*e7b1675dSTing-Kang Chang 74*e7b1675dSTing-Kang Changfunc createLoggers(ps *primitiveset.PrimitiveSet) (monitoring.Logger, monitoring.Logger, error) { 75*e7b1675dSTing-Kang Chang if len(ps.Annotations) == 0 { 76*e7b1675dSTing-Kang Chang return &monitoringutil.DoNothingLogger{}, &monitoringutil.DoNothingLogger{}, nil 77*e7b1675dSTing-Kang Chang } 78*e7b1675dSTing-Kang Chang client := internalregistry.GetMonitoringClient() 79*e7b1675dSTing-Kang Chang keysetInfo, err := monitoringutil.KeysetInfoFromPrimitiveSet(ps) 80*e7b1675dSTing-Kang Chang if err != nil { 81*e7b1675dSTing-Kang Chang return nil, nil, err 82*e7b1675dSTing-Kang Chang } 83*e7b1675dSTing-Kang Chang encLogger, err := client.NewLogger(&monitoring.Context{ 84*e7b1675dSTing-Kang Chang Primitive: "daead", 85*e7b1675dSTing-Kang Chang APIFunction: "encrypt", 86*e7b1675dSTing-Kang Chang KeysetInfo: keysetInfo, 87*e7b1675dSTing-Kang Chang }) 88*e7b1675dSTing-Kang Chang if err != nil { 89*e7b1675dSTing-Kang Chang return nil, nil, err 90*e7b1675dSTing-Kang Chang } 91*e7b1675dSTing-Kang Chang decLogger, err := client.NewLogger(&monitoring.Context{ 92*e7b1675dSTing-Kang Chang Primitive: "daead", 93*e7b1675dSTing-Kang Chang APIFunction: "decrypt", 94*e7b1675dSTing-Kang Chang KeysetInfo: keysetInfo, 95*e7b1675dSTing-Kang Chang }) 96*e7b1675dSTing-Kang Chang if err != nil { 97*e7b1675dSTing-Kang Chang return nil, nil, err 98*e7b1675dSTing-Kang Chang } 99*e7b1675dSTing-Kang Chang return encLogger, decLogger, nil 100*e7b1675dSTing-Kang Chang} 101*e7b1675dSTing-Kang Chang 102*e7b1675dSTing-Kang Chang// EncryptDeterministically deterministically encrypts plaintext with additionalData as additional authenticated data. 103*e7b1675dSTing-Kang Chang// It returns the concatenation of the primary's identifier and the ciphertext. 104*e7b1675dSTing-Kang Changfunc (d *wrappedDeterministicAEAD) EncryptDeterministically(pt, aad []byte) ([]byte, error) { 105*e7b1675dSTing-Kang Chang primary := d.ps.Primary 106*e7b1675dSTing-Kang Chang p, ok := (primary.Primitive).(tink.DeterministicAEAD) 107*e7b1675dSTing-Kang Chang if !ok { 108*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("daead_factory: not a DeterministicAEAD primitive") 109*e7b1675dSTing-Kang Chang } 110*e7b1675dSTing-Kang Chang 111*e7b1675dSTing-Kang Chang ct, err := p.EncryptDeterministically(pt, aad) 112*e7b1675dSTing-Kang Chang if err != nil { 113*e7b1675dSTing-Kang Chang d.encLogger.LogFailure() 114*e7b1675dSTing-Kang Chang return nil, err 115*e7b1675dSTing-Kang Chang } 116*e7b1675dSTing-Kang Chang d.encLogger.Log(primary.KeyID, len(pt)) 117*e7b1675dSTing-Kang Chang if len(primary.Prefix) == 0 { 118*e7b1675dSTing-Kang Chang return ct, nil 119*e7b1675dSTing-Kang Chang } 120*e7b1675dSTing-Kang Chang output := make([]byte, 0, len(primary.Prefix)+len(ct)) 121*e7b1675dSTing-Kang Chang output = append(output, primary.Prefix...) 122*e7b1675dSTing-Kang Chang output = append(output, ct...) 123*e7b1675dSTing-Kang Chang return output, nil 124*e7b1675dSTing-Kang Chang} 125*e7b1675dSTing-Kang Chang 126*e7b1675dSTing-Kang Chang// DecryptDeterministically deterministically decrypts ciphertext with additionalData as 127*e7b1675dSTing-Kang Chang// additional authenticated data. It returns the corresponding plaintext if the 128*e7b1675dSTing-Kang Chang// ciphertext is authenticated. 129*e7b1675dSTing-Kang Changfunc (d *wrappedDeterministicAEAD) DecryptDeterministically(ct, aad []byte) ([]byte, error) { 130*e7b1675dSTing-Kang Chang // try non-raw keys 131*e7b1675dSTing-Kang Chang prefixSize := cryptofmt.NonRawPrefixSize 132*e7b1675dSTing-Kang Chang if len(ct) > prefixSize { 133*e7b1675dSTing-Kang Chang prefix := ct[:prefixSize] 134*e7b1675dSTing-Kang Chang ctNoPrefix := ct[prefixSize:] 135*e7b1675dSTing-Kang Chang entries, err := d.ps.EntriesForPrefix(string(prefix)) 136*e7b1675dSTing-Kang Chang if err == nil { 137*e7b1675dSTing-Kang Chang for i := 0; i < len(entries); i++ { 138*e7b1675dSTing-Kang Chang p, ok := (entries[i].Primitive).(tink.DeterministicAEAD) 139*e7b1675dSTing-Kang Chang if !ok { 140*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("daead_factory: not a DeterministicAEAD primitive") 141*e7b1675dSTing-Kang Chang } 142*e7b1675dSTing-Kang Chang 143*e7b1675dSTing-Kang Chang pt, err := p.DecryptDeterministically(ctNoPrefix, aad) 144*e7b1675dSTing-Kang Chang if err == nil { 145*e7b1675dSTing-Kang Chang d.decLogger.Log(entries[i].KeyID, len(ctNoPrefix)) 146*e7b1675dSTing-Kang Chang return pt, nil 147*e7b1675dSTing-Kang Chang } 148*e7b1675dSTing-Kang Chang } 149*e7b1675dSTing-Kang Chang } 150*e7b1675dSTing-Kang Chang } 151*e7b1675dSTing-Kang Chang 152*e7b1675dSTing-Kang Chang // try raw keys 153*e7b1675dSTing-Kang Chang entries, err := d.ps.RawEntries() 154*e7b1675dSTing-Kang Chang if err == nil { 155*e7b1675dSTing-Kang Chang for i := 0; i < len(entries); i++ { 156*e7b1675dSTing-Kang Chang p, ok := (entries[i].Primitive).(tink.DeterministicAEAD) 157*e7b1675dSTing-Kang Chang if !ok { 158*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("daead_factory: not a DeterministicAEAD primitive") 159*e7b1675dSTing-Kang Chang } 160*e7b1675dSTing-Kang Chang 161*e7b1675dSTing-Kang Chang pt, err := p.DecryptDeterministically(ct, aad) 162*e7b1675dSTing-Kang Chang if err == nil { 163*e7b1675dSTing-Kang Chang d.decLogger.Log(entries[i].KeyID, len(ct)) 164*e7b1675dSTing-Kang Chang return pt, nil 165*e7b1675dSTing-Kang Chang } 166*e7b1675dSTing-Kang Chang } 167*e7b1675dSTing-Kang Chang } 168*e7b1675dSTing-Kang Chang // nothing worked 169*e7b1675dSTing-Kang Chang d.decLogger.LogFailure() 170*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("daead_factory: decryption failed") 171*e7b1675dSTing-Kang Chang} 172