• 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.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 /**
31  * Represents the Aead ChaCha20-Poly1305 specified in RFC 8439.
32  *
33  * <p>ChaCha20-Poly1305 allows no parameters; hence the main part here is really just the keys.
34  * However, Tink allows prefixing every ciphertext with an ID-dependent prefix, see {@link
35  * ChaCha20Poly1305Parameters.Variant}.
36  */
37 @Immutable
38 public final class ChaCha20Poly1305Key extends AeadKey {
39   private final ChaCha20Poly1305Parameters parameters;
40   private final SecretBytes keyBytes;
41   private final Bytes outputPrefix;
42   @Nullable private final Integer idRequirement;
43 
ChaCha20Poly1305Key( ChaCha20Poly1305Parameters parameters, SecretBytes keyBytes, Bytes outputPrefix, @Nullable Integer idRequirement)44   private ChaCha20Poly1305Key(
45       ChaCha20Poly1305Parameters parameters,
46       SecretBytes keyBytes,
47       Bytes outputPrefix,
48       @Nullable Integer idRequirement) {
49     this.parameters = parameters;
50     this.keyBytes = keyBytes;
51     this.outputPrefix = outputPrefix;
52     this.idRequirement = idRequirement;
53   }
54 
getOutputPrefix( ChaCha20Poly1305Parameters parameters, @Nullable Integer idRequirement)55   private static Bytes getOutputPrefix(
56       ChaCha20Poly1305Parameters parameters, @Nullable Integer idRequirement) {
57     if (parameters.getVariant() == ChaCha20Poly1305Parameters.Variant.NO_PREFIX) {
58       return OutputPrefixUtil.EMPTY_PREFIX;
59     }
60     if (parameters.getVariant() == ChaCha20Poly1305Parameters.Variant.CRUNCHY) {
61       return OutputPrefixUtil.getLegacyOutputPrefix(idRequirement);
62     }
63     if (parameters.getVariant() == ChaCha20Poly1305Parameters.Variant.TINK) {
64       return OutputPrefixUtil.getTinkOutputPrefix(idRequirement);
65     }
66     throw new IllegalStateException("Unknown Variant: " + parameters.getVariant());
67   }
68 
69   @Override
getOutputPrefix()70   public Bytes getOutputPrefix() {
71     return outputPrefix;
72   }
73 
74   @RestrictedApi(
75       explanation = "Accessing parts of keys can produce unexpected incompatibilities, annotate the function with @AccessesPartialKey",
76       link = "https://developers.google.com/tink/design/access_control#accessing_partial_keys",
77       allowedOnPath = ".*Test\\.java",
78       allowlistAnnotations = {AccessesPartialKey.class})
79   @AccessesPartialKey
create(SecretBytes secretBytes)80   public static ChaCha20Poly1305Key create(SecretBytes secretBytes)
81       throws GeneralSecurityException {
82     return create(ChaCha20Poly1305Parameters.Variant.NO_PREFIX, secretBytes, null);
83   }
84 
85   @RestrictedApi(
86       explanation = "Accessing parts of keys can produce unexpected incompatibilities, annotate the function with @AccessesPartialKey",
87       link = "https://developers.google.com/tink/design/access_control#accessing_partial_keys",
88       allowedOnPath = ".*Test\\.java",
89       allowlistAnnotations = {AccessesPartialKey.class})
create( ChaCha20Poly1305Parameters.Variant variant, SecretBytes secretBytes, @Nullable Integer idRequirement)90   public static ChaCha20Poly1305Key create(
91       ChaCha20Poly1305Parameters.Variant variant,
92       SecretBytes secretBytes,
93       @Nullable Integer idRequirement)
94       throws GeneralSecurityException {
95     if (variant != ChaCha20Poly1305Parameters.Variant.NO_PREFIX && idRequirement == null) {
96       throw new GeneralSecurityException(
97           "For given Variant " + variant + " the value of idRequirement must be non-null");
98     }
99     if (variant == ChaCha20Poly1305Parameters.Variant.NO_PREFIX && idRequirement != null) {
100       throw new GeneralSecurityException(
101           "For given Variant NO_PREFIX the value of idRequirement must be null");
102     }
103     if (secretBytes.size() != 32) {
104       throw new GeneralSecurityException(
105           "ChaCha20Poly1305 key must be constructed with key of length 32 bytes, not "
106               + secretBytes.size());
107     }
108     ChaCha20Poly1305Parameters parameters = ChaCha20Poly1305Parameters.create(variant);
109     return new ChaCha20Poly1305Key(
110         parameters, secretBytes, getOutputPrefix(parameters, 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})
getKeyBytes()118   public SecretBytes getKeyBytes() {
119     return keyBytes;
120   }
121 
122   @Override
getParameters()123   public ChaCha20Poly1305Parameters getParameters() {
124     return parameters;
125   }
126 
127   @Override
128   @Nullable
getIdRequirementOrNull()129   public Integer getIdRequirementOrNull() {
130     return idRequirement;
131   }
132 
133   @Override
equalsKey(Key o)134   public boolean equalsKey(Key o) {
135     if (!(o instanceof ChaCha20Poly1305Key)) {
136       return false;
137     }
138     ChaCha20Poly1305Key that = (ChaCha20Poly1305Key) o;
139     // Since outputPrefix is a function of parameters, we can ignore it here.
140     return that.parameters.equals(parameters)
141         && that.keyBytes.equalsSecretBytes(keyBytes)
142         && Objects.equals(that.idRequirement, idRequirement);
143   }
144 }
145