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