• 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.InsecureSecretKeyAccess;
21 import com.google.crypto.tink.Key;
22 import com.google.crypto.tink.internal.EllipticCurvesUtil;
23 import com.google.crypto.tink.util.SecretBigInteger;
24 import com.google.errorprone.annotations.CanIgnoreReturnValue;
25 import com.google.errorprone.annotations.Immutable;
26 import com.google.errorprone.annotations.RestrictedApi;
27 import java.math.BigInteger;
28 import java.security.GeneralSecurityException;
29 import java.security.spec.ECPoint;
30 
31 /**
32  * Represents a key for computing ECDSA signatures.
33  *
34  * <p>ECDSA is defined in http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf, section 6.
35  */
36 @Immutable
37 public final class EcdsaPrivateKey extends SignaturePrivateKey {
38   private final EcdsaPublicKey publicKey;
39   private final SecretBigInteger privateValue;
40 
41   /** Builder for EcdsaPrivateKey. */
42   public static class Builder {
43     private EcdsaPublicKey publicKey = null;
44     private SecretBigInteger privateValue = null;
45 
Builder()46     private Builder() {}
47 
48     @CanIgnoreReturnValue
setPublicKey(EcdsaPublicKey publicKey)49     public Builder setPublicKey(EcdsaPublicKey publicKey) {
50       this.publicKey = publicKey;
51       return this;
52     }
53 
54     @CanIgnoreReturnValue
setPrivateValue(SecretBigInteger privateValue)55     public Builder setPrivateValue(SecretBigInteger privateValue) {
56       this.privateValue = privateValue;
57       return this;
58     }
59 
validatePrivateValue( BigInteger privateValue, ECPoint publicPoint, EcdsaParameters.CurveType curveType)60     private static void validatePrivateValue(
61         BigInteger privateValue, ECPoint publicPoint, EcdsaParameters.CurveType curveType)
62         throws GeneralSecurityException {
63       BigInteger order = curveType.toParameterSpec().getOrder();
64       if ((privateValue.signum() <= 0) || (privateValue.compareTo(order) >= 0)) {
65         throw new GeneralSecurityException("Invalid private value");
66       }
67       ECPoint p = EllipticCurvesUtil.multiplyByGenerator(privateValue, curveType.toParameterSpec());
68       if (!p.equals(publicPoint)) {
69         throw new GeneralSecurityException("Invalid private value");
70       }
71     }
72 
73     @AccessesPartialKey
build()74     public EcdsaPrivateKey build() throws GeneralSecurityException {
75       if (publicKey == null) {
76         throw new GeneralSecurityException("Cannot build without a ecdsa public key");
77       }
78       if (privateValue == null) {
79         throw new GeneralSecurityException("Cannot build without a private value");
80       }
81       validatePrivateValue(
82           privateValue.getBigInteger(InsecureSecretKeyAccess.get()),
83           publicKey.getPublicPoint(),
84           publicKey.getParameters().getCurveType());
85       return new EcdsaPrivateKey(publicKey, privateValue);
86     }
87   }
88 
EcdsaPrivateKey(EcdsaPublicKey publicKey, SecretBigInteger privateValue)89   private EcdsaPrivateKey(EcdsaPublicKey publicKey, SecretBigInteger privateValue) {
90     this.publicKey = publicKey;
91     this.privateValue = privateValue;
92   }
93 
94   @RestrictedApi(
95       explanation = "Accessing parts of keys can produce unexpected incompatibilities, annotate the function with @AccessesPartialKey",
96       link = "https://developers.google.com/tink/design/access_control#accessing_partial_keys",
97       allowedOnPath = ".*Test\\.java",
98       allowlistAnnotations = {AccessesPartialKey.class})
builder()99   public static Builder builder() {
100     return new Builder();
101   }
102 
103   @Override
getParameters()104   public EcdsaParameters getParameters() {
105     return publicKey.getParameters();
106   }
107 
108   @Override
getPublicKey()109   public EcdsaPublicKey getPublicKey() {
110     return publicKey;
111   }
112 
113   @RestrictedApi(
114       explanation = "Accessing parts of keys can produce unexpected incompatibilities, annotate the function with @AccessesPartialKey",
115       link = "https://developers.google.com/tink/design/access_control#accessing_partial_keys",
116       allowedOnPath = ".*Test\\.java",
117       allowlistAnnotations = {AccessesPartialKey.class})
getPrivateValue()118   public SecretBigInteger getPrivateValue() {
119     return privateValue;
120   }
121 
122   @Override
equalsKey(Key o)123   public boolean equalsKey(Key o) {
124     if (!(o instanceof EcdsaPrivateKey)) {
125       return false;
126     }
127     EcdsaPrivateKey that = (EcdsaPrivateKey) o;
128     return that.publicKey.equalsKey(publicKey)
129         && privateValue.equalsSecretBigInteger(that.privateValue);
130   }
131 }
132