• 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.internal.EllipticCurvesUtil;
20 import com.google.errorprone.annotations.CanIgnoreReturnValue;
21 import com.google.errorprone.annotations.Immutable;
22 import java.security.GeneralSecurityException;
23 import java.security.spec.ECParameterSpec;
24 import java.util.Objects;
25 
26 /** Describes the parameters of an ECDSA signature primitive. */
27 public final class EcdsaParameters extends SignatureParameters {
28   /**
29    * Describes details of the ECDSA signature computation.
30    *
31    * <p>The standard ECDSA key is used for variant "NO_PREFIX". Other variants slightly change how
32    * the signature is computed, or add a prefix to every computation depending on the key id.
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 LEGACY = new Variant("LEGACY");
39     public static final Variant NO_PREFIX = new Variant("NO_PREFIX");
40 
41     private final String name;
42 
Variant(String name)43     private Variant(String name) {
44       this.name = name;
45     }
46 
47     @Override
toString()48     public String toString() {
49       return name;
50     }
51   }
52 
53   /** The encoding used in the signature. */
54   @Immutable
55   public static final class SignatureEncoding {
56     public static final SignatureEncoding IEEE_P1363 = new SignatureEncoding("IEEE_P1363");
57     public static final SignatureEncoding DER = new SignatureEncoding("DER");
58 
59     private final String name;
60 
SignatureEncoding(String name)61     private SignatureEncoding(String name) {
62       this.name = name;
63     }
64 
65     @Override
toString()66     public String toString() {
67       return name;
68     }
69   }
70 
71   /** The elliptic curve and its parameters. */
72   @Immutable
73   public static final class CurveType {
74     public static final CurveType NIST_P256 =
75         new CurveType("NIST_P256", EllipticCurvesUtil.NIST_P256_PARAMS);
76     public static final CurveType NIST_P384 =
77         new CurveType("NIST_P384", EllipticCurvesUtil.NIST_P384_PARAMS);
78     public static final CurveType NIST_P521 =
79         new CurveType("NIST_P521", EllipticCurvesUtil.NIST_P521_PARAMS);
80 
81     private final String name;
82     @SuppressWarnings("Immutable") // ECParameterSpec is immutable
83     private final ECParameterSpec spec;
84 
CurveType(String name, ECParameterSpec spec)85     private CurveType(String name, ECParameterSpec spec) {
86       this.name = name;
87       this.spec = spec;
88     }
89 
90     @Override
toString()91     public String toString() {
92       return name;
93     }
94 
toParameterSpec()95     public ECParameterSpec toParameterSpec() {
96       return spec;
97     }
98 
fromParameterSpec(ECParameterSpec spec)99     public static CurveType fromParameterSpec(ECParameterSpec spec)
100         throws GeneralSecurityException {
101       if (EllipticCurvesUtil.isSameEcParameterSpec(spec, NIST_P256.toParameterSpec())) {
102         return NIST_P256;
103       }
104       if (EllipticCurvesUtil.isSameEcParameterSpec(spec, NIST_P384.toParameterSpec())) {
105         return NIST_P384;
106       }
107       if (EllipticCurvesUtil.isSameEcParameterSpec(spec, NIST_P521.toParameterSpec())) {
108         return NIST_P521;
109       }
110       throw new GeneralSecurityException("unknown ECParameterSpec");
111     }
112   }
113 
114   /** The Hash algorithm used. */
115   @Immutable
116   public static final class HashType {
117     public static final HashType SHA256 = new HashType("SHA256");
118     public static final HashType SHA384 = new HashType("SHA384");
119     public static final HashType SHA512 = new HashType("SHA512");
120 
121     private final String name;
122 
HashType(String name)123     private HashType(String name) {
124       this.name = name;
125     }
126 
127     @Override
toString()128     public String toString() {
129       return name;
130     }
131   }
132 
133   /** Builds a new EcdsaParameters instance. */
134   public static final class Builder {
135     private SignatureEncoding signatureEncoding = null;
136     private CurveType curveType = null;
137     private HashType hashType = null;
138     private Variant variant = Variant.NO_PREFIX;
139 
Builder()140     private Builder() {}
141 
142     @CanIgnoreReturnValue
setSignatureEncoding(SignatureEncoding signatureEncoding)143     public Builder setSignatureEncoding(SignatureEncoding signatureEncoding) {
144       this.signatureEncoding = signatureEncoding;
145       return this;
146     }
147 
148     @CanIgnoreReturnValue
setCurveType(CurveType curveType)149     public Builder setCurveType(CurveType curveType) {
150       this.curveType = curveType;
151       return this;
152     }
153 
154     @CanIgnoreReturnValue
setHashType(HashType hashType)155     public Builder setHashType(HashType hashType) {
156       this.hashType = hashType;
157       return this;
158     }
159 
160     @CanIgnoreReturnValue
setVariant(Variant variant)161     public Builder setVariant(Variant variant) {
162       this.variant = variant;
163       return this;
164     }
165 
build()166     public EcdsaParameters build() throws GeneralSecurityException {
167       if (signatureEncoding == null) {
168         throw new GeneralSecurityException("signature encoding is not set");
169       }
170       if (curveType == null) {
171         throw new GeneralSecurityException("EC curve type is not set");
172       }
173       if (hashType == null) {
174         throw new GeneralSecurityException("hash type is not set");
175       }
176       if (variant == null) {
177         throw new GeneralSecurityException("variant is not set");
178       }
179 
180       if (curveType == CurveType.NIST_P256) {
181         if (hashType != HashType.SHA256) {
182           throw new GeneralSecurityException("NIST_P256 requires SHA256");
183         }
184       }
185       if (curveType == CurveType.NIST_P384) {
186         if (hashType != HashType.SHA384 && hashType != HashType.SHA512) {
187           throw new GeneralSecurityException("NIST_P384 requires SHA384 or SHA512");
188         }
189       }
190       if (curveType == CurveType.NIST_P521) {
191         if (hashType != HashType.SHA512) {
192           throw new GeneralSecurityException("NIST_P521 requires SHA512");
193         }
194       }
195       return new EcdsaParameters(signatureEncoding, curveType, hashType, variant);
196     }
197   }
198 
199   private final SignatureEncoding signatureEncoding;
200   private final CurveType curveType;
201   private final HashType hashType;
202   private final Variant variant;
203 
EcdsaParameters( SignatureEncoding signatureEncoding, CurveType curveType, HashType hashType, Variant variant)204   private EcdsaParameters(
205       SignatureEncoding signatureEncoding,
206       CurveType curveType,
207       HashType hashType,
208       Variant variant) {
209     this.signatureEncoding = signatureEncoding;
210     this.curveType = curveType;
211     this.hashType = hashType;
212     this.variant = variant;
213   }
214 
builder()215   public static Builder builder() {
216     return new Builder();
217   }
218 
getSignatureEncoding()219   public SignatureEncoding getSignatureEncoding() {
220     return signatureEncoding;
221   }
222 
getCurveType()223   public CurveType getCurveType() {
224     return curveType;
225   }
226 
getHashType()227   public HashType getHashType() {
228     return hashType;
229   }
230 
getVariant()231   public Variant getVariant() {
232     return variant;
233   }
234 
235   @Override
equals(Object o)236   public boolean equals(Object o) {
237     if (!(o instanceof EcdsaParameters)) {
238       return false;
239     }
240     EcdsaParameters that = (EcdsaParameters) o;
241     return that.getSignatureEncoding() == getSignatureEncoding()
242         && that.getCurveType() == getCurveType()
243         && that.getHashType() == getHashType()
244         && that.getVariant() == getVariant();
245   }
246 
247   @Override
hashCode()248   public int hashCode() {
249     return Objects.hash(EcdsaParameters.class, signatureEncoding, curveType, hashType, variant);
250   }
251 
252   @Override
hasIdRequirement()253   public boolean hasIdRequirement() {
254     return variant != Variant.NO_PREFIX;
255   }
256 
257   @Override
toString()258   public String toString() {
259     return "ECDSA Parameters (variant: "
260         + variant
261         + ", hashType: "
262         + hashType
263         + ", encoding: "
264         + signatureEncoding
265         + ", curve: "
266         + curveType
267         + ")";
268   }
269 }
270