• 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.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.errorprone.annotations.CanIgnoreReturnValue;
24 import com.google.errorprone.annotations.RestrictedApi;
25 import java.math.BigInteger;
26 import java.security.GeneralSecurityException;
27 import java.util.Objects;
28 import javax.annotation.Nullable;
29 
30 /**
31  * Represents a public key for the RSA SSA PKCS1 signature primitive.
32  *
33  * <p>Standard: https://www.rfc-editor.org/rfc/rfc8017.txt
34  */
35 public final class RsaSsaPkcs1PublicKey extends SignaturePublicKey {
36   private final RsaSsaPkcs1Parameters parameters;
37   private final BigInteger modulus;
38   private final Bytes outputPrefix;
39   @Nullable private final Integer idRequirement;
40 
41   /** Builder for RsaSsaPkcs1PublicKey. */
42   public static class Builder {
43     @Nullable private RsaSsaPkcs1Parameters parameters = null;
44     @Nullable private BigInteger modulus = null;
45     @Nullable private Integer idRequirement = null;
46 
Builder()47     private Builder() {}
48 
49     @CanIgnoreReturnValue
setParameters(RsaSsaPkcs1Parameters parameters)50     public Builder setParameters(RsaSsaPkcs1Parameters parameters) {
51       this.parameters = parameters;
52       return this;
53     }
54 
55     @CanIgnoreReturnValue
setModulus(BigInteger modulus)56     public Builder setModulus(BigInteger modulus) {
57       this.modulus = modulus;
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() == RsaSsaPkcs1Parameters.Variant.NO_PREFIX) {
69         return OutputPrefixUtil.EMPTY_PREFIX;
70       }
71       if (parameters.getVariant() == RsaSsaPkcs1Parameters.Variant.LEGACY
72           || parameters.getVariant() == RsaSsaPkcs1Parameters.Variant.CRUNCHY) {
73         return OutputPrefixUtil.getLegacyOutputPrefix(idRequirement);
74       }
75       if (parameters.getVariant() == RsaSsaPkcs1Parameters.Variant.TINK) {
76         return OutputPrefixUtil.getTinkOutputPrefix(idRequirement);
77       }
78       throw new IllegalStateException(
79           "Unknown RsaSsaPkcs1Parameters.Variant: " + parameters.getVariant());
80     }
81 
build()82     public RsaSsaPkcs1PublicKey build() throws GeneralSecurityException {
83       if (parameters == null) {
84         throw new GeneralSecurityException("Cannot build without parameters");
85       }
86 
87       if (modulus == null) {
88         throw new GeneralSecurityException("Cannot build without modulus");
89       }
90       int modulusSize = modulus.bitLength();
91       int paramModulusSize = parameters.getModulusSizeBits();
92       // https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf, B.3 requires p and q
93       // to be chosen such that 2^(paramModulusSize-1) < modulus < 2^paramModulusSize.
94       if (modulusSize != paramModulusSize) {
95         throw new GeneralSecurityException(
96             "Got modulus size "
97                 + modulusSize
98                 + ", but parameters requires modulus size "
99                 + paramModulusSize);
100       }
101 
102       if (parameters.hasIdRequirement() && idRequirement == null) {
103         throw new GeneralSecurityException(
104             "Cannot create key without ID requirement with parameters with ID requirement");
105       }
106 
107       if (!parameters.hasIdRequirement() && idRequirement != null) {
108         throw new GeneralSecurityException(
109             "Cannot create key with ID requirement with parameters without ID requirement");
110       }
111       Bytes outputPrefix = getOutputPrefix();
112       return new RsaSsaPkcs1PublicKey(parameters, modulus, outputPrefix, idRequirement);
113     }
114   }
115 
RsaSsaPkcs1PublicKey( RsaSsaPkcs1Parameters parameters, BigInteger modulus, Bytes outputPrefix, @Nullable Integer idRequirement)116   private RsaSsaPkcs1PublicKey(
117       RsaSsaPkcs1Parameters parameters,
118       BigInteger modulus,
119       Bytes outputPrefix,
120       @Nullable Integer idRequirement) {
121     this.parameters = parameters;
122     this.modulus = modulus;
123     this.outputPrefix = outputPrefix;
124     this.idRequirement = idRequirement;
125   }
126 
127   @RestrictedApi(
128       explanation = "Accessing parts of keys can produce unexpected incompatibilities, annotate the function with @AccessesPartialKey",
129       link = "https://developers.google.com/tink/design/access_control#accessing_partial_keys",
130       allowedOnPath = ".*Test\\.java",
131       allowlistAnnotations = {AccessesPartialKey.class})
builder()132   public static Builder builder() {
133     return new Builder();
134   }
135 
136   /** Returns the underlying key bytes. */
137   @RestrictedApi(
138       explanation = "Accessing parts of keys can produce unexpected incompatibilities, annotate the function with @AccessesPartialKey",
139       link = "https://developers.google.com/tink/design/access_control#accessing_partial_keys",
140       allowedOnPath = ".*Test\\.java",
141       allowlistAnnotations = {AccessesPartialKey.class})
getModulus()142   public BigInteger getModulus() {
143     return modulus;
144   }
145 
146   @Override
getOutputPrefix()147   public Bytes getOutputPrefix() {
148     return outputPrefix;
149   }
150 
151   @Override
getParameters()152   public RsaSsaPkcs1Parameters getParameters() {
153     return parameters;
154   }
155 
156   @Override
157   @Nullable
getIdRequirementOrNull()158   public Integer getIdRequirementOrNull() {
159     return idRequirement;
160   }
161 
162   @Override
equalsKey(Key o)163   public boolean equalsKey(Key o) {
164     if (!(o instanceof RsaSsaPkcs1PublicKey)) {
165       return false;
166     }
167     RsaSsaPkcs1PublicKey that = (RsaSsaPkcs1PublicKey) o;
168     // Since outputPrefix is a function of parameters, we can ignore it here.
169     return that.parameters.equals(parameters)
170         && that.modulus.equals(modulus)
171         && Objects.equals(that.idRequirement, idRequirement);
172   }
173 }
174