• 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.AesCtrHmacAeadProtoSerialization;
28 import com.google.crypto.tink.config.internal.TinkFipsUtil;
29 import com.google.crypto.tink.internal.KeyManagerRegistry;
30 import com.google.crypto.tink.internal.LegacyKeyManagerImpl;
31 import com.google.crypto.tink.internal.MutableKeyCreationRegistry;
32 import com.google.crypto.tink.internal.MutableKeyDerivationRegistry;
33 import com.google.crypto.tink.internal.MutableParametersRegistry;
34 import com.google.crypto.tink.internal.MutablePrimitiveRegistry;
35 import com.google.crypto.tink.internal.PrimitiveConstructor;
36 import com.google.crypto.tink.internal.Util;
37 import com.google.crypto.tink.proto.KeyData.KeyMaterialType;
38 import com.google.crypto.tink.subtle.EncryptThenAuthenticate;
39 import com.google.crypto.tink.util.SecretBytes;
40 import java.io.InputStream;
41 import java.security.GeneralSecurityException;
42 import java.util.Collections;
43 import java.util.HashMap;
44 import java.util.Map;
45 import javax.annotation.Nullable;
46 
47 /**
48  * This key manager generates new {@link AesCtrHmacAeadKey} keys and produces new instances of
49  * {@link EncryptThenAuthenticate}.
50  */
51 public final class AesCtrHmacAeadKeyManager {
validate(AesCtrHmacAeadParameters parameters)52   private static void validate(AesCtrHmacAeadParameters parameters)
53       throws GeneralSecurityException {
54     if (parameters.getAesKeySizeBytes() != 16 && parameters.getAesKeySizeBytes() != 32) {
55       throw new GeneralSecurityException("AES key size must be 16 or 32 bytes");
56     }
57   }
58 
59   private static final PrimitiveConstructor<com.google.crypto.tink.aead.AesCtrHmacAeadKey, Aead>
60       AES_CTR_HMAC_AEAD_PRIMITIVE_CONSTRUCTOR =
61           PrimitiveConstructor.create(
62               EncryptThenAuthenticate::create,
63               com.google.crypto.tink.aead.AesCtrHmacAeadKey.class,
64               Aead.class);
65 
66   private static final KeyManager<Aead> legacyKeyManager =
67       LegacyKeyManagerImpl.create(
68           getKeyType(),
69           Aead.class,
70           KeyMaterialType.SYMMETRIC,
71           com.google.crypto.tink.proto.AesCtrHmacAeadKey.parser());
72 
getKeyType()73   static String getKeyType() {
74     return "type.googleapis.com/google.crypto.tink.AesCtrHmacAeadKey";
75   }
76 
77   @SuppressWarnings("InlineLambdaConstant") // We need a correct Object#equals in registration.
78   private static final MutableKeyDerivationRegistry.InsecureKeyCreator<AesCtrHmacAeadParameters>
79       KEY_DERIVER = AesCtrHmacAeadKeyManager::createAesCtrHmacAeadKeyFromRandomness;
80 
81   // To ensure that the derived key can provide key commitment, the AES-CTR key must be derived
82   // before the HMAC key.
83   // Consider the following malicious scenario using a brute-forced key InputStream with a 0 as
84   // its 32nd byte:
85   //     31 bytes || 1 byte of 0s || 16 bytes
86   // We give this stream to party A, saying that it is 32-byte HMAC key || 16-byte AES key. We
87   // also give this stream to party B, saying that it is 31-byte HMAC key || 16-byte AES key.
88   // Since HMAC pads the key with zeroes, this same stream will lead to both parties using the
89   // same HMAC key but different AES keys.
90   @AccessesPartialKey
createAesCtrHmacAeadKeyFromRandomness( AesCtrHmacAeadParameters parameters, InputStream stream, @Nullable Integer idRequirement, SecretKeyAccess access)91   static com.google.crypto.tink.aead.AesCtrHmacAeadKey createAesCtrHmacAeadKeyFromRandomness(
92       AesCtrHmacAeadParameters parameters,
93       InputStream stream,
94       @Nullable Integer idRequirement,
95       SecretKeyAccess access)
96       throws GeneralSecurityException {
97     return com.google.crypto.tink.aead.AesCtrHmacAeadKey.builder()
98         .setParameters(parameters)
99         .setIdRequirement(idRequirement)
100         .setAesKeyBytes(Util.readIntoSecretBytes(stream, parameters.getAesKeySizeBytes(), access))
101         .setHmacKeyBytes(Util.readIntoSecretBytes(stream, parameters.getHmacKeySizeBytes(), access))
102         .build();
103   }
104 
105   @SuppressWarnings("InlineLambdaConstant") // We need a correct Object#equals in registration.
106   private static final MutableKeyCreationRegistry.KeyCreator<AesCtrHmacAeadParameters> KEY_CREATOR =
107       AesCtrHmacAeadKeyManager::createAesCtrHmacAeadKey;
108 
109   @AccessesPartialKey
createAesCtrHmacAeadKey( AesCtrHmacAeadParameters parameters, @Nullable Integer idRequirement)110   static com.google.crypto.tink.aead.AesCtrHmacAeadKey createAesCtrHmacAeadKey(
111       AesCtrHmacAeadParameters parameters, @Nullable Integer idRequirement)
112       throws GeneralSecurityException {
113     validate(parameters);
114     return com.google.crypto.tink.aead.AesCtrHmacAeadKey.builder()
115         .setParameters(parameters)
116         .setIdRequirement(idRequirement)
117         .setAesKeyBytes(SecretBytes.randomBytes(parameters.getAesKeySizeBytes()))
118         .setHmacKeyBytes(SecretBytes.randomBytes(parameters.getHmacKeySizeBytes()))
119         .build();
120   }
121 
namedParameters()122   private static Map<String, Parameters> namedParameters() throws GeneralSecurityException {
123         Map<String, Parameters> result = new HashMap<>();
124 
125         result.put("AES128_CTR_HMAC_SHA256", PredefinedAeadParameters.AES128_CTR_HMAC_SHA256);
126         result.put(
127             "AES128_CTR_HMAC_SHA256_RAW",
128             AesCtrHmacAeadParameters.builder()
129                 .setAesKeySizeBytes(16)
130                 .setHmacKeySizeBytes(32)
131                 .setTagSizeBytes(16)
132                 .setIvSizeBytes(16)
133                 .setHashType(AesCtrHmacAeadParameters.HashType.SHA256)
134                 .setVariant(AesCtrHmacAeadParameters.Variant.NO_PREFIX)
135                 .build());
136 
137         result.put("AES256_CTR_HMAC_SHA256", PredefinedAeadParameters.AES256_CTR_HMAC_SHA256);
138         result.put(
139             "AES256_CTR_HMAC_SHA256_RAW",
140             AesCtrHmacAeadParameters.builder()
141                 .setAesKeySizeBytes(32)
142                 .setHmacKeySizeBytes(32)
143                 .setTagSizeBytes(32)
144                 .setIvSizeBytes(16)
145                 .setHashType(AesCtrHmacAeadParameters.HashType.SHA256)
146                 .setVariant(AesCtrHmacAeadParameters.Variant.NO_PREFIX)
147                 .build());
148 
149         return Collections.unmodifiableMap(result);
150   }
151 
152   private static final TinkFipsUtil.AlgorithmFipsCompatibility FIPS =
153       TinkFipsUtil.AlgorithmFipsCompatibility.ALGORITHM_REQUIRES_BORINGCRYPTO;
154 
register(boolean newKeyAllowed)155   public static void register(boolean newKeyAllowed) throws GeneralSecurityException {
156     if (!FIPS.isCompatible()) {
157       throw new GeneralSecurityException(
158           "Can not use AES-CTR-HMAC in FIPS-mode, as BoringCrypto module is not available.");
159     }
160     AesCtrHmacAeadProtoSerialization.register();
161     MutablePrimitiveRegistry.globalInstance()
162         .registerPrimitiveConstructor(AES_CTR_HMAC_AEAD_PRIMITIVE_CONSTRUCTOR);
163     MutableParametersRegistry.globalInstance().putAll(namedParameters());
164     MutableKeyDerivationRegistry.globalInstance().add(KEY_DERIVER, AesCtrHmacAeadParameters.class);
165     MutableKeyCreationRegistry.globalInstance().add(KEY_CREATOR, AesCtrHmacAeadParameters.class);
166     KeyManagerRegistry.globalInstance()
167         .registerKeyManagerWithFipsCompatibility(legacyKeyManager, FIPS, newKeyAllowed);
168   }
169 
170   /**
171    * @return a {@link KeyTemplate} that generates new instances of AES-CTR-HMAC-AEAD keys with the
172    *     following parameters:
173    *     <ul>
174    *       <li>AES key size: 16 bytes
175    *       <li>AES CTR IV size: 16 byte
176    *       <li>HMAC key size: 32 bytes
177    *       <li>HMAC tag size: 16 bytes
178    *       <li>HMAC hash function: SHA256
179    *     </ul>
180    */
aes128CtrHmacSha256Template()181   public static final KeyTemplate aes128CtrHmacSha256Template() {
182     return exceptionIsBug(
183         () ->
184             KeyTemplate.createFrom(
185                 AesCtrHmacAeadParameters.builder()
186                     .setAesKeySizeBytes(16)
187                     .setHmacKeySizeBytes(32)
188                     .setIvSizeBytes(16)
189                     .setTagSizeBytes(16)
190                     .setHashType(AesCtrHmacAeadParameters.HashType.SHA256)
191                     .setVariant(AesCtrHmacAeadParameters.Variant.TINK)
192                     .build()));
193   }
194 
195   /**
196    * @return a {@link KeyTemplate} that generates new instances of AES-CTR-HMAC-AEAD keys with the
197    *     following parameters:
198    *     <ul>
199    *       <li>AES key size: 32 bytes
200    *       <li>AES CTR IV size: 16 byte
201    *       <li>HMAC key size: 32 bytes
202    *       <li>HMAC tag size: 32 bytes
203    *       <li>HMAC hash function: SHA256
204    *     </ul>
205    */
aes256CtrHmacSha256Template()206   public static final KeyTemplate aes256CtrHmacSha256Template() {
207     return exceptionIsBug(
208         () ->
209             KeyTemplate.createFrom(
210                 AesCtrHmacAeadParameters.builder()
211                     .setAesKeySizeBytes(32)
212                     .setHmacKeySizeBytes(32)
213                     .setIvSizeBytes(16)
214                     .setTagSizeBytes(32)
215                     .setHashType(AesCtrHmacAeadParameters.HashType.SHA256)
216                     .setVariant(AesCtrHmacAeadParameters.Variant.TINK)
217                     .build()));
218   }
219 
AesCtrHmacAeadKeyManager()220   private AesCtrHmacAeadKeyManager() {}
221 }
222