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 package com.google.crypto.tink.hybrid; 17 18 import com.google.crypto.tink.HybridEncrypt; 19 import com.google.crypto.tink.hybrid.internal.LegacyFullHybridEncrypt; 20 import com.google.crypto.tink.internal.LegacyProtoKey; 21 import com.google.crypto.tink.internal.MonitoringClient; 22 import com.google.crypto.tink.internal.MonitoringKeysetInfo; 23 import com.google.crypto.tink.internal.MonitoringUtil; 24 import com.google.crypto.tink.internal.MutableMonitoringRegistry; 25 import com.google.crypto.tink.internal.MutablePrimitiveRegistry; 26 import com.google.crypto.tink.internal.PrimitiveConstructor; 27 import com.google.crypto.tink.internal.PrimitiveRegistry; 28 import com.google.crypto.tink.internal.PrimitiveSet; 29 import com.google.crypto.tink.internal.PrimitiveWrapper; 30 import java.security.GeneralSecurityException; 31 32 /** 33 * The implementation of {@code PrimitiveWrapper<HybridEncrypt>}. 34 * 35 * <p>The returned primitive works with a keyset (rather than a single key). To encrypt a plaintext, 36 * it uses the primary key in the keyset, and prepends to the ciphertext a certain prefix associated 37 * with the primary key. 38 */ 39 public class HybridEncryptWrapper implements PrimitiveWrapper<HybridEncrypt, HybridEncrypt> { 40 41 private static final HybridEncryptWrapper WRAPPER = new HybridEncryptWrapper(); 42 private static final PrimitiveConstructor<LegacyProtoKey, HybridEncrypt> 43 LEGACY_PRIMITIVE_CONSTRUCTOR = 44 PrimitiveConstructor.create( 45 LegacyFullHybridEncrypt::create, LegacyProtoKey.class, HybridEncrypt.class); 46 47 private static class WrappedHybridEncrypt implements HybridEncrypt { 48 final PrimitiveSet<HybridEncrypt> primitives; 49 50 private final MonitoringClient.Logger encLogger; 51 WrappedHybridEncrypt(final PrimitiveSet<HybridEncrypt> primitives)52 public WrappedHybridEncrypt(final PrimitiveSet<HybridEncrypt> primitives) { 53 this.primitives = primitives; 54 if (primitives.hasAnnotations()) { 55 MonitoringClient client = MutableMonitoringRegistry.globalInstance().getMonitoringClient(); 56 MonitoringKeysetInfo keysetInfo = MonitoringUtil.getMonitoringKeysetInfo(primitives); 57 this.encLogger = client.createLogger(keysetInfo, "hybrid_encrypt", "encrypt"); 58 } else { 59 this.encLogger = MonitoringUtil.DO_NOTHING_LOGGER; 60 } 61 } 62 63 @Override encrypt(final byte[] plaintext, final byte[] contextInfo)64 public byte[] encrypt(final byte[] plaintext, final byte[] contextInfo) 65 throws GeneralSecurityException { 66 if (primitives.getPrimary() == null) { 67 encLogger.logFailure(); 68 throw new GeneralSecurityException("keyset without primary key"); 69 } 70 try { 71 byte[] output = primitives.getPrimary().getFullPrimitive().encrypt(plaintext, contextInfo); 72 encLogger.log(primitives.getPrimary().getKeyId(), plaintext.length); 73 return output; 74 } catch (GeneralSecurityException e) { 75 encLogger.logFailure(); 76 throw e; 77 } 78 } 79 } 80 HybridEncryptWrapper()81 HybridEncryptWrapper() {} 82 83 @Override wrap(final PrimitiveSet<HybridEncrypt> primitives)84 public HybridEncrypt wrap(final PrimitiveSet<HybridEncrypt> primitives) { 85 return new WrappedHybridEncrypt(primitives); 86 } 87 88 @Override getPrimitiveClass()89 public Class<HybridEncrypt> getPrimitiveClass() { 90 return HybridEncrypt.class; 91 } 92 93 @Override getInputPrimitiveClass()94 public Class<HybridEncrypt> getInputPrimitiveClass() { 95 return HybridEncrypt.class; 96 } 97 98 /** 99 * Register the wrapper within the registry. 100 * 101 * <p>This is required for calls to {@link Keyset.getPrimitive} with a {@link HybridEncrypt} 102 * argument. 103 */ register()104 public static void register() throws GeneralSecurityException { 105 MutablePrimitiveRegistry.globalInstance().registerPrimitiveWrapper(WRAPPER); 106 MutablePrimitiveRegistry.globalInstance() 107 .registerPrimitiveConstructor(LEGACY_PRIMITIVE_CONSTRUCTOR); 108 } 109 110 /** 111 * registerToInternalPrimitiveRegistry is a non-public method (it takes an argument of an 112 * internal-only type) registering an instance of {@code HybridEncryptWrapper} to the provided 113 * {@code PrimitiveRegistry.Builder}. 114 */ registerToInternalPrimitiveRegistry( PrimitiveRegistry.Builder primitiveRegistryBuilder)115 public static void registerToInternalPrimitiveRegistry( 116 PrimitiveRegistry.Builder primitiveRegistryBuilder) throws GeneralSecurityException { 117 primitiveRegistryBuilder.registerPrimitiveWrapper(WRAPPER); 118 } 119 } 120