• 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.signature;
18 
19 import com.google.crypto.tink.AccessesPartialKey;
20 import com.google.crypto.tink.Key;
21 import com.google.crypto.tink.internal.EllipticCurvesUtil;
22 import com.google.crypto.tink.internal.OutputPrefixUtil;
23 import com.google.crypto.tink.util.Bytes;
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.security.spec.ECPoint;
29 import java.util.Objects;
30 import javax.annotation.Nullable;
31 
32 /** EcdsaPublicKey represents the public portion of ECDSA signature primitive. */
33 @Immutable
34 public final class EcdsaPublicKey extends SignaturePublicKey {
35   private final EcdsaParameters parameters;
36   @SuppressWarnings("Immutable") // ECPoint is immutable
37   private final ECPoint publicPoint;
38   private final Bytes outputPrefix;
39   @Nullable private final Integer idRequirement;
40 
41   /** Builder for EcdsaPublicKey. */
42   public static class Builder {
43     @Nullable private EcdsaParameters parameters = null;
44     @Nullable private ECPoint publicPoint = null;
45     @Nullable private Integer idRequirement = null;
46 
Builder()47     private Builder() {}
48 
49     @CanIgnoreReturnValue
setParameters(EcdsaParameters parameters)50     public Builder setParameters(EcdsaParameters parameters) {
51       this.parameters = parameters;
52       return this;
53     }
54 
55     @CanIgnoreReturnValue
setPublicPoint(ECPoint publicPoint)56     public Builder setPublicPoint(ECPoint publicPoint) {
57       this.publicPoint = publicPoint;
58       return this;
59     }
60 
61     @CanIgnoreReturnValue
setIdRequirement(@ullable Integer idRequirement)62     public Builder setIdRequirement(@Nullable Integer idRequirement) {
63       this.idRequirement = idRequirement;
64       return this;
65     }
66 
getOutputPrefix()67     private Bytes getOutputPrefix() {
68       if (parameters.getVariant() == EcdsaParameters.Variant.NO_PREFIX) {
69         return OutputPrefixUtil.EMPTY_PREFIX;
70       }
71       if (parameters.getVariant() == EcdsaParameters.Variant.LEGACY
72           || parameters.getVariant() == EcdsaParameters.Variant.CRUNCHY) {
73         return OutputPrefixUtil.getLegacyOutputPrefix(idRequirement);
74       }
75       if (parameters.getVariant() == EcdsaParameters.Variant.TINK) {
76         return OutputPrefixUtil.getTinkOutputPrefix(idRequirement);
77       }
78       throw new IllegalStateException(
79           "Unknown EcdsaParameters.Variant: " + parameters.getVariant());
80     }
81 
build()82     public EcdsaPublicKey build() throws GeneralSecurityException {
83       if (parameters == null) {
84         throw new GeneralSecurityException("Cannot build without parameters");
85       }
86       if (publicPoint == null) {
87         throw new GeneralSecurityException("Cannot build without public point");
88       }
89       EllipticCurvesUtil.checkPointOnCurve(
90           publicPoint, parameters.getCurveType().toParameterSpec().getCurve());
91       if (parameters.hasIdRequirement() && idRequirement == null) {
92         throw new GeneralSecurityException(
93             "Cannot create key without ID requirement with parameters with ID requirement");
94       }
95       if (!parameters.hasIdRequirement() && idRequirement != null) {
96         throw new GeneralSecurityException(
97             "Cannot create key with ID requirement with parameters without ID requirement");
98       }
99       Bytes outputPrefix = getOutputPrefix();
100       return new EcdsaPublicKey(parameters, publicPoint, outputPrefix, idRequirement);
101     }
102   }
103 
EcdsaPublicKey( EcdsaParameters parameters, ECPoint publicPoint, Bytes outputPrefix, @Nullable Integer idRequirement)104   private EcdsaPublicKey(
105       EcdsaParameters parameters,
106       ECPoint publicPoint,
107       Bytes outputPrefix,
108       @Nullable Integer idRequirement) {
109     this.parameters = parameters;
110     this.publicPoint = publicPoint;
111     this.outputPrefix = outputPrefix;
112     this.idRequirement = idRequirement;
113   }
114 
115   @RestrictedApi(
116       explanation = "Accessing parts of keys can produce unexpected incompatibilities, annotate the function with @AccessesPartialKey",
117       link = "https://developers.google.com/tink/design/access_control#accessing_partial_keys",
118       allowedOnPath = ".*Test\\.java",
119       allowlistAnnotations = {AccessesPartialKey.class})
builder()120   public static Builder builder() {
121     return new Builder();
122   }
123 
124   @RestrictedApi(
125       explanation = "Accessing parts of keys can produce unexpected incompatibilities, annotate the function with @AccessesPartialKey",
126       link = "https://developers.google.com/tink/design/access_control#accessing_partial_keys",
127       allowedOnPath = ".*Test\\.java",
128       allowlistAnnotations = {AccessesPartialKey.class})
getPublicPoint()129   public ECPoint getPublicPoint() {
130     return publicPoint;
131   }
132 
133   @Override
getOutputPrefix()134   public Bytes getOutputPrefix() {
135     return outputPrefix;
136   }
137 
138   @Override
getParameters()139   public EcdsaParameters getParameters() {
140     return parameters;
141   }
142 
143   @Override
144   @Nullable
getIdRequirementOrNull()145   public Integer getIdRequirementOrNull() {
146     return idRequirement;
147   }
148 
149   @Override
equalsKey(Key o)150   public boolean equalsKey(Key o) {
151     if (!(o instanceof EcdsaPublicKey)) {
152       return false;
153     }
154     EcdsaPublicKey that = (EcdsaPublicKey) o;
155     // Since outputPrefix is a function of parameters, we can ignore it here.
156     return that.parameters.equals(parameters)
157         && that.publicPoint.equals(publicPoint)
158         && Objects.equals(that.idRequirement, idRequirement);
159   }
160 }
161