• 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 static com.google.common.truth.Truth.assertThat;
20 import static java.nio.charset.StandardCharsets.UTF_8;
21 
22 import com.google.crypto.tink.InsecureSecretKeyAccess;
23 import com.google.crypto.tink.KeyTemplates;
24 import com.google.crypto.tink.KeysetHandle;
25 import com.google.crypto.tink.PublicKeySign;
26 import com.google.crypto.tink.PublicKeyVerify;
27 import com.google.crypto.tink.RegistryConfiguration;
28 import com.google.crypto.tink.util.SecretBigInteger;
29 import java.security.KeyFactory;
30 import java.security.KeyPair;
31 import java.security.KeyPairGenerator;
32 import java.security.PrivateKey;
33 import java.security.PublicKey;
34 import java.security.Signature;
35 import java.security.interfaces.ECPrivateKey;
36 import java.security.interfaces.ECPublicKey;
37 import java.security.interfaces.RSAPrivateCrtKey;
38 import java.security.interfaces.RSAPublicKey;
39 import java.security.spec.RSAPrivateCrtKeySpec;
40 import java.security.spec.RSAPublicKeySpec;
41 import org.junit.BeforeClass;
42 import org.junit.Test;
43 import org.junit.runner.RunWith;
44 import org.junit.runners.JUnit4;
45 
46 @RunWith(JUnit4.class)
47 public final class KeyConversionTest {
48 
49   @BeforeClass
setUp()50   public static void setUp() throws Exception {
51     SignatureConfig.register();
52   }
53 
54   @Test
signAndVerifyWithEcdsaUsingJavaECKeys()55   public void signAndVerifyWithEcdsaUsingJavaECKeys() throws Exception {
56     // Generate a EC key pair
57     KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
58     keyGen.initialize(EcdsaParameters.CurveType.NIST_P384.toParameterSpec());
59     KeyPair keyPair = keyGen.generateKeyPair();
60     PrivateKey privateKey = keyPair.getPrivate();
61     PublicKey publicKey = keyPair.getPublic();
62 
63     // Convert publicKey into a Tink EcdsaPublicKey.
64     ECPublicKey ecPublicKey = (ECPublicKey) publicKey;
65     EcdsaPublicKey ecdsaPublicKey =
66         EcdsaPublicKey.builder()
67             .setParameters(
68                 EcdsaParameters.builder()
69                     .setSignatureEncoding(EcdsaParameters.SignatureEncoding.IEEE_P1363)
70                     .setCurveType(EcdsaParameters.CurveType.NIST_P384)
71                     .setHashType(EcdsaParameters.HashType.SHA384)
72                     .setVariant(EcdsaParameters.Variant.NO_PREFIX)
73                     .build())
74             .setPublicPoint(ecPublicKey.getW())
75             .build();
76 
77     // Convert privateKey and publicKey into a Tink EcdsaPrivateKey.
78     ECPrivateKey ecPrivateKey = (ECPrivateKey) privateKey;
79     EcdsaPrivateKey ecdsaPrivateKey =
80         EcdsaPrivateKey.builder()
81             .setPublicKey(
82                 EcdsaPublicKey.builder()
83                     .setParameters(
84                         EcdsaParameters.builder()
85                             .setSignatureEncoding(EcdsaParameters.SignatureEncoding.IEEE_P1363)
86                             .setCurveType(EcdsaParameters.CurveType.NIST_P384)
87                             .setHashType(EcdsaParameters.HashType.SHA384)
88                             .setVariant(EcdsaParameters.Variant.NO_PREFIX)
89                             .build())
90                     .setPublicPoint(ecPublicKey.getW())
91                     .build())
92             .setPrivateValue(
93                 SecretBigInteger.fromBigInteger(ecPrivateKey.getS(), InsecureSecretKeyAccess.get()))
94             .build();
95 
96     // Generate a PublicKeySign primitive from ecdsaPrivateKey and sign a message.
97     KeysetHandle privateHandle =
98         KeysetHandle.newBuilder()
99             .addEntry(KeysetHandle.importKey(ecdsaPrivateKey).withRandomId().makePrimary())
100             .build();
101     PublicKeySign signer =
102         privateHandle.getPrimitive(RegistryConfiguration.get(), PublicKeySign.class);
103     byte[] data = "data".getBytes(UTF_8);
104     byte[] sig = signer.sign(data);
105 
106     // Generate a PublicKeyVerify primitive from ecdsaPublicKey, and verify the signature.
107     KeysetHandle publicHandle =
108         KeysetHandle.newBuilder()
109             .addEntry(KeysetHandle.importKey(ecdsaPublicKey).withRandomId().makePrimary())
110             .build();
111     PublicKeyVerify verifier =
112         publicHandle.getPrimitive(RegistryConfiguration.get(), PublicKeyVerify.class);
113     verifier.verify(sig, data);
114   }
115 
116   /**
117    * This test show how Tink can be used with Java RSA keys, by importing them as RSA SSA PKCS1
118    * keys.
119    */
120   @Test
signAndVerifyUsingJavaRSAKeys()121   public void signAndVerifyUsingJavaRSAKeys() throws Exception {
122     // Generate a RSA key pair
123     KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
124     keyGen.initialize(/* keysize= */ 2048);
125     KeyPair keyPair = keyGen.generateKeyPair();
126     PrivateKey privateKey = keyPair.getPrivate();
127     PublicKey publicKey = keyPair.getPublic();
128 
129     // Convert publicKey into a Tink RsaSsaPkcs1PublicKey.
130     RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;
131     RsaSsaPkcs1PublicKey rsaSsaPkcs1PublicKey =
132         RsaSsaPkcs1PublicKey.builder()
133             .setParameters(
134                 RsaSsaPkcs1Parameters.builder()
135                     .setModulusSizeBits(rsaPublicKey.getModulus().bitLength())
136                     .setPublicExponent(rsaPublicKey.getPublicExponent())
137                     .setHashType(RsaSsaPkcs1Parameters.HashType.SHA256)
138                     .setVariant(RsaSsaPkcs1Parameters.Variant.NO_PREFIX)
139                     .build())
140             .setModulus(rsaPublicKey.getModulus())
141             .build();
142 
143     // Convert privateKey and publicKey into a Tink RsaSsaPkcs1PrivateKey.
144     RSAPrivateCrtKey rsaPrivateKey = (RSAPrivateCrtKey) privateKey;
145     RsaSsaPkcs1PrivateKey rsaSsaPkcs1PrivateKey =
146         RsaSsaPkcs1PrivateKey.builder()
147             .setPublicKey(rsaSsaPkcs1PublicKey)
148             .setPrimes(
149                 SecretBigInteger.fromBigInteger(
150                     rsaPrivateKey.getPrimeP(), InsecureSecretKeyAccess.get()),
151                 SecretBigInteger.fromBigInteger(
152                     rsaPrivateKey.getPrimeQ(), InsecureSecretKeyAccess.get()))
153             .setPrivateExponent(
154                 SecretBigInteger.fromBigInteger(
155                     rsaPrivateKey.getPrivateExponent(), InsecureSecretKeyAccess.get()))
156             .setPrimeExponents(
157                 SecretBigInteger.fromBigInteger(
158                     rsaPrivateKey.getPrimeExponentP(), InsecureSecretKeyAccess.get()),
159                 SecretBigInteger.fromBigInteger(
160                     rsaPrivateKey.getPrimeExponentQ(), InsecureSecretKeyAccess.get()))
161             .setCrtCoefficient(
162                 SecretBigInteger.fromBigInteger(
163                     rsaPrivateKey.getCrtCoefficient(), InsecureSecretKeyAccess.get()))
164             .build();
165 
166     // Generate a PublicKeySign primitive from rsaSsaPkcs1PrivateKey and sign a message.
167     KeysetHandle privateHandle =
168         KeysetHandle.newBuilder()
169             .addEntry(KeysetHandle.importKey(rsaSsaPkcs1PrivateKey).withRandomId().makePrimary())
170             .build();
171     PublicKeySign signer =
172         privateHandle.getPrimitive(RegistryConfiguration.get(), PublicKeySign.class);
173     byte[] data = "data".getBytes(UTF_8);
174     byte[] sig = signer.sign(data);
175 
176     // Generate a PublicKeyVerify primitive from rsaSsaPkcs1PublicKey, and verify the signature.
177     KeysetHandle publicHandle =
178         KeysetHandle.newBuilder()
179             .addEntry(KeysetHandle.importKey(rsaSsaPkcs1PublicKey).withRandomId().makePrimary())
180             .build();
181     PublicKeyVerify verifier =
182         publicHandle.getPrimitive(RegistryConfiguration.get(), PublicKeyVerify.class);
183     verifier.verify(sig, data);
184 
185     // Verify using java.security.Signature.
186     Signature signatureVerify = Signature.getInstance("SHA256withRSA");
187     signatureVerify.initVerify(publicKey);
188     signatureVerify.update(data);
189     assertThat(signatureVerify.verify(sig)).isTrue();
190   }
191 
192   /** This test shows how Tink keys can be exported to Java RSA keys. */
193   @Test
exportToJavaRSAKey()194   public void exportToJavaRSAKey() throws Exception {
195     KeysetHandle privateHandle =
196         KeysetHandle.generateNew(KeyTemplates.get("RSA_SSA_PKCS1_3072_SHA256_F4_RAW"));
197     KeysetHandle publicHandle = privateHandle.getPublicKeysetHandle();
198 
199     PublicKeySign signer =
200         privateHandle.getPrimitive(RegistryConfiguration.get(), PublicKeySign.class);
201     byte[] data = "data".getBytes(UTF_8);
202     byte[] sig = signer.sign(data);
203 
204     // Export private key and sign using java.security.Signature.
205     RsaSsaPkcs1PrivateKey rsaSsaPkcs1PrivateKey =
206         (RsaSsaPkcs1PrivateKey) privateHandle.getAt(0).getKey();
207     PrivateKey privateKey =
208         KeyFactory.getInstance("RSA")
209             .generatePrivate(
210                 new RSAPrivateCrtKeySpec(
211                     rsaSsaPkcs1PrivateKey.getPublicKey().getModulus(),
212                     rsaSsaPkcs1PrivateKey.getParameters().getPublicExponent(),
213                     rsaSsaPkcs1PrivateKey
214                         .getPrivateExponent()
215                         .getBigInteger(InsecureSecretKeyAccess.get()),
216                     rsaSsaPkcs1PrivateKey.getPrimeP().getBigInteger(InsecureSecretKeyAccess.get()),
217                     rsaSsaPkcs1PrivateKey.getPrimeQ().getBigInteger(InsecureSecretKeyAccess.get()),
218                     rsaSsaPkcs1PrivateKey
219                         .getPrimeExponentP()
220                         .getBigInteger(InsecureSecretKeyAccess.get()),
221                     rsaSsaPkcs1PrivateKey
222                         .getPrimeExponentQ()
223                         .getBigInteger(InsecureSecretKeyAccess.get()),
224                     rsaSsaPkcs1PrivateKey
225                         .getCrtCoefficient()
226                         .getBigInteger(InsecureSecretKeyAccess.get())));
227     Signature signatureSigner = Signature.getInstance("SHA256withRSA");
228     signatureSigner.initSign(privateKey);
229     signatureSigner.update(data);
230     // These signatures are deterministic, so they must be equal.
231     assertThat(signatureSigner.sign()).isEqualTo(sig);
232 
233     // Export public key and verify using java.security.Signature.
234     RsaSsaPkcs1PublicKey rsaSsaPkcs1PublicKey =
235         (RsaSsaPkcs1PublicKey) publicHandle.getAt(0).getKey();
236     PublicKey publicKey =
237         KeyFactory.getInstance("RSA")
238             .generatePublic(
239                 new RSAPublicKeySpec(
240                     rsaSsaPkcs1PublicKey.getModulus(),
241                     rsaSsaPkcs1PublicKey.getParameters().getPublicExponent()));
242     Signature signatureVerify = Signature.getInstance("SHA256withRSA");
243     signatureVerify.initVerify(publicKey);
244     signatureVerify.update(data);
245     assertThat(signatureVerify.verify(sig)).isTrue();
246   }
247 }
248