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