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 AesEaxKey}. */ 27 public final class AesEaxParameters 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 /** Builds a new AesEaxParameters instance. */ 53 public static final class Builder { 54 @Nullable private Integer keySizeBytes = null; 55 @Nullable private Integer ivSizeBytes = null; 56 @Nullable private Integer tagSizeBytes = null; 57 private Variant variant = Variant.NO_PREFIX; 58 Builder()59 private Builder() {} 60 61 /** 62 * Accepts key sizes of 16, 24 or 32 bytes. However, some implementation may not support the 63 * full set of parameters at the moment and may restrict the key size to 16 or 32-byte values. 64 */ 65 @CanIgnoreReturnValue setKeySizeBytes(int keySizeBytes)66 public Builder setKeySizeBytes(int keySizeBytes) throws GeneralSecurityException { 67 if (keySizeBytes != 16 && keySizeBytes != 24 && keySizeBytes != 32) { 68 throw new InvalidAlgorithmParameterException( 69 String.format( 70 "Invalid key size %d; only 16-byte, 24-byte and 32-byte AES keys are supported", 71 keySizeBytes)); 72 } 73 this.keySizeBytes = keySizeBytes; 74 return this; 75 } 76 /** IV size must be 12 or 16 bytes. */ 77 @CanIgnoreReturnValue setIvSizeBytes(int ivSizeBytes)78 public Builder setIvSizeBytes(int ivSizeBytes) throws GeneralSecurityException { 79 if (ivSizeBytes != 12 && ivSizeBytes != 16) { 80 throw new GeneralSecurityException( 81 String.format( 82 "Invalid IV size in bytes %d; acceptable values have 12 or 16 bytes", ivSizeBytes)); 83 } 84 this.ivSizeBytes = ivSizeBytes; 85 return this; 86 } 87 /** 88 * The tag size accepts values between 0 and 16 bytes. However, some implementation may not 89 * support the full set of parameters at the moment and may restrict the tag size to a fixed 90 * value (i.e. 16 bytes). 91 */ 92 @CanIgnoreReturnValue setTagSizeBytes(int tagSizeBytes)93 public Builder setTagSizeBytes(int tagSizeBytes) throws GeneralSecurityException { 94 if (tagSizeBytes < 0 || tagSizeBytes > 16) { 95 throw new GeneralSecurityException( 96 String.format( 97 "Invalid tag size in bytes %d; value must be at most 16 bytes", tagSizeBytes)); 98 } 99 this.tagSizeBytes = tagSizeBytes; 100 return this; 101 } 102 103 @CanIgnoreReturnValue setVariant(Variant variant)104 public Builder setVariant(Variant variant) { 105 this.variant = variant; 106 return this; 107 } 108 build()109 public AesEaxParameters build() throws GeneralSecurityException { 110 if (keySizeBytes == null) { 111 throw new GeneralSecurityException("Key size is not set"); 112 } 113 if (ivSizeBytes == null) { 114 throw new GeneralSecurityException("IV size is not set"); 115 } 116 if (variant == null) { 117 throw new GeneralSecurityException("Variant is not set"); 118 } 119 120 if (tagSizeBytes == null) { 121 throw new GeneralSecurityException("Tag size is not set"); 122 } 123 124 return new AesEaxParameters(keySizeBytes, ivSizeBytes, tagSizeBytes, variant); 125 } 126 } 127 128 private final int keySizeBytes; 129 private final int ivSizeBytes; 130 private final int tagSizeBytes; 131 private final Variant variant; 132 AesEaxParameters(int keySizeBytes, int ivSizeBytes, int tagSizeBytes, Variant variant)133 private AesEaxParameters(int keySizeBytes, int ivSizeBytes, int tagSizeBytes, Variant variant) { 134 this.keySizeBytes = keySizeBytes; 135 this.ivSizeBytes = ivSizeBytes; 136 this.tagSizeBytes = tagSizeBytes; 137 this.variant = variant; 138 } 139 builder()140 public static Builder builder() { 141 return new Builder(); 142 } 143 getKeySizeBytes()144 public int getKeySizeBytes() { 145 return keySizeBytes; 146 } 147 getIvSizeBytes()148 public int getIvSizeBytes() { 149 return ivSizeBytes; 150 } 151 getTagSizeBytes()152 public int getTagSizeBytes() { 153 return tagSizeBytes; 154 } 155 156 /** Returns a variant object. */ getVariant()157 public Variant getVariant() { 158 return variant; 159 } 160 161 @Override equals(Object o)162 public boolean equals(Object o) { 163 if (!(o instanceof AesEaxParameters)) { 164 return false; 165 } 166 AesEaxParameters that = (AesEaxParameters) o; 167 return that.getKeySizeBytes() == getKeySizeBytes() 168 && that.getIvSizeBytes() == getIvSizeBytes() 169 && that.getTagSizeBytes() == getTagSizeBytes() 170 && that.getVariant() == getVariant(); 171 } 172 173 @Override hashCode()174 public int hashCode() { 175 return Objects.hash(AesEaxParameters.class, keySizeBytes, ivSizeBytes, tagSizeBytes, variant); 176 } 177 178 @Override hasIdRequirement()179 public boolean hasIdRequirement() { 180 return variant != Variant.NO_PREFIX; 181 } 182 183 @Override toString()184 public String toString() { 185 return "AesEax Parameters (variant: " 186 + variant 187 + ", " 188 + ivSizeBytes 189 + "-byte IV, " 190 + tagSizeBytes 191 + "-byte tag, and " 192 + keySizeBytes 193 + "-byte key)"; 194 } 195 } 196