• 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.signature;
18 
19 import com.google.errorprone.annotations.CanIgnoreReturnValue;
20 import com.google.errorprone.annotations.Immutable;
21 import java.math.BigInteger;
22 import java.security.GeneralSecurityException;
23 import java.security.InvalidAlgorithmParameterException;
24 import java.util.Objects;
25 import javax.annotation.Nullable;
26 
27 /**
28  * Describes the parameters of a {@link RsaSsaPkcs1PublicKey} and {@link RsaSsaPkcs1PrivateKey}.
29  *
30  * <p>Standard: https://www.rfc-editor.org/rfc/rfc8017.txt
31  */
32 public final class RsaSsaPkcs1Parameters extends SignatureParameters {
33   /**
34    * Describes details of the signature.
35    *
36    * <p>The usual key is used for variant "NO_PREFIX". Other variants slightly change how the
37    * signature is computed, or add a prefix to every computation depending on the key id.
38    */
39   @Immutable
40   public static final class Variant {
41     public static final Variant TINK = new Variant("TINK");
42     public static final Variant CRUNCHY = new Variant("CRUNCHY");
43     public static final Variant LEGACY = new Variant("LEGACY");
44     public static final Variant NO_PREFIX = new Variant("NO_PREFIX");
45 
46     private final String name;
47 
Variant(String name)48     private Variant(String name) {
49       this.name = name;
50     }
51 
52     @Override
toString()53     public String toString() {
54       return name;
55     }
56   }
57 
58   /** The Hash algorithm used. */
59   @Immutable
60   public static final class HashType {
61     public static final HashType SHA256 = new HashType("SHA256");
62     public static final HashType SHA384 = new HashType("SHA384");
63     public static final HashType SHA512 = new HashType("SHA512");
64 
65     private final String name;
66 
HashType(String name)67     private HashType(String name) {
68       this.name = name;
69     }
70 
71     @Override
toString()72     public String toString() {
73       return name;
74     }
75   }
76 
77   public static final BigInteger F4 = BigInteger.valueOf(65537);
78 
79   /** Builds a new RsaSsaPkcs1Parameters instance. */
80   public static final class Builder {
81     @Nullable private Integer modulusSizeBits = null;
82     @Nullable private BigInteger publicExponent = F4;
83     @Nullable private HashType hashType = null;
84     private Variant variant = Variant.NO_PREFIX;
85 
Builder()86     private Builder() {}
87 
88     @CanIgnoreReturnValue
setModulusSizeBits(int modulusSizeBits)89     public Builder setModulusSizeBits(int modulusSizeBits) {
90       this.modulusSizeBits = modulusSizeBits;
91       return this;
92     }
93 
94     @CanIgnoreReturnValue
setPublicExponent(BigInteger e)95     public Builder setPublicExponent(BigInteger e) {
96       this.publicExponent = e;
97       return this;
98     }
99 
100     @CanIgnoreReturnValue
setVariant(Variant variant)101     public Builder setVariant(Variant variant) {
102       this.variant = variant;
103       return this;
104     }
105 
106     @CanIgnoreReturnValue
setHashType(HashType hashType)107     public Builder setHashType(HashType hashType) {
108       this.hashType = hashType;
109       return this;
110     }
111 
112     private static final BigInteger TWO = BigInteger.valueOf(2);
113     private static final BigInteger PUBLIC_EXPONENT_UPPER_BOUND = TWO.pow(256);
114 
validatePublicExponent(BigInteger publicExponent)115     private void validatePublicExponent(BigInteger publicExponent)
116         throws InvalidAlgorithmParameterException {
117       // We use the validation of the public exponent as defined in
118       // https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf, B.3
119       int c = publicExponent.compareTo(F4);
120       if (c == 0) {
121         // publicExponent is F4.
122         return;
123       }
124       if (c < 0) {
125         // publicExponent is smaller than F4.
126         throw new InvalidAlgorithmParameterException("Public exponent must be at least 65537.");
127       }
128       if (publicExponent.mod(TWO).equals(BigInteger.ZERO)) {
129         // publicExponent is even. This is invalid since it is not co-prime to p-1.
130         throw new InvalidAlgorithmParameterException("Invalid public exponent");
131       }
132       if (publicExponent.compareTo(PUBLIC_EXPONENT_UPPER_BOUND) > 0) {
133         // publicExponent is larger than PUBLIC_EXPONENT_UPPER_BOUND.
134         throw new InvalidAlgorithmParameterException(
135             "Public exponent cannot be larger than 2^256.");
136       }
137     }
138 
build()139     public RsaSsaPkcs1Parameters build() throws GeneralSecurityException {
140       if (modulusSizeBits == null) {
141         throw new GeneralSecurityException("key size is not set");
142       }
143       if (publicExponent == null) {
144         throw new GeneralSecurityException("publicExponent is not set");
145       }
146       if (hashType == null) {
147         throw new GeneralSecurityException("hash type is not set");
148       }
149       if (variant == null) {
150         throw new GeneralSecurityException("variant is not set");
151       }
152       if (modulusSizeBits < 2048) {
153         throw new InvalidAlgorithmParameterException(
154             String.format(
155                 "Invalid key size in bytes %d; must be at least 2048 bits", modulusSizeBits));
156       }
157       validatePublicExponent(publicExponent);
158       return new RsaSsaPkcs1Parameters(modulusSizeBits, publicExponent, variant, hashType);
159     }
160   }
161 
162   private final int modulusSizeBits;
163   private final BigInteger publicExponent;
164   private final Variant variant;
165   private final HashType hashType;
166 
RsaSsaPkcs1Parameters( int modulusSizeBits, BigInteger publicExponent, Variant variant, HashType hashType)167   private RsaSsaPkcs1Parameters(
168       int modulusSizeBits, BigInteger publicExponent, Variant variant, HashType hashType) {
169     this.modulusSizeBits = modulusSizeBits;
170     this.publicExponent = publicExponent;
171     this.variant = variant;
172     this.hashType = hashType;
173   }
174 
builder()175   public static Builder builder() {
176     return new Builder();
177   }
178 
getModulusSizeBits()179   public int getModulusSizeBits() {
180     return modulusSizeBits;
181   }
182 
getPublicExponent()183   public BigInteger getPublicExponent() {
184     return publicExponent;
185   }
186 
getVariant()187   public Variant getVariant() {
188     return variant;
189   }
190 
getHashType()191   public HashType getHashType() {
192     return hashType;
193   }
194 
195   @Override
equals(Object o)196   public boolean equals(Object o) {
197     if (!(o instanceof RsaSsaPkcs1Parameters)) {
198       return false;
199     }
200     RsaSsaPkcs1Parameters that = (RsaSsaPkcs1Parameters) o;
201     return that.getModulusSizeBits() == getModulusSizeBits()
202         && Objects.equals(that.getPublicExponent(), getPublicExponent())
203         && that.getVariant() == getVariant()
204         && that.getHashType() == getHashType();
205   }
206 
207   @Override
hashCode()208   public int hashCode() {
209     return Objects.hash(
210         RsaSsaPkcs1Parameters.class, modulusSizeBits, publicExponent, variant, hashType);
211   }
212 
213   @Override
hasIdRequirement()214   public boolean hasIdRequirement() {
215     return variant != Variant.NO_PREFIX;
216   }
217 
218   @Override
toString()219   public String toString() {
220     return "RSA SSA PKCS1 Parameters (variant: "
221         + variant
222         + ", hashType: "
223         + hashType
224         + ", publicExponent: "
225         + publicExponent
226         + ", and "
227         + modulusSizeBits
228         + "-bit modulus)";
229   }
230 }
231