blob: eb6b86322e26dd93b71a18890a71a1d5288180c3 [file] [log] [blame]
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package com.google.crypto.tink.testing;
import com.google.crypto.tink.PrivilegedRegistry;
import com.google.crypto.tink.proto.Keyset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Provides a function {@link compareKeysets} which can compare two keysets.
*/
final class CompareKeysets {
// Compares two keys of a keyset. We parse the KeyData in each keyset in order to ensure we do not
// depend strongly on the serialization order of the tags; note that keysets may be serialized
// in different languages, and assuming that the fields are ordered in the same way when generated
// in each language seems relatively strong.
private static boolean equalKeys(Keyset.Key key1, Keyset.Key key2) throws Exception {
if (!key1.getStatus().equals(key2.getStatus())) {
return false;
}
if (key1.getKeyId() != key2.getKeyId()) {
return false;
}
if (!key1.getOutputPrefixType().equals(key2.getOutputPrefixType())) {
return false;
}
if (!key1.getKeyData().getKeyMaterialType().equals(key2.getKeyData().getKeyMaterialType())) {
return false;
}
if (!PrivilegedRegistry.parseKeyData(key1.getKeyData())
.equals(PrivilegedRegistry.parseKeyData(key2.getKeyData()))) {
return false;
}
return true;
}
/**
* Finds a key in {@param keyList} for which {@link areEqualKeys} returns true, removes it, and
* returns true. If not such key exists returns false.
*/
private static boolean findAndRemove(Keyset.Key key, List<Keyset.Key> keyList) throws Exception {
for (Keyset.Key key2 : keyList) {
if (equalKeys(key, key2)) {
keyList.remove(key2);
return true;
}
}
return false;
}
private static void compareKeysetLists(List<Keyset.Key> keyList1, List<Keyset.Key> keyList2)
throws Exception {
for (Keyset.Key key1 : keyList1) {
if (!findAndRemove(key1, keyList2)) {
throw new IllegalArgumentException("Key " + key1 + " not found in second keyset.");
}
}
}
/**
* Collects all keys with a fixed key id in a {@link List}, returning the result in a map from
* the key-id to this list.
*/
private static Map<Integer, List<Keyset.Key>> getKeyDataMap(Keyset keyset) {
Map<Integer, List<Keyset.Key>> result = new HashMap<>();
for (int i = 0; i < keyset.getKeyCount(); ++i) {
Keyset.Key key = keyset.getKey(i);
if (!result.containsKey(key.getKeyId())) {
result.put(key.getKeyId(), new ArrayList<Keyset.Key>());
}
result.get(key.getKeyId()).add(key);
}
return result;
}
/**
* Compares two keysets, throws some exception if the keyset are different.
*
* <p>If the keysets are different, this is guaranteed to throw an exception. If they are the same
* there are several possibilities why this will still throw an exception:
*
* <ul>
* <li>There is no key manager registered for one of the Keys used in the keyset
* <li>
* </ul>
*/
public static void compareKeysets(Keyset keyset1, Keyset keyset2) throws Exception {
if (keyset1.getPrimaryKeyId() != keyset2.getPrimaryKeyId()) {
throw new IllegalArgumentException(
"Given keysets contain different key ids. \n\nKeyset 1: "
+ keyset1
+ "\n\nKeyset2: "
+ keyset2);
}
if (keyset1.getKeyCount() != keyset2.getKeyCount()) {
throw new IllegalArgumentException(
"Given keysets contain different number of keys. \n\nKeyset 1: "
+ keyset1
+ "\n\nKeyset2: "
+ keyset2);
}
// The order of the keys in the keyset is considered irrelevant.
Map<Integer, List<Keyset.Key>> keyset1Map = getKeyDataMap(keyset1);
Map<Integer, List<Keyset.Key>> keyset2Map = getKeyDataMap(keyset2);
for (Map.Entry<Integer, List<Keyset.Key>> idToList : keyset1Map.entrySet()) {
if (!keyset2Map.containsKey(idToList.getKey())) {
throw new IllegalArgumentException(
"Keysets differ; the second one contains no key with id "
+ idToList.getKey()
+ ", but the first one does. \n\nKeyset 1: "
+ keyset1
+ "\n\nKeyset 2:"
+ keyset2);
}
compareKeysetLists(keyset2Map.get(idToList.getKey()), idToList.getValue());
}
}
private CompareKeysets() {
}
}