• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 package com.google.crypto.tink.tinkkey;
17 
18 import static com.google.crypto.tink.internal.KeyTemplateProtoConverter.getOutputPrefixType;
19 
20 import com.google.crypto.tink.KeyManager;
21 import com.google.crypto.tink.KeyTemplate;
22 import com.google.crypto.tink.KeyTemplate.OutputPrefixType;
23 import com.google.crypto.tink.TinkProtoParametersFormat;
24 import com.google.crypto.tink.internal.KeyManagerRegistry;
25 import com.google.crypto.tink.internal.Util;
26 import com.google.crypto.tink.proto.KeyData;
27 import com.google.crypto.tink.tinkkey.internal.ProtoKey;
28 import com.google.errorprone.annotations.Immutable;
29 import com.google.protobuf.ExtensionRegistryLite;
30 import com.google.protobuf.InvalidProtocolBufferException;
31 import java.security.GeneralSecurityException;
32 
33 /**
34  * Wraps a {@link TinkKey} and enforces access to the underlying {@link TinkKey} with {@link
35  * KeyAccess}. Specifically, if the underlying {@link TinkKey} has a secret, then one can only get
36  * it with a {@link SecretKeyAccess} instance.
37  *
38  * <p>Do not use this in new code. Instead, use {@link com.google.crypto.tink.Key} and
39  * these facilities.
40  */
41 @Immutable
42 public class KeyHandle {
newKeyData(com.google.crypto.tink.KeyTemplate keyTemplate)43   private static KeyData newKeyData(com.google.crypto.tink.KeyTemplate keyTemplate)
44       throws GeneralSecurityException {
45     try {
46       byte[] serializedKeyTemplate =
47           TinkProtoParametersFormat.serialize(keyTemplate.toParameters());
48       com.google.crypto.tink.proto.KeyTemplate protoTemplate =
49           com.google.crypto.tink.proto.KeyTemplate.parseFrom(
50               serializedKeyTemplate, ExtensionRegistryLite.getEmptyRegistry());
51       KeyManager<?> manager =
52           KeyManagerRegistry.globalInstance().getUntypedKeyManager(protoTemplate.getTypeUrl());
53       if (KeyManagerRegistry.globalInstance().isNewKeyAllowed(protoTemplate.getTypeUrl())) {
54         return manager.newKeyData(protoTemplate.getValue());
55       } else {
56         throw new GeneralSecurityException(
57             "newKey-operation not permitted for key type " + protoTemplate.getTypeUrl());
58       }
59     } catch (InvalidProtocolBufferException e) {
60       throw new GeneralSecurityException("Failed to parse serialized parameters", e);
61     }
62   }
63 
64   /**
65    * KeyStatusType is metadata associated to a key which is only meaningful when the key is part of
66    * a {@link Keyset}. A key's status in the Keyset is either ENABLED (able to perform cryptographic
67    * operations), DISABLED (unable to perform operations, but could be re-enabled), or DESTROYED
68    * (the key's data is no longer present in the keyset).
69    */
70   public enum KeyStatusType {
71     ENABLED,
72     DISABLED,
73     DESTROYED;
74   }
75 
76   /**
77    * Returns a {@link KeyHandle} instance with {@code key} as the underlying {@link TinkKey} if the
78    * caller provides the correct {@link KeyAccess} instance.
79    *
80    * @throws GeneralSecurityException if {@code access} does not grant access to {@code key}
81    */
createFromKey(TinkKey key, KeyAccess access)82   public static KeyHandle createFromKey(TinkKey key, KeyAccess access)
83       throws GeneralSecurityException {
84     KeyHandle result = new KeyHandle(key);
85     result.checkAccess(access);
86     return result;
87   }
88 
89   /**
90    * Returns a {@link KeyHandle} instance where the underlying {@link TinkKey} wraps the input
91    * {@code keyData}. The returned KeyHandle has a secret if keyData has key material of type
92    * UNKNOWN_KEYMATERIAL, SYMMETRIC, or ASYMMETRIC_PRIVATE.
93    *
94    * <p>Do not use this in new code. Instead, use {@link com.google.crypto.tink.Key} and these
95    * facilities.
96    */
createFromKey(KeyData keyData, OutputPrefixType opt)97   public static KeyHandle createFromKey(KeyData keyData, OutputPrefixType opt) {
98     return new KeyHandle(new ProtoKey(keyData, opt));
99   }
100 
101   private final TinkKey key;
102   private final KeyStatusType status;
103   private final int id;
104 
105   /**
106    * Constructs a KeyHandle wrapping the input TinkKey. The KeyStatusType is set to ENABLED and an
107    * arbitrary key ID is assigned.
108    */
KeyHandle(TinkKey key)109   private KeyHandle(TinkKey key) {
110     this.key = key;
111     this.status = KeyStatusType.ENABLED;
112     this.id = Util.randKeyId();
113   }
114 
115   /**
116    * Constructor intended for Tink internal purposes; allows one to set all the member variables of
117    * a {@link KeyHandle}.
118    */
KeyHandle(TinkKey key, KeyStatusType status, int keyId)119   protected KeyHandle(TinkKey key, KeyStatusType status, int keyId) {
120     this.key = key;
121     this.status = status;
122     this.id = keyId;
123   }
124 
125   /**
126    * Generates a new {@link KeyHandle} that contains a fresh key generated according to {@code
127    * keyTemplate}.
128    *
129    * @throws GeneralSecurityException if the key template's type URL has not been registered with
130    *     the {@link Registry}.
131    */
generateNew(KeyTemplate keyTemplate)132   public static KeyHandle generateNew(KeyTemplate keyTemplate) throws GeneralSecurityException {
133     ProtoKey protoKey = new ProtoKey(newKeyData(keyTemplate), getOutputPrefixType(keyTemplate));
134     return new KeyHandle(protoKey);
135   }
136 
137   /** Returns {@code true} if the underlying {@link TinkKey} has a secret. */
hasSecret()138   public boolean hasSecret() {
139     return key.hasSecret();
140   }
141 
142   /** Returns the status of the key. See {@link KeyStatusType}. */
getStatus()143   public KeyStatusType getStatus() {
144     return this.status;
145   }
146 
147   /**
148    * Returns the key ID of this key. The key ID is not guaranteed to be unique among all KeyHandles.
149    */
getId()150   public int getId() {
151     return id;
152   }
153 
154   /**
155    * Returns the underlying {@link TinkKey} key if {@code access} is a {@link SecretKeyAccess} and
156    * the key has a secret, or if the key does not have a secret, otherwise throws a {@link
157    * GeneralSecurityException}.
158    */
getKey(KeyAccess access)159   public TinkKey getKey(KeyAccess access) throws GeneralSecurityException {
160     checkAccess(access);
161     return key;
162   }
163 
164   /**
165    * Returns the {@link KeyTemplate} of the underlying {@link TinkKey}.
166    *
167    * @throws UnsupportedOperationException if the underlying {@link TinkKey} has not implemented
168    *     getKeyTemplate().
169    */
getKeyTemplate()170   public KeyTemplate getKeyTemplate() {
171     return key.getKeyTemplate();
172   }
173 
checkAccess(KeyAccess access)174   private void checkAccess(KeyAccess access) throws GeneralSecurityException {
175     if (hasSecret() && !access.canAccessSecret()) {
176       throw new GeneralSecurityException("No access");
177     }
178   }
179 }
180