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 17package prf_test 18 19import ( 20 "encoding/hex" 21 "fmt" 22 "testing" 23 24 "google.golang.org/protobuf/proto" 25 "github.com/google/tink/go/core/registry" 26 "github.com/google/tink/go/prf" 27 "github.com/google/tink/go/prf/subtle" 28 "github.com/google/tink/go/subtle/random" 29 "github.com/google/tink/go/testutil" 30 cmacpb "github.com/google/tink/go/proto/aes_cmac_prf_go_proto" 31 commonpb "github.com/google/tink/go/proto/common_go_proto" 32 tinkpb "github.com/google/tink/go/proto/tink_go_proto" 33) 34 35func TestGetPrimitiveCMACBasic(t *testing.T) { 36 km, err := registry.GetKeyManager(testutil.AESCMACPRFTypeURL) 37 if err != nil { 38 t.Errorf("AES CMAC PRF key manager not found: %s", err) 39 } 40 testKeys := genValidCMACKeys() 41 for i := 0; i < len(testKeys); i++ { 42 serializedKey, _ := proto.Marshal(testKeys[i]) 43 p, err := km.Primitive(serializedKey) 44 if err != nil { 45 t.Errorf("unexpected error in test case %d: %s", i, err) 46 } 47 if err := validateCMACPrimitive(p, testKeys[i]); err != nil { 48 t.Errorf("%s", err) 49 } 50 } 51} 52 53func TestGetPrimitiveCMACWithInvalidInput(t *testing.T) { 54 km, err := registry.GetKeyManager(testutil.AESCMACPRFTypeURL) 55 if err != nil { 56 t.Errorf("cannot obtain AES CMAC PRF key manager: %s", err) 57 } 58 // invalid key 59 testKeys := genInvalidCMACKeys() 60 for i := 0; i < len(testKeys); i++ { 61 serializedKey, _ := proto.Marshal(testKeys[i]) 62 if _, err := km.Primitive(serializedKey); err == nil { 63 t.Errorf("expect an error in test case %d", i) 64 } 65 } 66 if _, err := km.Primitive(nil); err == nil { 67 t.Errorf("expect an error when input is nil") 68 } 69 // empty input 70 if _, err := km.Primitive([]byte{}); err == nil { 71 t.Errorf("expect an error when input is empty") 72 } 73} 74 75func TestNewKeyCMACMultipleTimes(t *testing.T) { 76 km, err := registry.GetKeyManager(testutil.AESCMACPRFTypeURL) 77 if err != nil { 78 t.Errorf("cannot obtain AES CMAC PRF key manager: %s", err) 79 } 80 serializedFormat, _ := proto.Marshal(testutil.NewAESCMACPRFKeyFormat()) 81 keys := make(map[string]bool) 82 nTest := 26 83 for i := 0; i < nTest; i++ { 84 key, _ := km.NewKey(serializedFormat) 85 serializedKey, _ := proto.Marshal(key) 86 keys[string(serializedKey)] = true 87 88 keyData, _ := km.NewKeyData(serializedFormat) 89 serializedKey = keyData.Value 90 keys[string(serializedKey)] = true 91 } 92 if len(keys) != nTest*2 { 93 t.Errorf("key is repeated") 94 } 95} 96 97func TestNewKeyCMACBasic(t *testing.T) { 98 km, err := registry.GetKeyManager(testutil.AESCMACPRFTypeURL) 99 if err != nil { 100 t.Errorf("cannot obtain AES CMAC PRF key manager: %s", err) 101 } 102 testFormats := genValidCMACKeyFormats() 103 for i := 0; i < len(testFormats); i++ { 104 serializedFormat, _ := proto.Marshal(testFormats[i]) 105 key, err := km.NewKey(serializedFormat) 106 if err != nil { 107 t.Errorf("unexpected error in test case %d: %s", i, err) 108 } 109 if err := validateCMACKey(testFormats[i], key.(*cmacpb.AesCmacPrfKey)); err != nil { 110 t.Errorf("%s", err) 111 } 112 } 113} 114 115func TestNewKeyCMACWithInvalidInput(t *testing.T) { 116 km, err := registry.GetKeyManager(testutil.AESCMACPRFTypeURL) 117 if err != nil { 118 t.Errorf("cannot obtain AES CMAC PRF key manager: %s", err) 119 } 120 // invalid key formats 121 testFormats := genInvalidCMACKeyFormats() 122 for i := 0; i < len(testFormats); i++ { 123 serializedFormat, err := proto.Marshal(testFormats[i]) 124 if err != nil { 125 fmt.Println("Error!") 126 } 127 if _, err := km.NewKey(serializedFormat); err == nil { 128 t.Errorf("expect an error in test case %d: %s", i, err) 129 } 130 } 131 if _, err := km.NewKey(nil); err == nil { 132 t.Errorf("expect an error when input is nil") 133 } 134 // empty input 135 if _, err := km.NewKey([]byte{}); err == nil { 136 t.Errorf("expect an error when input is empty") 137 } 138} 139 140func TestNewKeyDataCMACBasic(t *testing.T) { 141 km, err := registry.GetKeyManager(testutil.AESCMACPRFTypeURL) 142 if err != nil { 143 t.Errorf("cannot obtain AES CMAC PRF key manager: %s", err) 144 } 145 testFormats := genValidCMACKeyFormats() 146 for i := 0; i < len(testFormats); i++ { 147 serializedFormat, _ := proto.Marshal(testFormats[i]) 148 keyData, err := km.NewKeyData(serializedFormat) 149 if err != nil { 150 t.Errorf("unexpected error in test case %d: %s", i, err) 151 } 152 if keyData.TypeUrl != testutil.AESCMACPRFTypeURL { 153 t.Errorf("incorrect type url in test case %d", i) 154 } 155 if keyData.KeyMaterialType != tinkpb.KeyData_SYMMETRIC { 156 t.Errorf("incorrect key material type in test case %d", i) 157 } 158 key := new(cmacpb.AesCmacPrfKey) 159 if err := proto.Unmarshal(keyData.Value, key); err != nil { 160 t.Errorf("invalid key value") 161 } 162 if err := validateCMACKey(testFormats[i], key); err != nil { 163 t.Errorf("invalid key") 164 } 165 } 166} 167 168func TestNewKeyDataCMACWithInvalidInput(t *testing.T) { 169 km, err := registry.GetKeyManager(testutil.AESCMACPRFTypeURL) 170 if err != nil { 171 t.Errorf("AES CMAC PRF key manager not found: %s", err) 172 } 173 // invalid key formats 174 testFormats := genInvalidCMACKeyFormats() 175 for i := 0; i < len(testFormats); i++ { 176 serializedFormat, _ := proto.Marshal(testFormats[i]) 177 if _, err := km.NewKeyData(serializedFormat); err == nil { 178 t.Errorf("expect an error in test case %d", i) 179 } 180 } 181 // nil input 182 if _, err := km.NewKeyData(nil); err == nil { 183 t.Errorf("expect an error when input is nil") 184 } 185} 186 187func TestCMACDoesSupport(t *testing.T) { 188 km, err := registry.GetKeyManager(testutil.AESCMACPRFTypeURL) 189 if err != nil { 190 t.Errorf("AES CMAC PRF key manager not found: %s", err) 191 } 192 if !km.DoesSupport(testutil.AESCMACPRFTypeURL) { 193 t.Errorf("AESCMACPRFKeyManager must support %s", testutil.AESCMACPRFTypeURL) 194 } 195 if km.DoesSupport("some bad type") { 196 t.Errorf("AESCMACPRFKeyManager must support only %s", testutil.AESCMACPRFTypeURL) 197 } 198} 199 200func TestCMACTypeURL(t *testing.T) { 201 km, err := registry.GetKeyManager(testutil.AESCMACPRFTypeURL) 202 if err != nil { 203 t.Errorf("AES CMAC PRF key manager not found: %s", err) 204 } 205 if km.TypeURL() != testutil.AESCMACPRFTypeURL { 206 t.Errorf("incorrect GetKeyType()") 207 } 208} 209 210func genInvalidCMACKeys() []proto.Message { 211 badVersionKey := testutil.NewAESCMACPRFKey() 212 badVersionKey.Version++ 213 shortKey := testutil.NewAESCMACPRFKey() 214 shortKey.KeyValue = []byte{1, 1} 215 return []proto.Message{ 216 // not a AESCMACPRFKey 217 testutil.NewHMACParams(commonpb.HashType_SHA256, 32), 218 // bad version 219 badVersionKey, 220 // key too short 221 shortKey, 222 } 223} 224 225func genInvalidCMACKeyFormats() []proto.Message { 226 shortKeyFormat := testutil.NewAESCMACPRFKeyFormat() 227 shortKeyFormat.KeySize = 1 228 return []proto.Message{ 229 // not a AESCMACPRFKeyFormat 230 testutil.NewHMACParams(commonpb.HashType_SHA256, 32), 231 // key too short 232 shortKeyFormat, 233 } 234} 235 236func genValidCMACKeyFormats() []*cmacpb.AesCmacPrfKeyFormat { 237 return []*cmacpb.AesCmacPrfKeyFormat{ 238 testutil.NewAESCMACPRFKeyFormat(), 239 } 240} 241 242func genValidCMACKeys() []*cmacpb.AesCmacPrfKey { 243 return []*cmacpb.AesCmacPrfKey{ 244 testutil.NewAESCMACPRFKey(), 245 } 246} 247 248// Checks whether the given CMACPRFKey matches the given key AESCMACPRFKeyFormat 249func validateCMACKey(format *cmacpb.AesCmacPrfKeyFormat, key *cmacpb.AesCmacPrfKey) error { 250 if format.KeySize != uint32(len(key.KeyValue)) { 251 return fmt.Errorf("key format and generated key do not match") 252 } 253 p, err := subtle.NewAESCMACPRF(key.KeyValue) 254 if err != nil { 255 return fmt.Errorf("cannot create primitive from key: %s", err) 256 } 257 return validateCMACPrimitive(p, key) 258} 259 260// validateCMACPrimitive checks whether the given primitive matches the given AESCMACPRFKey 261func validateCMACPrimitive(p interface{}, key *cmacpb.AesCmacPrfKey) error { 262 cmacPrimitive := p.(prf.PRF) 263 prfPrimitive, err := subtle.NewAESCMACPRF(key.KeyValue) 264 if err != nil { 265 return fmt.Errorf("Could not create AES CMAC PRF with key material %q: %s", hex.EncodeToString(key.KeyValue), err) 266 } 267 data := random.GetRandomBytes(20) 268 res, err := cmacPrimitive.ComputePRF(data, 16) 269 if err != nil { 270 return fmt.Errorf("prf computation failed: %s", err) 271 } 272 if len(res) != 16 { 273 return fmt.Errorf("prf computation did not produce 16 byte output") 274 } 275 res2, err := prfPrimitive.ComputePRF(data, 16) 276 if err != nil { 277 return fmt.Errorf("prf computation failed: %s", err) 278 } 279 if len(res2) != 16 { 280 return fmt.Errorf("prf computation did not produce 16 byte output") 281 } 282 if hex.EncodeToString(res) != hex.EncodeToString(res2) { 283 return fmt.Errorf("prf computation did not produce the same output for the same key and input") 284 } 285 return nil 286} 287