• 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.errorprone.annotations.CanIgnoreReturnValue;
20 import com.google.errorprone.annotations.Immutable;
21 import java.security.GeneralSecurityException;
22 import java.security.InvalidAlgorithmParameterException;
23 import java.util.Objects;
24 import javax.annotation.Nullable;
25 
26 /** Describes the parameters of an {@link AesGcmKey} */
27 public final class AesGcmParameters extends AeadParameters {
28   /**
29    * Describes how the prefix is computed. For AEAD there are three main possibilities: NO_PREFIX
30    * (empty prefix), TINK (prefix the ciphertext with 0x01 followed by a 4-byte key id in big endian
31    * format) or CRUNCHY (prefix the ciphertext with 0x00 followed by a 4-byte key id in big endian
32    * format)
33    */
34   @Immutable
35   public static final class Variant {
36     public static final Variant TINK = new Variant("TINK");
37     public static final Variant CRUNCHY = new Variant("CRUNCHY");
38     public static final Variant NO_PREFIX = new Variant("NO_PREFIX");
39 
40     private final String name;
41 
Variant(String name)42     private Variant(String name) {
43       this.name = name;
44     }
45 
46     @Override
toString()47     public String toString() {
48       return name;
49     }
50   }
51 
52   /**
53    * Builds a new AesGcmParameters instance. The class AesGcmParameters is not responsible for
54    * checking if all allowed values for the parameters are implemented and satisfy any potential
55    * security policies. Some implementation may not support the full set of parameters at the moment
56    * and may restrict them to certain lengths (i.e. key size may be restricted to 16 or 32 bytes).
57    */
58   public static final class Builder {
59     @Nullable private Integer keySizeBytes = null;
60     @Nullable private Integer ivSizeBytes = null;
61     @Nullable private Integer tagSizeBytes = null;
62     private Variant variant = Variant.NO_PREFIX;
63 
Builder()64     private Builder() {}
65 
66     /** Accepts key sizes of 16, 24 or 32 bytes. */
67     @CanIgnoreReturnValue
setKeySizeBytes(int keySizeBytes)68     public Builder setKeySizeBytes(int keySizeBytes) throws GeneralSecurityException {
69       if (keySizeBytes != 16 && keySizeBytes != 24 && keySizeBytes != 32) {
70         throw new InvalidAlgorithmParameterException(
71             String.format(
72                 "Invalid key size %d; only 16-byte, 24-byte and 32-byte AES keys are supported",
73                 keySizeBytes));
74       }
75       this.keySizeBytes = keySizeBytes;
76       return this;
77     }
78 
79     /** IV size must greater than 0. */
80     @CanIgnoreReturnValue
setIvSizeBytes(int ivSizeBytes)81     public Builder setIvSizeBytes(int ivSizeBytes) throws GeneralSecurityException {
82       if (ivSizeBytes <= 0) {
83         throw new GeneralSecurityException(
84             String.format("Invalid IV size in bytes %d; IV size must be positive", ivSizeBytes));
85       }
86       this.ivSizeBytes = ivSizeBytes;
87       return this;
88     }
89     /** Tag size must be between 12 and 16 bytes. */
90     @CanIgnoreReturnValue
setTagSizeBytes(int tagSizeBytes)91     public Builder setTagSizeBytes(int tagSizeBytes) throws GeneralSecurityException {
92       if (tagSizeBytes < 12 || tagSizeBytes > 16) {
93         throw new GeneralSecurityException(
94             String.format(
95                 "Invalid tag size in bytes %d; value must be between 12 and 16 bytes",
96                 tagSizeBytes));
97       }
98       this.tagSizeBytes = tagSizeBytes;
99       return this;
100     }
101 
102     @CanIgnoreReturnValue
setVariant(Variant variant)103     public Builder setVariant(Variant variant) {
104       this.variant = variant;
105       return this;
106     }
107 
build()108     public AesGcmParameters build() throws GeneralSecurityException {
109       if (keySizeBytes == null) {
110         throw new GeneralSecurityException("Key size is not set");
111       }
112       if (variant == null) {
113         throw new GeneralSecurityException("Variant is not set");
114       }
115       if (ivSizeBytes == null) {
116         throw new GeneralSecurityException("IV size is not set");
117       }
118 
119       if (tagSizeBytes == null) {
120         throw new GeneralSecurityException("Tag size is not set");
121       }
122 
123       return new AesGcmParameters(keySizeBytes, ivSizeBytes, tagSizeBytes, variant);
124     }
125   }
126 
127   private final int keySizeBytes;
128   private final int ivSizeBytes;
129   private final int tagSizeBytes;
130   private final Variant variant;
131 
AesGcmParameters(int keySizeBytes, int ivSizeBytes, int tagSizeBytes, Variant variant)132   private AesGcmParameters(int keySizeBytes, int ivSizeBytes, int tagSizeBytes, Variant variant) {
133     this.keySizeBytes = keySizeBytes;
134     this.ivSizeBytes = ivSizeBytes;
135     this.tagSizeBytes = tagSizeBytes;
136     this.variant = variant;
137   }
138 
builder()139   public static Builder builder() {
140     return new Builder();
141   }
142 
getKeySizeBytes()143   public int getKeySizeBytes() {
144     return keySizeBytes;
145   }
146 
getIvSizeBytes()147   public int getIvSizeBytes() {
148     return ivSizeBytes;
149   }
150 
getTagSizeBytes()151   public int getTagSizeBytes() {
152     return tagSizeBytes;
153   }
154 
155   /** Returns a variant object. */
getVariant()156   public Variant getVariant() {
157     return variant;
158   }
159 
160   @Override
equals(Object o)161   public boolean equals(Object o) {
162     if (!(o instanceof AesGcmParameters)) {
163       return false;
164     }
165     AesGcmParameters that = (AesGcmParameters) o;
166     return that.getKeySizeBytes() == getKeySizeBytes()
167         && that.getIvSizeBytes() == getIvSizeBytes()
168         && that.getTagSizeBytes() == getTagSizeBytes()
169         && that.getVariant() == getVariant();
170   }
171 
172   @Override
hashCode()173   public int hashCode() {
174     return Objects.hash(AesGcmParameters.class, keySizeBytes, ivSizeBytes, tagSizeBytes, variant);
175   }
176 
177   @Override
hasIdRequirement()178   public boolean hasIdRequirement() {
179     return variant != Variant.NO_PREFIX;
180   }
181 
182   @Override
toString()183   public String toString() {
184     return "AesGcm Parameters (variant: "
185         + variant
186         + ", "
187         + ivSizeBytes
188         + "-byte IV, "
189         + tagSizeBytes
190         + "-byte tag, and "
191         + keySizeBytes
192         + "-byte key)";
193   }
194 }
195