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