• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 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.CanIgnoreReturnValue;
25 import com.google.errorprone.annotations.Immutable;
26 import com.google.errorprone.annotations.RestrictedApi;
27 import java.security.GeneralSecurityException;
28 import java.util.Objects;
29 import javax.annotation.Nullable;
30 
31 /** Represents an AES-GCM-SIV key used for computing AEAD. */
32 @Immutable
33 public final class AesGcmSivKey extends AeadKey {
34   private final AesGcmSivParameters parameters;
35   private final SecretBytes keyBytes;
36   private final Bytes outputPrefix;
37   @Nullable private final Integer idRequirement;
38 
39   /** Builder for AesGcmSivKey. */
40   public static class Builder {
41     @Nullable private AesGcmSivParameters parameters = null;
42     @Nullable private SecretBytes keyBytes = null;
43     @Nullable private Integer idRequirement = null;
44 
Builder()45     private Builder() {}
46 
47     @CanIgnoreReturnValue
setParameters(AesGcmSivParameters parameters)48     public Builder setParameters(AesGcmSivParameters parameters) {
49       this.parameters = parameters;
50       return this;
51     }
52 
53     @CanIgnoreReturnValue
setKeyBytes(SecretBytes keyBytes)54     public Builder setKeyBytes(SecretBytes keyBytes) {
55       this.keyBytes = keyBytes;
56       return this;
57     }
58 
59     @CanIgnoreReturnValue
setIdRequirement(@ullable Integer idRequirement)60     public Builder setIdRequirement(@Nullable Integer idRequirement) {
61       this.idRequirement = idRequirement;
62       return this;
63     }
64 
getOutputPrefix()65     private Bytes getOutputPrefix() {
66       if (parameters.getVariant() == AesGcmSivParameters.Variant.NO_PREFIX) {
67         return OutputPrefixUtil.EMPTY_PREFIX;
68       }
69       if (parameters.getVariant() == AesGcmSivParameters.Variant.CRUNCHY) {
70         return OutputPrefixUtil.getLegacyOutputPrefix(idRequirement);
71       }
72       if (parameters.getVariant() == AesGcmSivParameters.Variant.TINK) {
73         return OutputPrefixUtil.getTinkOutputPrefix(idRequirement);
74       }
75       throw new IllegalStateException(
76           "Unknown AesGcmSivParameters.Variant: " + parameters.getVariant());
77     }
78 
build()79     public AesGcmSivKey build() throws GeneralSecurityException {
80       if (parameters == null || keyBytes == null) {
81         throw new GeneralSecurityException("Cannot build without parameters and/or key material");
82       }
83 
84       if (parameters.getKeySizeBytes() != keyBytes.size()) {
85         throw new GeneralSecurityException("Key size mismatch");
86       }
87 
88       if (parameters.hasIdRequirement() && idRequirement == null) {
89         throw new GeneralSecurityException(
90             "Cannot create key without ID requirement with parameters with ID requirement");
91       }
92 
93       if (!parameters.hasIdRequirement() && idRequirement != null) {
94         throw new GeneralSecurityException(
95             "Cannot create key with ID requirement with parameters without ID requirement");
96       }
97       Bytes outputPrefix = getOutputPrefix();
98       return new AesGcmSivKey(parameters, keyBytes, outputPrefix, idRequirement);
99     }
100   }
101 
AesGcmSivKey( AesGcmSivParameters parameters, SecretBytes keyBytes, Bytes outputPrefix, @Nullable Integer idRequirement)102   private AesGcmSivKey(
103       AesGcmSivParameters parameters,
104       SecretBytes keyBytes,
105       Bytes outputPrefix,
106       @Nullable Integer idRequirement) {
107     this.parameters = parameters;
108     this.keyBytes = keyBytes;
109     this.outputPrefix = outputPrefix;
110     this.idRequirement = idRequirement;
111   }
112 
113   @RestrictedApi(
114       explanation = "Accessing parts of keys can produce unexpected incompatibilities, annotate the function with @AccessesPartialKey",
115       link = "https://developers.google.com/tink/design/access_control#accessing_partial_keys",
116       allowedOnPath = ".*Test\\.java",
117       allowlistAnnotations = {AccessesPartialKey.class})
builder()118   public static Builder builder() {
119     return new Builder();
120   }
121 
122   /** Returns the underlying key bytes. */
123   @RestrictedApi(
124       explanation = "Accessing parts of keys can produce unexpected incompatibilities, annotate the function with @AccessesPartialKey",
125       link = "https://developers.google.com/tink/design/access_control#accessing_partial_keys",
126       allowedOnPath = ".*Test\\.java",
127       allowlistAnnotations = {AccessesPartialKey.class})
getKeyBytes()128   public SecretBytes getKeyBytes() {
129     return keyBytes;
130   }
131 
132   @Override
getOutputPrefix()133   public Bytes getOutputPrefix() {
134     return outputPrefix;
135   }
136 
137   @Override
getParameters()138   public AesGcmSivParameters getParameters() {
139     return parameters;
140   }
141 
142   @Override
143   @Nullable
getIdRequirementOrNull()144   public Integer getIdRequirementOrNull() {
145     return idRequirement;
146   }
147 
148   @Override
equalsKey(Key o)149   public boolean equalsKey(Key o) {
150     if (!(o instanceof AesGcmSivKey)) {
151       return false;
152     }
153     AesGcmSivKey that = (AesGcmSivKey) o;
154     // Since outputPrefix is a function of parameters, we can ignore it here.
155     return that.parameters.equals(parameters)
156         && that.keyBytes.equalsSecretBytes(keyBytes)
157         && Objects.equals(that.idRequirement, idRequirement);
158   }
159 }
160