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