1 // Copyright 2017 Google Inc. 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 com.google.crypto.tink; 18 19 import com.google.crypto.tink.proto.KeyData; 20 import com.google.crypto.tink.proto.KeyStatusType; 21 import com.google.crypto.tink.proto.Keyset; 22 import com.google.crypto.tink.proto.KeysetInfo; 23 import com.google.crypto.tink.proto.OutputPrefixType; 24 import java.io.ByteArrayOutputStream; 25 import java.io.IOException; 26 import java.io.InputStream; 27 import java.nio.charset.Charset; 28 import java.security.GeneralSecurityException; 29 30 /** Various helpers. */ 31 final class Util { 32 public static final Charset UTF_8 = Charset.forName("UTF-8"); 33 34 /** @return a KeysetInfo-proto from a {@code keyset} protobuf. */ getKeysetInfo(Keyset keyset)35 public static KeysetInfo getKeysetInfo(Keyset keyset) { 36 KeysetInfo.Builder info = KeysetInfo.newBuilder().setPrimaryKeyId(keyset.getPrimaryKeyId()); 37 for (Keyset.Key key : keyset.getKeyList()) { 38 info.addKeyInfo(getKeyInfo(key)); 39 } 40 return info.build(); 41 } 42 43 /** @return a KeyInfo-proto from a {@code key} protobuf. */ getKeyInfo(Keyset.Key key)44 public static KeysetInfo.KeyInfo getKeyInfo(Keyset.Key key) { 45 return KeysetInfo.KeyInfo.newBuilder() 46 .setTypeUrl(key.getKeyData().getTypeUrl()) 47 .setStatus(key.getStatus()) 48 .setOutputPrefixType(key.getOutputPrefixType()) 49 .setKeyId(key.getKeyId()) 50 .build(); 51 } 52 53 /** 54 * Validates a {@code key}. 55 * 56 * @throws GeneralSecurityException if {@code key} is invalid. 57 */ validateKey(Keyset.Key key)58 public static void validateKey(Keyset.Key key) throws GeneralSecurityException { 59 if (!key.hasKeyData()) { 60 throw new GeneralSecurityException(String.format("key %d has no key data", key.getKeyId())); 61 } 62 63 if (key.getOutputPrefixType() == OutputPrefixType.UNKNOWN_PREFIX) { 64 throw new GeneralSecurityException( 65 String.format("key %d has unknown prefix", key.getKeyId())); 66 } 67 68 if (key.getStatus() == KeyStatusType.UNKNOWN_STATUS) { 69 throw new GeneralSecurityException( 70 String.format("key %d has unknown status", key.getKeyId())); 71 } 72 } 73 74 /** 75 * Validates a {@code Keyset}. 76 * 77 * @throws GeneralSecurityException if {@code keyset} is invalid. 78 */ validateKeyset(Keyset keyset)79 public static void validateKeyset(Keyset keyset) throws GeneralSecurityException { 80 int primaryKeyId = keyset.getPrimaryKeyId(); 81 boolean hasPrimaryKey = false; 82 boolean containsOnlyPublicKeyMaterial = true; 83 int numEnabledKeys = 0; 84 for (Keyset.Key key : keyset.getKeyList()) { 85 if (key.getStatus() != KeyStatusType.ENABLED) { 86 continue; 87 } 88 validateKey(key); 89 if (key.getKeyId() == primaryKeyId) { 90 if (hasPrimaryKey) { 91 throw new GeneralSecurityException("keyset contains multiple primary keys"); 92 } 93 hasPrimaryKey = true; 94 } 95 if (key.getKeyData().getKeyMaterialType() != KeyData.KeyMaterialType.ASYMMETRIC_PUBLIC) { 96 containsOnlyPublicKeyMaterial = false; 97 } 98 numEnabledKeys++; 99 } 100 if (numEnabledKeys == 0) { 101 throw new GeneralSecurityException("keyset must contain at least one ENABLED key"); 102 } 103 // Checks that a keyset contains a primary key, except when it contains only public keys. 104 if (!hasPrimaryKey && !containsOnlyPublicKeyMaterial) { 105 throw new GeneralSecurityException("keyset doesn't contain a valid primary key"); 106 } 107 } 108 109 /** 110 * Reads all bytes from {@code inputStream}. 111 */ readAll(InputStream inputStream)112 public static byte[] readAll(InputStream inputStream) throws IOException { 113 ByteArrayOutputStream result = new ByteArrayOutputStream(); 114 byte[] buf = new byte[1024]; 115 int count; 116 while ((count = inputStream.read(buf)) != -1) { 117 result.write(buf, 0, count); 118 } 119 return result.toByteArray(); 120 } 121 Util()122 private Util() {} 123 } 124