1*e7b1675dSTing-Kang Chang// Copyright 2020 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 Chang// Package prf contains utilities to calculate pseudo random function families. 18*e7b1675dSTing-Kang Changpackage prf 19*e7b1675dSTing-Kang Chang 20*e7b1675dSTing-Kang Changimport ( 21*e7b1675dSTing-Kang Chang "fmt" 22*e7b1675dSTing-Kang Chang 23*e7b1675dSTing-Kang Chang "github.com/google/tink/go/core/registry" 24*e7b1675dSTing-Kang Chang "github.com/google/tink/go/internal/internalregistry" 25*e7b1675dSTing-Kang Chang "github.com/google/tink/go/monitoring" 26*e7b1675dSTing-Kang Chang) 27*e7b1675dSTing-Kang Chang 28*e7b1675dSTing-Kang Chang// The PRF interface is an abstraction for an element of a pseudo random 29*e7b1675dSTing-Kang Chang// function family, selected by a key. It has the following property: 30*e7b1675dSTing-Kang Chang// - It is deterministic. PRF.compute(input, length) will always return the 31*e7b1675dSTing-Kang Chang// same output if the same key is used. PRF.compute(input, length1) will be 32*e7b1675dSTing-Kang Chang// a prefix of PRF.compute(input, length2) if length1 < length2 and the same 33*e7b1675dSTing-Kang Chang// key is used. 34*e7b1675dSTing-Kang Chang// - It is indistinguishable from a random function: 35*e7b1675dSTing-Kang Chang// Given the evaluation of n different inputs, an attacker cannot 36*e7b1675dSTing-Kang Chang// distinguish between the PRF and random bytes on an input different from 37*e7b1675dSTing-Kang Chang// the n that are known. 38*e7b1675dSTing-Kang Chang// 39*e7b1675dSTing-Kang Chang// Use cases for PRF are deterministic redaction of PII, keyed hash functions, 40*e7b1675dSTing-Kang Chang// creating sub IDs that do not allow joining with the original dataset without 41*e7b1675dSTing-Kang Chang// knowing the key. 42*e7b1675dSTing-Kang Chang// While PRFs can be used in order to prove authenticity of a message, using the 43*e7b1675dSTing-Kang Chang// MAC interface is recommended for that use case, as it has support for 44*e7b1675dSTing-Kang Chang// verification, avoiding the security problems that often happen during 45*e7b1675dSTing-Kang Chang// verification, and having automatic support for key rotation. It also allows 46*e7b1675dSTing-Kang Chang// for non-deterministic MAC algorithms. 47*e7b1675dSTing-Kang Changtype PRF interface { 48*e7b1675dSTing-Kang Chang // Computes the PRF selected by the underlying key on input and 49*e7b1675dSTing-Kang Chang // returns the first outputLength bytes. 50*e7b1675dSTing-Kang Chang // When choosing this parameter keep the birthday paradox in mind. 51*e7b1675dSTing-Kang Chang // If you have 2^n different inputs that your system has to handle 52*e7b1675dSTing-Kang Chang // set the output length (in bytes) to at least 53*e7b1675dSTing-Kang Chang // ceil(n/4 + 4) 54*e7b1675dSTing-Kang Chang // This corresponds to 2*n + 32 bits, meaning a collision will occur with 55*e7b1675dSTing-Kang Chang // a probability less than 1:2^32. When in doubt, request a security review. 56*e7b1675dSTing-Kang Chang // Returns a non ok status if the algorithm fails or if the output of 57*e7b1675dSTing-Kang Chang // algorithm is less than outputLength. 58*e7b1675dSTing-Kang Chang ComputePRF(input []byte, outputLength uint32) ([]byte, error) 59*e7b1675dSTing-Kang Chang} 60*e7b1675dSTing-Kang Chang 61*e7b1675dSTing-Kang Changtype monitoredPRF struct { 62*e7b1675dSTing-Kang Chang prf PRF 63*e7b1675dSTing-Kang Chang keyID uint32 64*e7b1675dSTing-Kang Chang logger monitoring.Logger 65*e7b1675dSTing-Kang Chang} 66*e7b1675dSTing-Kang Chang 67*e7b1675dSTing-Kang Changvar _ PRF = (*monitoredPRF)(nil) 68*e7b1675dSTing-Kang Chang 69*e7b1675dSTing-Kang Changfunc (w *monitoredPRF) ComputePRF(input []byte, outputLength uint32) ([]byte, error) { 70*e7b1675dSTing-Kang Chang p, err := w.prf.ComputePRF(input, outputLength) 71*e7b1675dSTing-Kang Chang if err != nil { 72*e7b1675dSTing-Kang Chang w.logger.LogFailure() 73*e7b1675dSTing-Kang Chang return nil, err 74*e7b1675dSTing-Kang Chang } 75*e7b1675dSTing-Kang Chang w.logger.Log(w.keyID, len(input)) 76*e7b1675dSTing-Kang Chang return p, nil 77*e7b1675dSTing-Kang Chang} 78*e7b1675dSTing-Kang Chang 79*e7b1675dSTing-Kang Chang// Set is a set of PRFs. A Tink Keyset can be converted into a set of PRFs using this primitive. Every 80*e7b1675dSTing-Kang Chang// key in the keyset corresponds to a PRF in the prf.Set. 81*e7b1675dSTing-Kang Chang// Every PRF in the set is given an ID, which is the same ID as the key id in 82*e7b1675dSTing-Kang Chang// the Keyset. 83*e7b1675dSTing-Kang Changtype Set struct { 84*e7b1675dSTing-Kang Chang // PrimaryID is the key ID marked as primary in the corresponding Keyset. 85*e7b1675dSTing-Kang Chang PrimaryID uint32 86*e7b1675dSTing-Kang Chang // PRFs maps key IDs to their corresponding PRF. 87*e7b1675dSTing-Kang Chang PRFs map[uint32]PRF 88*e7b1675dSTing-Kang Chang} 89*e7b1675dSTing-Kang Chang 90*e7b1675dSTing-Kang Chang// ComputePrimaryPRF is equivalent to set.PRFs[set.PrimaryID].ComputePRF(input, outputLength). 91*e7b1675dSTing-Kang Changfunc (s Set) ComputePrimaryPRF(input []byte, outputLength uint32) ([]byte, error) { 92*e7b1675dSTing-Kang Chang prf, ok := s.PRFs[s.PrimaryID] 93*e7b1675dSTing-Kang Chang if !ok { 94*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("Could not find primary ID %d in prf.Set", s.PrimaryID) 95*e7b1675dSTing-Kang Chang } 96*e7b1675dSTing-Kang Chang return prf.ComputePRF(input, outputLength) 97*e7b1675dSTing-Kang Chang} 98*e7b1675dSTing-Kang Chang 99*e7b1675dSTing-Kang Changfunc init() { 100*e7b1675dSTing-Kang Chang if err := registry.RegisterKeyManager(new(hmacprfKeyManager)); err != nil { 101*e7b1675dSTing-Kang Chang panic(fmt.Sprintf("prf.init() failed: %v", err)) 102*e7b1675dSTing-Kang Chang } 103*e7b1675dSTing-Kang Chang if err := internalregistry.AllowKeyDerivation(hmacprfTypeURL); err != nil { 104*e7b1675dSTing-Kang Chang panic(fmt.Sprintf("prf.init() failed: %v", err)) 105*e7b1675dSTing-Kang Chang } 106*e7b1675dSTing-Kang Chang if err := registry.RegisterKeyManager(new(hkdfprfKeyManager)); err != nil { 107*e7b1675dSTing-Kang Chang panic(fmt.Sprintf("prf.init() failed: %v", err)) 108*e7b1675dSTing-Kang Chang } 109*e7b1675dSTing-Kang Chang if err := internalregistry.AllowKeyDerivation(hkdfprfTypeURL); err != nil { 110*e7b1675dSTing-Kang Chang panic(fmt.Sprintf("prf.init() failed: %v", err)) 111*e7b1675dSTing-Kang Chang } 112*e7b1675dSTing-Kang Chang if err := registry.RegisterKeyManager(new(aescmacprfKeyManager)); err != nil { 113*e7b1675dSTing-Kang Chang panic(fmt.Sprintf("prf.init() failed: %v", err)) 114*e7b1675dSTing-Kang Chang } 115*e7b1675dSTing-Kang Chang} 116