• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 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 
17 package com.google.crypto.tink.aead;
18 
19 import com.google.crypto.tink.Aead;
20 import com.google.crypto.tink.CryptoFormat;
21 import com.google.crypto.tink.aead.internal.LegacyFullAead;
22 import com.google.crypto.tink.internal.LegacyProtoKey;
23 import com.google.crypto.tink.internal.MonitoringClient;
24 import com.google.crypto.tink.internal.MonitoringKeysetInfo;
25 import com.google.crypto.tink.internal.MonitoringUtil;
26 import com.google.crypto.tink.internal.MutableMonitoringRegistry;
27 import com.google.crypto.tink.internal.MutablePrimitiveRegistry;
28 import com.google.crypto.tink.internal.PrimitiveConstructor;
29 import com.google.crypto.tink.internal.PrimitiveRegistry;
30 import com.google.crypto.tink.internal.PrimitiveSet;
31 import com.google.crypto.tink.internal.PrimitiveWrapper;
32 import java.security.GeneralSecurityException;
33 import java.util.Arrays;
34 import java.util.List;
35 
36 /**
37  * AeadWrapper is the implementation of SetWrapper for the Aead primitive.
38  *
39  * <p>Key rotation works as follows: each ciphertext is prefixed with the keyId. When decrypting, we
40  * first try all primitives whose keyId starts with the prefix of the ciphertext. If none of these
41  * succeed, we try the raw primitives. If any succeeds, we return the ciphertext, otherwise we
42  * simply throw a GeneralSecurityException.
43  */
44 public class AeadWrapper implements PrimitiveWrapper<Aead, Aead> {
45 
46   private static final AeadWrapper WRAPPER = new AeadWrapper();
47   private static final PrimitiveConstructor<LegacyProtoKey, Aead>
48       LEGACY_FULL_AEAD_PRIMITIVE_CONSTRUCTOR =
49           PrimitiveConstructor.create(LegacyFullAead::create, LegacyProtoKey.class, Aead.class);
50 
51   private static class WrappedAead implements Aead {
52     private final PrimitiveSet<Aead> pSet;
53     private final MonitoringClient.Logger encLogger;
54     private final MonitoringClient.Logger decLogger;
55 
WrappedAead(PrimitiveSet<Aead> pSet)56     private WrappedAead(PrimitiveSet<Aead> pSet) {
57       this.pSet = pSet;
58       if (pSet.hasAnnotations()) {
59         MonitoringClient client = MutableMonitoringRegistry.globalInstance().getMonitoringClient();
60         MonitoringKeysetInfo keysetInfo = MonitoringUtil.getMonitoringKeysetInfo(pSet);
61         this.encLogger = client.createLogger(keysetInfo, "aead", "encrypt");
62         this.decLogger = client.createLogger(keysetInfo, "aead", "decrypt");
63       } else {
64         this.encLogger = MonitoringUtil.DO_NOTHING_LOGGER;
65         this.decLogger = MonitoringUtil.DO_NOTHING_LOGGER;
66       }
67     }
68 
69     @Override
encrypt(final byte[] plaintext, final byte[] associatedData)70     public byte[] encrypt(final byte[] plaintext, final byte[] associatedData)
71         throws GeneralSecurityException {
72       try {
73         byte[] result = pSet.getPrimary().getFullPrimitive().encrypt(plaintext, associatedData);
74         encLogger.log(pSet.getPrimary().getKeyId(), plaintext.length);
75         return result;
76       } catch (GeneralSecurityException e) {
77         encLogger.logFailure();
78         throw e;
79       }
80     }
81 
82     @Override
decrypt(final byte[] ciphertext, final byte[] associatedData)83     public byte[] decrypt(final byte[] ciphertext, final byte[] associatedData)
84         throws GeneralSecurityException {
85       if (ciphertext.length > CryptoFormat.NON_RAW_PREFIX_SIZE) {
86         byte[] prefix = Arrays.copyOf(ciphertext, CryptoFormat.NON_RAW_PREFIX_SIZE);
87         List<PrimitiveSet.Entry<Aead>> entries = pSet.getPrimitive(prefix);
88         for (PrimitiveSet.Entry<Aead> entry : entries) {
89           try {
90             byte[] result = entry.getFullPrimitive().decrypt(ciphertext, associatedData);
91             decLogger.log(entry.getKeyId(), ciphertext.length);
92             return result;
93           } catch (GeneralSecurityException ignored) {
94             // ignore and continue trying
95           }
96         }
97       }
98 
99       // Let's try all RAW keys.
100       List<PrimitiveSet.Entry<Aead>> entries = pSet.getRawPrimitives();
101       for (PrimitiveSet.Entry<Aead> entry : entries) {
102         try {
103           byte[] result = entry.getFullPrimitive().decrypt(ciphertext, associatedData);
104           decLogger.log(entry.getKeyId(), ciphertext.length);
105           return result;
106         } catch (GeneralSecurityException ignored) {
107           // ignore and continue trying
108         }
109       }
110       decLogger.logFailure();
111       // nothing works.
112       throw new GeneralSecurityException("decryption failed");
113     }
114   }
115 
AeadWrapper()116   AeadWrapper() {}
117 
118   @Override
wrap(final PrimitiveSet<Aead> pset)119   public Aead wrap(final PrimitiveSet<Aead> pset) throws GeneralSecurityException {
120     return new WrappedAead(pset);
121   }
122 
123   @Override
getPrimitiveClass()124   public Class<Aead> getPrimitiveClass() {
125     return Aead.class;
126   }
127 
128   @Override
getInputPrimitiveClass()129   public Class<Aead> getInputPrimitiveClass() {
130     return Aead.class;
131   }
132 
register()133   public static void register() throws GeneralSecurityException {
134     MutablePrimitiveRegistry.globalInstance().registerPrimitiveWrapper(WRAPPER);
135     MutablePrimitiveRegistry.globalInstance()
136         .registerPrimitiveConstructor(LEGACY_FULL_AEAD_PRIMITIVE_CONSTRUCTOR);
137   }
138 
139   /**
140    * registerToInternalPrimitiveRegistry is a non-public method (it takes an argument of an
141    * internal-only type) registering an instance of {@code AeadWrapper} to the provided {@code
142    * PrimitiveRegistry.Builder}.
143    */
registerToInternalPrimitiveRegistry( PrimitiveRegistry.Builder primitiveRegistryBuilder)144   public static void registerToInternalPrimitiveRegistry(
145       PrimitiveRegistry.Builder primitiveRegistryBuilder) throws GeneralSecurityException {
146     primitiveRegistryBuilder.registerPrimitiveWrapper(WRAPPER);
147   }
148 }
149