1 // Copyright 2024 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.AccessesPartialKey; 20 import com.google.crypto.tink.Key; 21 import com.google.crypto.tink.internal.OutputPrefixUtil; 22 import com.google.crypto.tink.util.Bytes; 23 import com.google.crypto.tink.util.SecretBytes; 24 import com.google.errorprone.annotations.Immutable; 25 import com.google.errorprone.annotations.RestrictedApi; 26 import java.security.GeneralSecurityException; 27 import java.util.Objects; 28 import javax.annotation.Nullable; 29 30 /** Represents an X-AES-GCM key used for computing AEAD. */ 31 @Immutable 32 public final class XAesGcmKey extends AeadKey { 33 private final XAesGcmParameters parameters; 34 private final SecretBytes keyBytes; 35 private final Bytes outputPrefix; 36 @Nullable private final Integer idRequirement; 37 XAesGcmKey( XAesGcmParameters parameters, SecretBytes keyBytes, Bytes outputPrefix, @Nullable Integer idRequirement)38 private XAesGcmKey( 39 XAesGcmParameters parameters, 40 SecretBytes keyBytes, 41 Bytes outputPrefix, 42 @Nullable Integer idRequirement) { 43 this.parameters = parameters; 44 this.keyBytes = keyBytes; 45 this.outputPrefix = outputPrefix; 46 this.idRequirement = idRequirement; 47 } 48 getOutputPrefix( XAesGcmParameters parameters, @Nullable Integer idRequirement)49 private static Bytes getOutputPrefix( 50 XAesGcmParameters parameters, @Nullable Integer idRequirement) { 51 if (parameters.getVariant() == XAesGcmParameters.Variant.NO_PREFIX) { 52 return OutputPrefixUtil.EMPTY_PREFIX; 53 } 54 if (parameters.getVariant() == XAesGcmParameters.Variant.TINK) { 55 return OutputPrefixUtil.getTinkOutputPrefix(idRequirement); 56 } 57 throw new IllegalStateException("Unknown Variant: " + parameters.getVariant()); 58 } 59 60 @Override getOutputPrefix()61 public Bytes getOutputPrefix() { 62 return outputPrefix; 63 } 64 65 @RestrictedApi( 66 explanation = "Accessing parts of keys can produce unexpected incompatibilities, annotate the function with @AccessesPartialKey", 67 link = "https://developers.google.com/tink/design/access_control#accessing_partial_keys", 68 allowedOnPath = ".*Test\\.java", 69 allowlistAnnotations = {AccessesPartialKey.class}) create( XAesGcmParameters parameters, SecretBytes secretBytes, @Nullable Integer idRequirement)70 public static XAesGcmKey create( 71 XAesGcmParameters parameters, SecretBytes secretBytes, @Nullable Integer idRequirement) 72 throws GeneralSecurityException { 73 if (parameters.getVariant() != XAesGcmParameters.Variant.NO_PREFIX && idRequirement == null) { 74 throw new GeneralSecurityException( 75 "For given Variant " 76 + parameters.getVariant() 77 + " the value of idRequirement must be non-null"); 78 } 79 if (parameters.getVariant() == XAesGcmParameters.Variant.NO_PREFIX && idRequirement != null) { 80 throw new GeneralSecurityException( 81 "For given Variant NO_PREFIX the value of idRequirement must be null"); 82 } 83 if (secretBytes.size() != 32) { 84 throw new GeneralSecurityException( 85 "XAesGcmKey key must be constructed with key of length 32 bytes, not " 86 + secretBytes.size()); 87 } 88 return new XAesGcmKey( 89 parameters, secretBytes, getOutputPrefix(parameters, idRequirement), idRequirement); 90 } 91 92 @RestrictedApi( 93 explanation = "Accessing parts of keys can produce unexpected incompatibilities, annotate the function with @AccessesPartialKey", 94 link = "https://developers.google.com/tink/design/access_control#accessing_partial_keys", 95 allowedOnPath = ".*Test\\.java", 96 allowlistAnnotations = {AccessesPartialKey.class}) getKeyBytes()97 public SecretBytes getKeyBytes() { 98 return keyBytes; 99 } 100 101 @Override getParameters()102 public XAesGcmParameters getParameters() { 103 return parameters; 104 } 105 106 @Override 107 @Nullable getIdRequirementOrNull()108 public Integer getIdRequirementOrNull() { 109 return idRequirement; 110 } 111 112 @Override equalsKey(Key o)113 public boolean equalsKey(Key o) { 114 if (!(o instanceof XAesGcmKey)) { 115 return false; 116 } 117 XAesGcmKey that = (XAesGcmKey) o; 118 // Since outputPrefix is a function of parameters, we can ignore it here. 119 return that.parameters.equals(parameters) 120 && that.keyBytes.equalsSecretBytes(keyBytes) 121 && Objects.equals(that.idRequirement, idRequirement); 122 } 123 } 124