• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.aead;
18 
19 import static com.google.crypto.tink.internal.TinkBugException.exceptionIsBug;
20 
21 import com.google.crypto.tink.AccessesPartialKey;
22 import com.google.crypto.tink.Aead;
23 import com.google.crypto.tink.KeyManager;
24 import com.google.crypto.tink.KeyTemplate;
25 import com.google.crypto.tink.Parameters;
26 import com.google.crypto.tink.SecretKeyAccess;
27 import com.google.crypto.tink.aead.internal.AesGcmSivProtoSerialization;
28 import com.google.crypto.tink.aead.subtle.AesGcmSiv;
29 import com.google.crypto.tink.config.internal.TinkFipsUtil;
30 import com.google.crypto.tink.internal.KeyManagerRegistry;
31 import com.google.crypto.tink.internal.LegacyKeyManagerImpl;
32 import com.google.crypto.tink.internal.MutableKeyCreationRegistry;
33 import com.google.crypto.tink.internal.MutableKeyDerivationRegistry;
34 import com.google.crypto.tink.internal.MutableParametersRegistry;
35 import com.google.crypto.tink.internal.MutablePrimitiveRegistry;
36 import com.google.crypto.tink.internal.PrimitiveConstructor;
37 import com.google.crypto.tink.internal.Util;
38 import com.google.crypto.tink.proto.KeyData.KeyMaterialType;
39 import com.google.crypto.tink.util.SecretBytes;
40 import java.io.InputStream;
41 import java.security.GeneralSecurityException;
42 import java.security.NoSuchAlgorithmException;
43 import java.util.Collections;
44 import java.util.HashMap;
45 import java.util.Map;
46 import javax.annotation.Nullable;
47 import javax.crypto.Cipher;
48 import javax.crypto.NoSuchPaddingException;
49 
50 /**
51  * This key manager generates new {@code AesGcmSivKey} keys and produces new instances of {@code
52  * AesGcmSiv}.
53  */
54 public final class AesGcmSivKeyManager {
55   private static final PrimitiveConstructor<com.google.crypto.tink.aead.AesGcmSivKey, Aead>
56       AES_GCM_SIV_PRIMITIVE_CONSTRUCTOR =
57           PrimitiveConstructor.create(
58               AesGcmSiv::create, com.google.crypto.tink.aead.AesGcmSivKey.class, Aead.class);
59 
60   @SuppressWarnings("InlineLambdaConstant") // We need a correct Object#equals in registration.
61   private static final MutableKeyCreationRegistry.KeyCreator<AesGcmSivParameters> KEY_CREATOR =
62       AesGcmSivKeyManager::createAesGcmSivKey;
63 
64   @SuppressWarnings("InlineLambdaConstant") // We need a correct Object#equals in registration.
65   private static final MutableKeyDerivationRegistry.InsecureKeyCreator<AesGcmSivParameters>
66       KEY_DERIVER = AesGcmSivKeyManager::createAesGcmSivKeyFromRandomness;
67 
68   private static final KeyManager<Aead> legacyKeyManager =
69       LegacyKeyManagerImpl.create(
70           "type.googleapis.com/google.crypto.tink.AesGcmSivKey",
71           Aead.class,
72           KeyMaterialType.SYMMETRIC,
73           com.google.crypto.tink.proto.AesGcmSivKey.parser());
74 
75   @AccessesPartialKey
createAesGcmSivKeyFromRandomness( AesGcmSivParameters parameters, InputStream stream, @Nullable Integer idRequirement, SecretKeyAccess access)76   static com.google.crypto.tink.aead.AesGcmSivKey createAesGcmSivKeyFromRandomness(
77       AesGcmSivParameters parameters,
78       InputStream stream,
79       @Nullable Integer idRequirement,
80       SecretKeyAccess access)
81       throws GeneralSecurityException {
82     return com.google.crypto.tink.aead.AesGcmSivKey.builder()
83         .setParameters(parameters)
84         .setIdRequirement(idRequirement)
85         .setKeyBytes(Util.readIntoSecretBytes(stream, parameters.getKeySizeBytes(), access))
86         .build();
87   }
88 
89   @AccessesPartialKey
createAesGcmSivKey( AesGcmSivParameters parameters, @Nullable Integer idRequirement)90   private static com.google.crypto.tink.aead.AesGcmSivKey createAesGcmSivKey(
91       AesGcmSivParameters parameters, @Nullable Integer idRequirement)
92       throws GeneralSecurityException {
93     return com.google.crypto.tink.aead.AesGcmSivKey.builder()
94         .setParameters(parameters)
95         .setIdRequirement(idRequirement)
96         .setKeyBytes(SecretBytes.randomBytes(parameters.getKeySizeBytes()))
97         .build();
98   }
99 
namedParameters()100   private static Map<String, Parameters> namedParameters() throws GeneralSecurityException {
101     Map<String, Parameters> result = new HashMap<>();
102 
103     result.put(
104         "AES128_GCM_SIV",
105         AesGcmSivParameters.builder()
106             .setKeySizeBytes(16)
107             .setVariant(AesGcmSivParameters.Variant.TINK)
108             .build());
109     result.put(
110         "AES128_GCM_SIV_RAW",
111         AesGcmSivParameters.builder()
112             .setKeySizeBytes(16)
113             .setVariant(AesGcmSivParameters.Variant.NO_PREFIX)
114             .build());
115     result.put(
116         "AES256_GCM_SIV",
117         AesGcmSivParameters.builder()
118             .setKeySizeBytes(32)
119             .setVariant(AesGcmSivParameters.Variant.TINK)
120             .build());
121     result.put(
122         "AES256_GCM_SIV_RAW",
123         AesGcmSivParameters.builder()
124             .setKeySizeBytes(32)
125             .setVariant(AesGcmSivParameters.Variant.NO_PREFIX)
126             .build());
127 
128     return Collections.unmodifiableMap(result);
129   }
130 
canUseAesGcmSive()131   private static boolean canUseAesGcmSive() {
132     try {
133       Cipher.getInstance("AES/GCM-SIV/NoPadding");
134       return true;
135     } catch (NoSuchAlgorithmException | NoSuchPaddingException ex) {
136       return false;
137     }
138   }
139 
register(boolean newKeyAllowed)140   public static void register(boolean newKeyAllowed) throws GeneralSecurityException {
141     if (!TinkFipsUtil.AlgorithmFipsCompatibility.ALGORITHM_NOT_FIPS.isCompatible()) {
142       throw new GeneralSecurityException("Registering AES GCM SIV is not supported in FIPS mode");
143     }
144     // We want to register key proto serialization even when AES-GCM-SIV is unavailable via the
145     // Java Cryptographic Extension framework (and thus via Tink) to enable operations that don't
146     // depend on the actual cryptographic primitive - for example, exporting keys to key management
147     // systems.
148     AesGcmSivProtoSerialization.register();
149     if (canUseAesGcmSive()) {
150       MutablePrimitiveRegistry.globalInstance()
151           .registerPrimitiveConstructor(AES_GCM_SIV_PRIMITIVE_CONSTRUCTOR);
152       MutableParametersRegistry.globalInstance().putAll(namedParameters());
153       MutableKeyDerivationRegistry.globalInstance().add(KEY_DERIVER, AesGcmSivParameters.class);
154       MutableKeyCreationRegistry.globalInstance().add(KEY_CREATOR, AesGcmSivParameters.class);
155       KeyManagerRegistry.globalInstance().registerKeyManager(legacyKeyManager, newKeyAllowed);
156     }
157   }
158 
159   /**
160    * Creates and returns a {@link KeyTemplate} that generates new instances of AES-GCM-SIV with the
161    * following parameters:
162    *
163    * <ul>
164    *   <li>Key size: 16 bytes
165    *   <li>Prefix type: {@link KeyTemplate.OutputPrefixType#TINK}
166    * </ul>
167    */
aes128GcmSivTemplate()168   public static final KeyTemplate aes128GcmSivTemplate() {
169     return exceptionIsBug(
170         () ->
171             KeyTemplate.createFrom(
172                 AesGcmSivParameters.builder()
173                     .setKeySizeBytes(16)
174                     .setVariant(AesGcmSivParameters.Variant.TINK)
175                     .build()));
176   }
177 
178   /**
179    * Creates and returns a {@link KeyTemplate} that generates new instances of AES-GCM with the
180    * following parameters:
181    *
182    * <ul>
183    *   <li>Key size: 16 bytes
184    *   <li>Prefix type: {@link KeyTemplate.OutputPrefixType#RAW} (no prefix)
185    * </ul>
186    *
187    * <p>Keys generated from this template should create ciphertexts compatible with other libraries.
188    */
rawAes128GcmSivTemplate()189   public static final KeyTemplate rawAes128GcmSivTemplate() {
190     return exceptionIsBug(
191         () ->
192             KeyTemplate.createFrom(
193                 AesGcmSivParameters.builder()
194                     .setKeySizeBytes(16)
195                     .setVariant(AesGcmSivParameters.Variant.NO_PREFIX)
196                     .build()));
197   }
198 
199   /**
200    * Creates and returns a {@link KeyTemplate} that generates new instances of AES-GCM-SIV with the
201    * following parameters:
202    *
203    * <ul>
204    *   <li>Key size: 32 bytes
205    *   <li>Prefix type: {@link KeyTemplate.OutputPrefixType#TINK}
206    * </ul>
207    */
aes256GcmSivTemplate()208   public static final KeyTemplate aes256GcmSivTemplate() {
209     return exceptionIsBug(
210         () ->
211             KeyTemplate.createFrom(
212                 AesGcmSivParameters.builder()
213                     .setKeySizeBytes(32)
214                     .setVariant(AesGcmSivParameters.Variant.TINK)
215                     .build()));
216   }
217 
218   /**
219    * Creates and returns a {@link KeyTemplate} that generates new instances of AES-GCM-SIV with the
220    * following parameters:
221    *
222    * <ul>
223    *   <li>Key size: 32 bytes
224    *   <li>Prefix type: {@link KeyTemplate.OutputPrefixType#RAW} (no prefix)
225    * </ul>
226    *
227    * <p>Keys generated from this template should create ciphertexts compatible with other libraries.
228    */
rawAes256GcmSivTemplate()229   public static final KeyTemplate rawAes256GcmSivTemplate() {
230     return exceptionIsBug(
231         () ->
232             KeyTemplate.createFrom(
233                 AesGcmSivParameters.builder()
234                     .setKeySizeBytes(32)
235                     .setVariant(AesGcmSivParameters.Variant.NO_PREFIX)
236                     .build()));
237   }
238 
AesGcmSivKeyManager()239   private AesGcmSivKeyManager() {}
240 }
241