1 // Copyright 2017 Google Inc. 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.assertTrue; 21 22 import com.google.crypto.tink.InsecureSecretKeyAccess; 23 import com.google.crypto.tink.KeyTemplate; 24 import com.google.crypto.tink.KeyTemplates; 25 import com.google.crypto.tink.KeysetHandle; 26 import com.google.crypto.tink.Parameters; 27 import com.google.crypto.tink.PublicKeySign; 28 import com.google.crypto.tink.PublicKeyVerify; 29 import com.google.crypto.tink.RegistryConfiguration; 30 import com.google.crypto.tink.TinkProtoKeysetFormat; 31 import com.google.crypto.tink.internal.KeyManagerRegistry; 32 import com.google.crypto.tink.internal.SlowInputStream; 33 import com.google.crypto.tink.signature.internal.testing.Ed25519TestUtil; 34 import com.google.crypto.tink.signature.internal.testing.SignatureTestVector; 35 import com.google.crypto.tink.subtle.Hex; 36 import com.google.crypto.tink.util.Bytes; 37 import com.google.crypto.tink.util.SecretBytes; 38 import java.io.ByteArrayInputStream; 39 import java.util.Set; 40 import java.util.TreeSet; 41 import javax.annotation.Nullable; 42 import org.junit.Before; 43 import org.junit.Test; 44 import org.junit.experimental.theories.DataPoints; 45 import org.junit.experimental.theories.FromDataPoints; 46 import org.junit.experimental.theories.Theories; 47 import org.junit.experimental.theories.Theory; 48 import org.junit.runner.RunWith; 49 50 /** Unit tests for Ed25519PrivateKeyManager. */ 51 @RunWith(Theories.class) 52 public class Ed25519PrivateKeyManagerTest { 53 54 @Before register()55 public void register() throws Exception { 56 SignatureConfig.register(); 57 } 58 59 // Tests that generated keys are different. 60 @Test createKey_differentValues()61 public void createKey_differentValues() throws Exception { 62 Set<String> keys = new TreeSet<>(); 63 int numTests = 100; 64 for (int i = 0; i < numTests; i++) { 65 KeysetHandle handle = KeysetHandle.generateNew(Ed25519Parameters.create()); 66 assertThat(handle.size()).isEqualTo(1); 67 assertThat(handle.getAt(0).getKey().getParameters()).isEqualTo(Ed25519Parameters.create()); 68 com.google.crypto.tink.signature.Ed25519PrivateKey key = 69 (com.google.crypto.tink.signature.Ed25519PrivateKey) handle.getAt(0).getKey(); 70 keys.add(Hex.encode(key.getPrivateKeyBytes().toByteArray(InsecureSecretKeyAccess.get()))); 71 } 72 assertThat(keys).hasSize(numTests); 73 } 74 75 @Test testEd25519Template()76 public void testEd25519Template() throws Exception { 77 KeyTemplate template = Ed25519PrivateKeyManager.ed25519Template(); 78 assertThat(template.toParameters()) 79 .isEqualTo(Ed25519Parameters.create(Ed25519Parameters.Variant.TINK)); 80 } 81 82 @Test testRawEd25519Template()83 public void testRawEd25519Template() throws Exception { 84 KeyTemplate template = Ed25519PrivateKeyManager.rawEd25519Template(); 85 assertThat(template.toParameters()) 86 .isEqualTo(Ed25519Parameters.create()); 87 } 88 89 @Test testKeyTemplateAndManagerCompatibility()90 public void testKeyTemplateAndManagerCompatibility() throws Exception { 91 Parameters p = Ed25519PrivateKeyManager.ed25519Template().toParameters(); 92 assertThat(KeysetHandle.generateNew(p).getAt(0).getKey().getParameters()).isEqualTo(p); 93 94 p = Ed25519PrivateKeyManager.rawEd25519Template().toParameters(); 95 assertThat(KeysetHandle.generateNew(p).getAt(0).getKey().getParameters()).isEqualTo(p); 96 } 97 98 @DataPoints("templateNames") 99 public static final String[] KEY_TEMPLATES = 100 new String[] { 101 "ED25519", "ED25519_RAW", "ED25519WithRawOutput", 102 }; 103 104 @Theory testTemplates(@romDataPoints"templateNames") String templateName)105 public void testTemplates(@FromDataPoints("templateNames") String templateName) throws Exception { 106 KeysetHandle h = KeysetHandle.generateNew(KeyTemplates.get(templateName)); 107 assertThat(h.size()).isEqualTo(1); 108 assertThat(h.getAt(0).getKey().getParameters()) 109 .isEqualTo(KeyTemplates.get(templateName).toParameters()); 110 } 111 112 @Test testKeyManagerRegistered()113 public void testKeyManagerRegistered() throws Exception { 114 assertThat( 115 KeyManagerRegistry.globalInstance() 116 .getKeyManager( 117 "type.googleapis.com/google.crypto.tink.Ed25519PrivateKey", 118 PublicKeySign.class)) 119 .isNotNull(); 120 } 121 122 @Test testCreateRawKeyFromRandomness()123 public void testCreateRawKeyFromRandomness() throws Exception { 124 byte[] keyMaterial = 125 Hex.decode( 126 "" 127 + "000102030405060708090A0B0C0D0E0F" 128 + "101112131415161718191A1B1C1D1E1F" 129 + "202122232425262728292A2B2C2D2E2F"); 130 com.google.crypto.tink.signature.Ed25519PrivateKey key = 131 Ed25519PrivateKeyManager.createEd25519KeyFromRandomness( 132 Ed25519Parameters.create(Ed25519Parameters.Variant.NO_PREFIX), 133 new ByteArrayInputStream(keyMaterial), 134 null, 135 InsecureSecretKeyAccess.get()); 136 com.google.crypto.tink.signature.Ed25519PublicKey expectedPublicKey = 137 com.google.crypto.tink.signature.Ed25519PublicKey.create( 138 Ed25519Parameters.Variant.NO_PREFIX, 139 Bytes.copyFrom( 140 Hex.decode("03a107bff3ce10be1d70dd18e74bc09967e4d6309ba50d5f1ddc8664125531b8")), 141 /* idRequirement= */ null); 142 143 com.google.crypto.tink.signature.Ed25519PrivateKey expectedPrivateKey = 144 com.google.crypto.tink.signature.Ed25519PrivateKey.create( 145 expectedPublicKey, 146 SecretBytes.copyFrom( 147 Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"), 148 InsecureSecretKeyAccess.get())); 149 assertTrue(key.equalsKey(expectedPrivateKey)); 150 } 151 152 @Test testCreateTinkKeyFromRandomness()153 public void testCreateTinkKeyFromRandomness() throws Exception { 154 byte[] keyMaterial = 155 Hex.decode( 156 "" 157 + "000102030405060708090A0B0C0D0E0F" 158 + "101112131415161718191A1B1C1D1E1F" 159 + "202122232425262728292A2B2C2D2E2F"); 160 com.google.crypto.tink.signature.Ed25519PrivateKey key = 161 Ed25519PrivateKeyManager.createEd25519KeyFromRandomness( 162 Ed25519Parameters.create(Ed25519Parameters.Variant.TINK), 163 new ByteArrayInputStream(keyMaterial), 164 2344, 165 InsecureSecretKeyAccess.get()); 166 com.google.crypto.tink.signature.Ed25519PublicKey expectedPublicKey = 167 com.google.crypto.tink.signature.Ed25519PublicKey.create( 168 Ed25519Parameters.Variant.TINK, 169 Bytes.copyFrom( 170 Hex.decode("03a107bff3ce10be1d70dd18e74bc09967e4d6309ba50d5f1ddc8664125531b8")), 171 2344); 172 173 com.google.crypto.tink.signature.Ed25519PrivateKey expectedPrivateKey = 174 com.google.crypto.tink.signature.Ed25519PrivateKey.create( 175 expectedPublicKey, 176 SecretBytes.copyFrom( 177 Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"), 178 InsecureSecretKeyAccess.get())); 179 assertTrue(key.equalsKey(expectedPrivateKey)); 180 } 181 182 @Test testCreateKeyFromRandomness_slowInputStream_works()183 public void testCreateKeyFromRandomness_slowInputStream_works() throws Exception { 184 byte[] keyMaterial = 185 Hex.decode( 186 "" 187 + "000102030405060708090A0B0C0D0E0F" 188 + "101112131415161718191A1B1C1D1E1F" 189 + "202122232425262728292A2B2C2D2E2F"); 190 com.google.crypto.tink.signature.Ed25519PrivateKey key = 191 Ed25519PrivateKeyManager.createEd25519KeyFromRandomness( 192 Ed25519Parameters.create(Ed25519Parameters.Variant.TINK), 193 SlowInputStream.copyFrom(keyMaterial), 194 2344, 195 InsecureSecretKeyAccess.get()); 196 com.google.crypto.tink.signature.Ed25519PublicKey expectedPublicKey = 197 com.google.crypto.tink.signature.Ed25519PublicKey.create( 198 Ed25519Parameters.Variant.TINK, 199 Bytes.copyFrom( 200 Hex.decode("03a107bff3ce10be1d70dd18e74bc09967e4d6309ba50d5f1ddc8664125531b8")), 201 2344); 202 com.google.crypto.tink.signature.Ed25519PrivateKey expectedPrivateKey = 203 com.google.crypto.tink.signature.Ed25519PrivateKey.create( 204 expectedPublicKey, 205 SecretBytes.copyFrom( 206 Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"), 207 InsecureSecretKeyAccess.get())); 208 assertTrue(key.equalsKey(expectedPrivateKey)); 209 } 210 211 @DataPoints("testVectors") 212 public static final SignatureTestVector[] ALL_TEST_VECTORS = 213 Ed25519TestUtil.createEd25519TestVectors(); 214 215 @Theory test_computeSignatureInTestVector( @romDataPoints"testVectors") SignatureTestVector v)216 public void test_computeSignatureInTestVector( 217 @FromDataPoints("testVectors") SignatureTestVector v) throws Exception { 218 KeysetHandle.Builder.Entry entry = KeysetHandle.importKey(v.getPrivateKey()).makePrimary(); 219 @Nullable Integer id = v.getPrivateKey().getIdRequirementOrNull(); 220 if (id == null) { 221 entry.withRandomId(); 222 } else { 223 entry.withFixedId(id); 224 } 225 KeysetHandle handle = KeysetHandle.newBuilder().addEntry(entry).build(); 226 PublicKeySign signer = handle.getPrimitive(RegistryConfiguration.get(), PublicKeySign.class); 227 byte[] signature = signer.sign(v.getMessage()); 228 assertThat(Hex.encode(signature)).isEqualTo(Hex.encode(v.getSignature())); 229 } 230 231 @Theory test_validateSignatureInTestVector( @romDataPoints"testVectors") SignatureTestVector v)232 public void test_validateSignatureInTestVector( 233 @FromDataPoints("testVectors") SignatureTestVector v) throws Exception { 234 KeysetHandle.Builder.Entry entry = KeysetHandle.importKey(v.getPrivateKey()).makePrimary(); 235 @Nullable Integer id = v.getPrivateKey().getIdRequirementOrNull(); 236 if (id == null) { 237 entry.withRandomId(); 238 } else { 239 entry.withFixedId(id); 240 } 241 KeysetHandle handle = KeysetHandle.newBuilder().addEntry(entry).build(); 242 PublicKeyVerify verifier = 243 handle 244 .getPublicKeysetHandle() 245 .getPrimitive(RegistryConfiguration.get(), PublicKeyVerify.class); 246 verifier.verify(v.getSignature(), v.getMessage()); 247 } 248 249 @Test test_serializeAndParse_works()250 public void test_serializeAndParse_works() throws Exception { 251 KeysetHandle handle = KeysetHandle.generateNew(Ed25519Parameters.create()); 252 byte[] serializedHandle = 253 TinkProtoKeysetFormat.serializeKeyset(handle, InsecureSecretKeyAccess.get()); 254 KeysetHandle parsedHandle = 255 TinkProtoKeysetFormat.parseKeyset(serializedHandle, InsecureSecretKeyAccess.get()); 256 assertThat(parsedHandle.equalsKeyset(handle)).isTrue(); 257 } 258 } 259