• 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 static com.google.common.truth.Truth.assertThat;
20 import static org.junit.Assert.assertThrows;
21 
22 import com.google.crypto.tink.InsecureSecretKeyAccess;
23 import com.google.crypto.tink.internal.KeyTester;
24 import com.google.crypto.tink.subtle.Hex;
25 import com.google.crypto.tink.util.Bytes;
26 import com.google.crypto.tink.util.SecretBigInteger;
27 import java.math.BigInteger;
28 import java.security.GeneralSecurityException;
29 import java.security.KeyFactory;
30 import java.security.KeyPair;
31 import java.security.KeyPairGenerator;
32 import java.security.interfaces.ECPrivateKey;
33 import java.security.interfaces.ECPublicKey;
34 import java.security.spec.ECPoint;
35 import java.security.spec.ECPrivateKeySpec;
36 import java.security.spec.ECPublicKeySpec;
37 import org.junit.Test;
38 import org.junit.runner.RunWith;
39 import org.junit.runners.JUnit4;
40 
41 @RunWith(JUnit4.class)
42 public final class EcdsaPrivateKeyTest {
43 
44   // Test case from https://www.ietf.org/rfc/rfc6979.txt, A.2.5
45   private static final ECPoint P256_PUBLIC_POINT =
46       new ECPoint(
47           new BigInteger("60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6", 16),
48           new BigInteger("7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299", 16));
49   private static final BigInteger P256_PRIVATE_VALUE =
50       new BigInteger("C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721", 16);
51 
52   // Test case from https://www.ietf.org/rfc/rfc6979.txt, A.2.5
53   private static final ECPoint P521_PUBLIC_POINT =
54       new ECPoint(
55           new BigInteger(
56               "1894550D0785932E00EAA23B694F213F8C3121F86DC97A04E5A7167DB4E5BCD3"
57                   + "71123D46E45DB6B5D5370A7F20FB633155D38FFA16D2BD761DCAC474B9A2F502"
58                   + "3A4",
59               16),
60           new BigInteger(
61               "0493101C962CD4D2FDDF782285E64584139C2F91B47F87FF82354D6630F746A2"
62                   + "8A0DB25741B5B34A828008B22ACC23F924FAAFBD4D33F81EA66956DFEAA2BFDF"
63                   + "CF5",
64               16));
65   private static final BigInteger P521_PRIVATE_VALUE =
66       new BigInteger(
67           "0FAD06DAA62BA3B25D2FB40133DA757205DE67F5BB0018FEE8C86E1B68C7E75C"
68               + "AA896EB32F1F47C70855836A6D16FCC1466F6D8FBEC67DB89EC0C08B0E996B83"
69               + "538",
70           16);
71 
72   @Test
buildNoPrefixVariantAndGetProperties()73   public void buildNoPrefixVariantAndGetProperties() throws Exception {
74     EcdsaParameters parameters =
75         EcdsaParameters.builder()
76             .setSignatureEncoding(EcdsaParameters.SignatureEncoding.IEEE_P1363)
77             .setCurveType(EcdsaParameters.CurveType.NIST_P256)
78             .setHashType(EcdsaParameters.HashType.SHA256)
79             .setVariant(EcdsaParameters.Variant.NO_PREFIX)
80             .build();
81     assertThat(parameters.hasIdRequirement()).isFalse();
82     EcdsaPublicKey publicKey =
83         EcdsaPublicKey.builder()
84             .setParameters(parameters)
85             .setPublicPoint(P256_PUBLIC_POINT)
86             .build();
87     EcdsaPrivateKey privateKey =
88         EcdsaPrivateKey.builder()
89             .setPublicKey(publicKey)
90             .setPrivateValue(
91                 SecretBigInteger.fromBigInteger(P256_PRIVATE_VALUE, InsecureSecretKeyAccess.get()))
92             .build();
93     assertThat(privateKey.getParameters()).isEqualTo(parameters);
94     assertThat(privateKey.getPublicKey()).isEqualTo(publicKey);
95     assertThat(privateKey.getPrivateValue().getBigInteger(InsecureSecretKeyAccess.get()))
96         .isEqualTo(P256_PRIVATE_VALUE);
97     assertThat(privateKey.getOutputPrefix()).isEqualTo(Bytes.copyFrom(new byte[] {}));
98     assertThat(privateKey.getIdRequirementOrNull()).isNull();
99   }
100 
101   @Test
buildTinkVariantAndGetProperties()102   public void buildTinkVariantAndGetProperties() throws Exception {
103     EcdsaParameters parameters =
104         EcdsaParameters.builder()
105             .setSignatureEncoding(EcdsaParameters.SignatureEncoding.IEEE_P1363)
106             .setCurveType(EcdsaParameters.CurveType.NIST_P256)
107             .setHashType(EcdsaParameters.HashType.SHA256)
108             .setVariant(EcdsaParameters.Variant.TINK)
109             .build();
110     assertThat(parameters.hasIdRequirement()).isTrue();
111     EcdsaPublicKey publicKey =
112         EcdsaPublicKey.builder()
113             .setParameters(parameters)
114             .setPublicPoint(P256_PUBLIC_POINT)
115             .setIdRequirement(0x66AABBCC)
116             .build();
117     EcdsaPrivateKey privateKey =
118         EcdsaPrivateKey.builder()
119             .setPublicKey(publicKey)
120             .setPrivateValue(
121                 SecretBigInteger.fromBigInteger(P256_PRIVATE_VALUE, InsecureSecretKeyAccess.get()))
122             .build();
123     assertThat(privateKey.getParameters()).isEqualTo(parameters);
124     assertThat(privateKey.getPublicKey()).isEqualTo(publicKey);
125     assertThat(privateKey.getPrivateValue().getBigInteger(InsecureSecretKeyAccess.get()))
126         .isEqualTo(P256_PRIVATE_VALUE);
127     assertThat(privateKey.getOutputPrefix()).isEqualTo(Bytes.copyFrom(Hex.decode("0166AABBCC")));
128     assertThat(privateKey.getIdRequirementOrNull()).isEqualTo(0x66AABBCC);
129   }
130 
131   @Test
convertToAndFromJavaECKeys()132   public void convertToAndFromJavaECKeys() throws Exception {
133     // Create an elliptic curve key pair using Java's KeyPairGenerator.
134     KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
135     keyGen.initialize(EcdsaParameters.CurveType.NIST_P384.toParameterSpec());
136     KeyPair keyPair = keyGen.generateKeyPair();
137     ECPrivateKey ecPrivateKey = (ECPrivateKey) keyPair.getPrivate();
138     ECPublicKey ecPublicKey = (ECPublicKey) keyPair.getPublic();
139 
140     // Before conversion, always check that the specs of ecPrivateKey and ecPublicKey are what
141     // we expect.
142     assertThat(EcdsaParameters.CurveType.fromParameterSpec(ecPrivateKey.getParams()))
143         .isEqualTo(EcdsaParameters.CurveType.NIST_P384);
144     assertThat(EcdsaParameters.CurveType.fromParameterSpec(ecPublicKey.getParams()))
145         .isEqualTo(EcdsaParameters.CurveType.NIST_P384);
146 
147     // Create EcdsaParameters that match the curve type.
148     EcdsaParameters parameters =
149         EcdsaParameters.builder()
150             .setSignatureEncoding(EcdsaParameters.SignatureEncoding.IEEE_P1363)
151             .setCurveType(EcdsaParameters.CurveType.NIST_P384)
152             .setHashType(EcdsaParameters.HashType.SHA384)
153             .setVariant(EcdsaParameters.Variant.NO_PREFIX)
154             .build();
155 
156     // Create EcdsaPublicKey and EcdsaPrivateKey using ecPublicKey and ecPrivateKey.
157     EcdsaPublicKey publicKey =
158         EcdsaPublicKey.builder()
159             .setParameters(parameters)
160             .setPublicPoint(ecPublicKey.getW())
161             .build();
162     EcdsaPrivateKey privateKey =
163         EcdsaPrivateKey.builder()
164             .setPublicKey(publicKey)
165             .setPrivateValue(
166                 SecretBigInteger.fromBigInteger(ecPrivateKey.getS(), InsecureSecretKeyAccess.get()))
167             .build();
168 
169     // Convert EcdsaPublicKey and back into a ECPublicKey.
170     KeyFactory keyFactory = KeyFactory.getInstance("EC");
171     ECPublicKey ecPublicKey2 =
172         (ECPublicKey)
173             keyFactory.generatePublic(
174                 new ECPublicKeySpec(
175                     publicKey.getPublicPoint(),
176                     publicKey.getParameters().getCurveType().toParameterSpec()));
177     assertThat(ecPublicKey2.getW()).isEqualTo(ecPublicKey.getW());
178     assertThat(EcdsaParameters.CurveType.fromParameterSpec(ecPublicKey2.getParams()))
179         .isEqualTo(EcdsaParameters.CurveType.NIST_P384);
180 
181     // Convert EcdsaPrivateKey back into a ECPrivateKey.
182     ECPrivateKey ecPrivateKey2 =
183         (ECPrivateKey)
184             keyFactory.generatePrivate(
185                 new ECPrivateKeySpec(
186                     privateKey.getPrivateValue().getBigInteger(InsecureSecretKeyAccess.get()),
187                     privateKey.getParameters().getCurveType().toParameterSpec()));
188     assertThat(ecPrivateKey2.getS()).isEqualTo(ecPrivateKey.getS());
189     assertThat(EcdsaParameters.CurveType.fromParameterSpec(ecPrivateKey2.getParams()))
190         .isEqualTo(EcdsaParameters.CurveType.NIST_P384);
191   }
192 
193   @Test
emptyBuild_fails()194   public void emptyBuild_fails() throws Exception {
195     assertThrows(GeneralSecurityException.class, () -> EcdsaPublicKey.builder().build());
196   }
197 
198   @Test
buildWithoutPublicKey_fails()199   public void buildWithoutPublicKey_fails() throws Exception {
200     assertThrows(
201         GeneralSecurityException.class,
202         () ->
203             EcdsaPrivateKey.builder()
204                 .setPrivateValue(
205                     SecretBigInteger.fromBigInteger(
206                         P256_PRIVATE_VALUE, InsecureSecretKeyAccess.get()))
207                 .build());
208   }
209 
210   @Test
build_validatesPrivateValue()211   public void build_validatesPrivateValue() throws Exception {
212     EcdsaParameters parameters =
213         EcdsaParameters.builder()
214             .setSignatureEncoding(EcdsaParameters.SignatureEncoding.IEEE_P1363)
215             .setCurveType(EcdsaParameters.CurveType.NIST_P256)
216             .setHashType(EcdsaParameters.HashType.SHA256)
217             .setVariant(EcdsaParameters.Variant.NO_PREFIX)
218             .build();
219     EcdsaPublicKey publicKey =
220         EcdsaPublicKey.builder()
221             .setParameters(parameters)
222             .setPublicPoint(P256_PUBLIC_POINT)
223             .build();
224     EcdsaPrivateKey valid =
225         EcdsaPrivateKey.builder()
226             .setPublicKey(publicKey)
227             .setPrivateValue(
228                 SecretBigInteger.fromBigInteger(P256_PRIVATE_VALUE, InsecureSecretKeyAccess.get()))
229             .build();
230     assertThat(valid.getPrivateValue().getBigInteger(InsecureSecretKeyAccess.get()))
231         .isEqualTo(P256_PRIVATE_VALUE);
232     BigInteger invalidPrivateValue = P256_PRIVATE_VALUE.add(BigInteger.ONE);
233     assertThrows(
234         GeneralSecurityException.class,
235         () ->
236             EcdsaPrivateKey.builder()
237                 .setPublicKey(publicKey)
238                 .setPrivateValue(
239                     SecretBigInteger.fromBigInteger(
240                         invalidPrivateValue, InsecureSecretKeyAccess.get()))
241                 .build());
242     assertThrows(
243         GeneralSecurityException.class,
244         () ->
245             EcdsaPrivateKey.builder()
246                 .setPublicKey(publicKey)
247                 .setPrivateValue(
248                     SecretBigInteger.fromBigInteger(BigInteger.ZERO, InsecureSecretKeyAccess.get()))
249                 .build());
250     assertThrows(
251         GeneralSecurityException.class,
252         () ->
253             EcdsaPrivateKey.builder()
254                 .setPublicKey(publicKey)
255                 .setPrivateValue(
256                     SecretBigInteger.fromBigInteger(
257                         new BigInteger("-1"), InsecureSecretKeyAccess.get()))
258                 .build());
259   }
260 
261   @Test
build_rejectsPrivateValueThatIsLargerThanOrder()262   public void build_rejectsPrivateValueThatIsLargerThanOrder() throws Exception {
263     EcdsaParameters parameters =
264         EcdsaParameters.builder()
265             .setSignatureEncoding(EcdsaParameters.SignatureEncoding.IEEE_P1363)
266             .setCurveType(EcdsaParameters.CurveType.NIST_P256)
267             .setHashType(EcdsaParameters.HashType.SHA256)
268             .setVariant(EcdsaParameters.Variant.NO_PREFIX)
269             .build();
270     EcdsaPublicKey publicKey =
271         EcdsaPublicKey.builder()
272             .setParameters(parameters)
273             .setPublicPoint(P256_PUBLIC_POINT)
274             .build();
275     EcdsaPrivateKey valid =
276         EcdsaPrivateKey.builder()
277             .setPublicKey(publicKey)
278             .setPrivateValue(
279                 SecretBigInteger.fromBigInteger(P256_PRIVATE_VALUE, InsecureSecretKeyAccess.get()))
280             .build();
281     assertThat(valid.getPrivateValue().getBigInteger(InsecureSecretKeyAccess.get()))
282         .isEqualTo(P256_PRIVATE_VALUE);
283     // Add the order of the generator to the private value.
284     BigInteger tooLargePrivateValue =
285         P256_PRIVATE_VALUE.add(EcdsaParameters.CurveType.NIST_P256.toParameterSpec().getOrder());
286     assertThrows(
287         GeneralSecurityException.class,
288         () ->
289             EcdsaPrivateKey.builder()
290                 .setPublicKey(publicKey)
291                 .setPrivateValue(
292                     SecretBigInteger.fromBigInteger(
293                         tooLargePrivateValue, InsecureSecretKeyAccess.get()))
294                 .build());
295   }
296 
297   @Test
testEqualities()298   public void testEqualities() throws Exception {
299     EcdsaPublicKey noPrefixPublicKey =
300         EcdsaPublicKey.builder()
301             .setParameters(
302                 EcdsaParameters.builder()
303                     .setSignatureEncoding(EcdsaParameters.SignatureEncoding.IEEE_P1363)
304                     .setCurveType(EcdsaParameters.CurveType.NIST_P256)
305                     .setHashType(EcdsaParameters.HashType.SHA256)
306                     .setVariant(EcdsaParameters.Variant.NO_PREFIX)
307                     .build())
308             .setPublicPoint(P256_PUBLIC_POINT)
309             .build();
310 
311     // Uses generator as public key, and private key as ONE
312     EcdsaPublicKey noPrefixPublicKeyOne =
313         EcdsaPublicKey.builder()
314             .setParameters(
315                 EcdsaParameters.builder()
316                     .setSignatureEncoding(EcdsaParameters.SignatureEncoding.IEEE_P1363)
317                     .setCurveType(EcdsaParameters.CurveType.NIST_P256)
318                     .setHashType(EcdsaParameters.HashType.SHA256)
319                     .setVariant(EcdsaParameters.Variant.NO_PREFIX)
320                     .build())
321             .setPublicPoint(EcdsaParameters.CurveType.NIST_P256.toParameterSpec().getGenerator())
322             .build();
323 
324     EcdsaPublicKey tinkPrefixPublicKey =
325         EcdsaPublicKey.builder()
326             .setParameters(
327                 EcdsaParameters.builder()
328                     .setSignatureEncoding(EcdsaParameters.SignatureEncoding.IEEE_P1363)
329                     .setCurveType(EcdsaParameters.CurveType.NIST_P256)
330                     .setHashType(EcdsaParameters.HashType.SHA256)
331                     .setVariant(EcdsaParameters.Variant.TINK)
332                     .build())
333             .setPublicPoint(P256_PUBLIC_POINT)
334             .setIdRequirement(1907)
335             .build();
336 
337     EcdsaPublicKey noPrefixPublicKeyP521 =
338         EcdsaPublicKey.builder()
339             .setParameters(
340                 EcdsaParameters.builder()
341                     .setSignatureEncoding(EcdsaParameters.SignatureEncoding.IEEE_P1363)
342                     .setCurveType(EcdsaParameters.CurveType.NIST_P521)
343                     .setHashType(EcdsaParameters.HashType.SHA512)
344                     .setVariant(EcdsaParameters.Variant.NO_PREFIX)
345                     .build())
346             .setPublicPoint(P521_PUBLIC_POINT)
347             .build();
348 
349     new KeyTester()
350         .addEqualityGroup(
351             "No prefix",
352             EcdsaPrivateKey.builder()
353                 .setPublicKey(noPrefixPublicKey)
354                 .setPrivateValue(
355                     SecretBigInteger.fromBigInteger(
356                         P256_PRIVATE_VALUE, InsecureSecretKeyAccess.get()))
357                 .build(),
358             // the same key built twice must be equal
359             EcdsaPrivateKey.builder()
360                 .setPublicKey(
361                     EcdsaPublicKey.builder()
362                         .setParameters(
363                             EcdsaParameters.builder()
364                                 .setSignatureEncoding(EcdsaParameters.SignatureEncoding.IEEE_P1363)
365                                 .setCurveType(EcdsaParameters.CurveType.NIST_P256)
366                                 .setHashType(EcdsaParameters.HashType.SHA256)
367                                 .setVariant(EcdsaParameters.Variant.NO_PREFIX)
368                                 .build())
369                         .setPublicPoint(P256_PUBLIC_POINT)
370                         .build())
371                 .setPrivateValue(
372                     SecretBigInteger.fromBigInteger(
373                         P256_PRIVATE_VALUE, InsecureSecretKeyAccess.get()))
374                 .build())
375         // This group checks that keys with different key bytes are not equal
376         .addEqualityGroup(
377             "No prefix, ONE",
378             EcdsaPrivateKey.builder()
379                 .setPublicKey(noPrefixPublicKeyOne)
380                 .setPrivateValue(
381                     SecretBigInteger.fromBigInteger(BigInteger.ONE, InsecureSecretKeyAccess.get()))
382                 .build())
383         // This group checks that keys with different parameters are not equal
384         .addEqualityGroup(
385             "No prefix, P521",
386             EcdsaPrivateKey.builder()
387                 .setPublicKey(noPrefixPublicKeyP521)
388                 .setPrivateValue(
389                     SecretBigInteger.fromBigInteger(
390                         P521_PRIVATE_VALUE, InsecureSecretKeyAccess.get()))
391                 .build())
392         .addEqualityGroup(
393             "Tink with key id 1907",
394             EcdsaPrivateKey.builder()
395                 .setPublicKey(tinkPrefixPublicKey)
396                 .setPrivateValue(
397                     SecretBigInteger.fromBigInteger(
398                         P256_PRIVATE_VALUE, InsecureSecretKeyAccess.get()))
399                 .build())
400         .doTests();
401   }
402 }
403