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.internal; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertThrows; 22 import static org.junit.Assert.assertTrue; 23 24 import com.google.crypto.tink.InsecureSecretKeyAccess; 25 import com.google.crypto.tink.KeyManager; 26 import com.google.crypto.tink.Mac; 27 import com.google.crypto.tink.PrivateKeyManager; 28 import com.google.crypto.tink.PublicKeySign; 29 import com.google.crypto.tink.PublicKeyVerify; 30 import com.google.crypto.tink.mac.internal.HmacProtoSerialization; 31 import com.google.crypto.tink.proto.EcdsaKeyFormat; 32 import com.google.crypto.tink.proto.EcdsaParams; 33 import com.google.crypto.tink.proto.EcdsaPrivateKey; 34 import com.google.crypto.tink.proto.EcdsaPublicKey; 35 import com.google.crypto.tink.proto.EcdsaSignatureEncoding; 36 import com.google.crypto.tink.proto.EllipticCurveType; 37 import com.google.crypto.tink.proto.HashType; 38 import com.google.crypto.tink.proto.HmacKey; 39 import com.google.crypto.tink.proto.HmacKeyFormat; 40 import com.google.crypto.tink.proto.HmacParams; 41 import com.google.crypto.tink.proto.KeyData; 42 import com.google.crypto.tink.proto.KeyData.KeyMaterialType; 43 import com.google.crypto.tink.signature.EcdsaParameters; 44 import com.google.crypto.tink.signature.internal.EcdsaProtoSerialization; 45 import com.google.crypto.tink.subtle.EcdsaSignJce; 46 import com.google.crypto.tink.subtle.EcdsaVerifyJce; 47 import com.google.crypto.tink.subtle.Hex; 48 import com.google.crypto.tink.subtle.PrfMac; 49 import com.google.crypto.tink.util.SecretBigInteger; 50 import com.google.crypto.tink.util.SecretBytes; 51 import com.google.protobuf.ByteString; 52 import com.google.protobuf.ExtensionRegistryLite; 53 import java.math.BigInteger; 54 import java.security.GeneralSecurityException; 55 import java.security.KeyPair; 56 import java.security.KeyPairGenerator; 57 import java.security.interfaces.ECPrivateKey; 58 import java.security.interfaces.ECPublicKey; 59 import java.security.spec.ECPoint; 60 import javax.annotation.Nullable; 61 import org.junit.BeforeClass; 62 import org.junit.Test; 63 import org.junit.runner.RunWith; 64 import org.junit.runners.JUnit4; 65 66 @RunWith(JUnit4.class) 67 public final class LegacyKeyManagerImplTest { 68 69 private static KeyManager<Mac> keyManager; 70 private static PrivateKeyManager<PublicKeySign> privateKeyManager; 71 createHmacKey( com.google.crypto.tink.mac.HmacParameters parameters, @Nullable Integer idRequirement)72 private static com.google.crypto.tink.mac.HmacKey createHmacKey( 73 com.google.crypto.tink.mac.HmacParameters parameters, @Nullable Integer idRequirement) 74 throws GeneralSecurityException { 75 return com.google.crypto.tink.mac.HmacKey.builder() 76 .setParameters(parameters) 77 .setKeyBytes(SecretBytes.randomBytes(parameters.getKeySizeBytes())) 78 .setIdRequirement(idRequirement) 79 .build(); 80 } 81 createEcdsaPrivateKey( EcdsaParameters parameters, @Nullable Integer idRequirement)82 private static com.google.crypto.tink.signature.EcdsaPrivateKey createEcdsaPrivateKey( 83 EcdsaParameters parameters, @Nullable Integer idRequirement) throws GeneralSecurityException { 84 KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC"); 85 keyGen.initialize(parameters.getCurveType().toParameterSpec()); 86 KeyPair keyPair = keyGen.generateKeyPair(); 87 ECPrivateKey ecPrivateKey = (ECPrivateKey) keyPair.getPrivate(); 88 ECPublicKey ecPublicKey = (ECPublicKey) keyPair.getPublic(); 89 90 com.google.crypto.tink.signature.EcdsaPublicKey publicKey = 91 com.google.crypto.tink.signature.EcdsaPublicKey.builder() 92 .setParameters(parameters) 93 .setPublicPoint(ecPublicKey.getW()) 94 .setIdRequirement(idRequirement) 95 .build(); 96 return com.google.crypto.tink.signature.EcdsaPrivateKey.builder() 97 .setPublicKey(publicKey) 98 .setPrivateValue( 99 SecretBigInteger.fromBigInteger(ecPrivateKey.getS(), InsecureSecretKeyAccess.get())) 100 .build(); 101 } 102 103 @BeforeClass register()104 public static void register() throws GeneralSecurityException { 105 HmacProtoSerialization.register(); 106 MutablePrimitiveRegistry.globalInstance() 107 .registerPrimitiveConstructor( 108 PrimitiveConstructor.create( 109 PrfMac::create, com.google.crypto.tink.mac.HmacKey.class, Mac.class)); 110 MutableKeyCreationRegistry.globalInstance() 111 .add( 112 LegacyKeyManagerImplTest::createHmacKey, 113 com.google.crypto.tink.mac.HmacParameters.class); 114 115 keyManager = 116 LegacyKeyManagerImpl.create( 117 "type.googleapis.com/google.crypto.tink.HmacKey", 118 Mac.class, 119 KeyMaterialType.SYMMETRIC, 120 HmacKey.parser()); 121 122 EcdsaProtoSerialization.register(); 123 MutablePrimitiveRegistry.globalInstance() 124 .registerPrimitiveConstructor( 125 PrimitiveConstructor.create( 126 EcdsaSignJce::create, 127 com.google.crypto.tink.signature.EcdsaPrivateKey.class, 128 PublicKeySign.class)); 129 MutableKeyCreationRegistry.globalInstance() 130 .add(LegacyKeyManagerImplTest::createEcdsaPrivateKey, EcdsaParameters.class); 131 privateKeyManager = 132 LegacyKeyManagerImpl.createPrivateKeyManager( 133 "type.googleapis.com/google.crypto.tink.EcdsaPrivateKey", 134 PublicKeySign.class, 135 EcdsaPrivateKey.parser()); 136 } 137 138 @Test getPrimitive_messageLite_works()139 public void getPrimitive_messageLite_works() throws Exception { 140 HmacKey key = 141 HmacKey.newBuilder() 142 .setVersion(0) 143 .setParams(HmacParams.newBuilder().setHash(HashType.SHA1).setTagSize(16)) 144 .setKeyValue( 145 ByteString.copyFrom( 146 Hex.decode("816aa4c3ee066310ac1e6666cf830c375355c3c8ba18cfe1f50a48c988b46272"))) 147 .build(); 148 149 Mac mac = keyManager.getPrimitive(key); 150 byte[] message = 151 Hex.decode( 152 "220248f5e6d7a49335b3f91374f18bb8b0ff5e8b9a5853f3cfb293855d78301d837a0a2eb9e4f056f06c08361" 153 + "bd07180ee802651e69726c28910d2baef379606815dcbab01d0dc7acb0ba8e65a2928130da0522f2b2b3d05260" 154 + "885cf1c64f14ca3145313c685b0274bf6a1cb38e4f99895c6a8cc72fbe0e52c01766fede78a1a"); 155 byte[] tag = Hex.decode("17cb2e9e98b748b5ae0f7078ea5519e5"); 156 157 mac.verifyMac(tag, message); 158 } 159 160 @Test getPrimitive_byteString_works()161 public void getPrimitive_byteString_works() throws Exception { 162 HmacKey key = 163 HmacKey.newBuilder() 164 .setVersion(0) 165 .setParams(HmacParams.newBuilder().setHash(HashType.SHA1).setTagSize(16)) 166 .setKeyValue( 167 ByteString.copyFrom( 168 Hex.decode("816aa4c3ee066310ac1e6666cf830c375355c3c8ba18cfe1f50a48c988b46272"))) 169 .build(); 170 171 Mac mac = keyManager.getPrimitive(key.toByteString()); 172 byte[] message = 173 Hex.decode( 174 "220248f5e6d7a49335b3f91374f18bb8b0ff5e8b9a5853f3cfb293855d78301d837a0a2eb9e4f056f06c08361" 175 + "bd07180ee802651e69726c28910d2baef379606815dcbab01d0dc7acb0ba8e65a2928130da0522f2b2b3d05260" 176 + "885cf1c64f14ca3145313c685b0274bf6a1cb38e4f99895c6a8cc72fbe0e52c01766fede78a1a"); 177 byte[] tag = Hex.decode("17cb2e9e98b748b5ae0f7078ea5519e5"); 178 179 mac.verifyMac(tag, message); 180 } 181 182 @Test getPrimitive_invalidKey_throws()183 public void getPrimitive_invalidKey_throws() throws Exception { 184 HmacKey key = 185 HmacKey.newBuilder() 186 .setVersion(0) 187 .setParams(HmacParams.newBuilder().setHash(HashType.UNKNOWN_HASH).setTagSize(16)) 188 .build(); 189 190 assertThrows(GeneralSecurityException.class, () -> keyManager.getPrimitive(key)); 191 } 192 193 @Test newKey_byteString_works()194 public void newKey_byteString_works() throws Exception { 195 HmacKeyFormat keyFormat = 196 HmacKeyFormat.newBuilder() 197 .setKeySize(32) 198 .setParams(HmacParams.newBuilder().setHash(HashType.SHA1).setTagSize(16)) 199 .build(); 200 201 HmacKey key1 = (HmacKey) keyManager.newKey(keyFormat.toByteString()); 202 HmacKey key2 = (HmacKey) keyManager.newKey(keyFormat.toByteString()); 203 assertThat(key1.getKeyValue().size()).isEqualTo(32); 204 assertThat(key1.getKeyValue()).isNotEqualTo(key2.getKeyValue()); 205 assertThat(key1.getParams()).isEqualTo(keyFormat.getParams()); 206 } 207 208 @Test newKey_messageLite_works()209 public void newKey_messageLite_works() throws Exception { 210 HmacKeyFormat keyFormat = 211 HmacKeyFormat.newBuilder() 212 .setKeySize(32) 213 .setParams(HmacParams.newBuilder().setHash(HashType.SHA1).setTagSize(16)) 214 .build(); 215 216 HmacKey key1 = (HmacKey) keyManager.newKey(keyFormat); 217 HmacKey key2 = (HmacKey) keyManager.newKey(keyFormat); 218 assertThat(key1.getKeyValue().size()).isEqualTo(32); 219 assertThat(key1.getKeyValue()).isNotEqualTo(key2.getKeyValue()); 220 assertThat(key1.getParams()).isEqualTo(keyFormat.getParams()); 221 } 222 223 @Test newKeyData_works()224 public void newKeyData_works() throws Exception { 225 HmacKeyFormat keyFormat = 226 HmacKeyFormat.newBuilder() 227 .setKeySize(32) 228 .setParams(HmacParams.newBuilder().setHash(HashType.SHA1).setTagSize(16)) 229 .build(); 230 231 KeyData keyData1 = keyManager.newKeyData(keyFormat.toByteString()); 232 KeyData keyData2 = keyManager.newKeyData(keyFormat.toByteString()); 233 assertThat(keyData1.getKeyMaterialType()).isEqualTo(KeyMaterialType.SYMMETRIC); 234 assertThat(keyData1.getTypeUrl()).isEqualTo("type.googleapis.com/google.crypto.tink.HmacKey"); 235 HmacKey key1 = HmacKey.parseFrom(keyData1.getValue(), ExtensionRegistryLite.getEmptyRegistry()); 236 HmacKey key2 = HmacKey.parseFrom(keyData2.getValue(), ExtensionRegistryLite.getEmptyRegistry()); 237 assertThat(key1.getParams()).isEqualTo(keyFormat.getParams()); 238 assertThat(key1.getKeyValue().size()).isEqualTo(32); 239 assertThat(key1.getKeyValue()).isNotEqualTo(key2.getKeyValue()); 240 } 241 242 @Test doesSupport_works()243 public void doesSupport_works() throws Exception { 244 assertTrue(keyManager.doesSupport("type.googleapis.com/google.crypto.tink.HmacKey")); 245 assertFalse(keyManager.doesSupport("type.googleapis.com/google.crypto.tink.SomeOtherKey")); 246 } 247 248 @Test getKeyType_works()249 public void getKeyType_works() throws Exception { 250 assertThat(keyManager.getKeyType()).isEqualTo("type.googleapis.com/google.crypto.tink.HmacKey"); 251 } 252 253 @Test getVersion_works()254 public void getVersion_works() throws Exception { 255 assertThat(keyManager.getVersion()).isEqualTo(0); 256 } 257 getHexX()258 private static String getHexX() { 259 return "60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6"; 260 } 261 getHexY()262 private static String getHexY() { 263 return "7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299"; 264 } 265 getHexPrivateValue()266 private static String getHexPrivateValue() { 267 return "C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721"; 268 } 269 getProtoPrivateKey()270 private static com.google.crypto.tink.proto.EcdsaPrivateKey getProtoPrivateKey() { 271 com.google.crypto.tink.proto.EcdsaPublicKey protoPublicKey = 272 com.google.crypto.tink.proto.EcdsaPublicKey.newBuilder() 273 .setVersion(0) 274 .setX(ByteString.copyFrom(Hex.decode("00" + getHexX()))) 275 .setY(ByteString.copyFrom(Hex.decode("00" + getHexY()))) 276 .setParams( 277 EcdsaParams.newBuilder() 278 .setHashType(HashType.SHA256) 279 .setCurve(EllipticCurveType.NIST_P256) 280 .setEncoding(EcdsaSignatureEncoding.IEEE_P1363)) 281 .build(); 282 return com.google.crypto.tink.proto.EcdsaPrivateKey.newBuilder() 283 .setVersion(0) 284 .setPublicKey(protoPublicKey) 285 // privateValue is currently serialized with an extra zero at the beginning. 286 .setKeyValue(ByteString.copyFrom(Hex.decode("00" + getHexPrivateValue()))) 287 .build(); 288 } 289 getPlainJavaPrivateKey()290 private static com.google.crypto.tink.signature.EcdsaPrivateKey getPlainJavaPrivateKey() 291 throws GeneralSecurityException { 292 com.google.crypto.tink.signature.EcdsaPublicKey publicKey = 293 com.google.crypto.tink.signature.EcdsaPublicKey.builder() 294 .setParameters( 295 EcdsaParameters.builder() 296 .setSignatureEncoding(EcdsaParameters.SignatureEncoding.IEEE_P1363) 297 .setCurveType(EcdsaParameters.CurveType.NIST_P256) 298 .setHashType(EcdsaParameters.HashType.SHA256) 299 .setVariant(EcdsaParameters.Variant.NO_PREFIX) 300 .build()) 301 .setPublicPoint( 302 new ECPoint(new BigInteger(getHexX(), 16), new BigInteger(getHexY(), 16))) 303 .build(); 304 return com.google.crypto.tink.signature.EcdsaPrivateKey.builder() 305 .setPublicKey(publicKey) 306 .setPrivateValue( 307 SecretBigInteger.fromBigInteger( 308 new BigInteger(getHexPrivateValue(), 16), InsecureSecretKeyAccess.get())) 309 .build(); 310 } 311 312 @Test getPrimitiveClass_works()313 public void getPrimitiveClass_works() throws Exception { 314 assertThat(keyManager.getPrimitiveClass()).isEqualTo(Mac.class); 315 } 316 317 @Test privateKeyManager_getPrimitive_messageLite_works()318 public void privateKeyManager_getPrimitive_messageLite_works() throws Exception { 319 PublicKeySign signer = privateKeyManager.getPrimitive(getProtoPrivateKey()); 320 PublicKeyVerify verifier = EcdsaVerifyJce.create(getPlainJavaPrivateKey().getPublicKey()); 321 byte[] message = new byte[] {}; 322 verifier.verify(signer.sign(message), message); 323 } 324 325 @Test privateKeyManager_getPrimitive_byteString_works()326 public void privateKeyManager_getPrimitive_byteString_works() throws Exception { 327 PublicKeySign signer = privateKeyManager.getPrimitive(getProtoPrivateKey().toByteString()); 328 PublicKeyVerify verifier = EcdsaVerifyJce.create(getPlainJavaPrivateKey().getPublicKey()); 329 byte[] message = new byte[] {}; 330 verifier.verify(signer.sign(message), message); 331 } 332 333 @Test privateKeyManager_getPrimitive_invalidKey_throws()334 public void privateKeyManager_getPrimitive_invalidKey_throws() throws Exception { 335 EcdsaPrivateKey key = EcdsaPrivateKey.getDefaultInstance(); 336 337 assertThrows(GeneralSecurityException.class, () -> keyManager.getPrimitive(key)); 338 } 339 340 @Test privateKeyManager_newKey_byteString_works()341 public void privateKeyManager_newKey_byteString_works() throws Exception { 342 EcdsaKeyFormat keyFormat = 343 EcdsaKeyFormat.newBuilder() 344 .setParams( 345 EcdsaParams.newBuilder() 346 .setHashType(HashType.SHA256) 347 .setCurve(EllipticCurveType.NIST_P256) 348 .setEncoding(EcdsaSignatureEncoding.IEEE_P1363)) 349 .build(); 350 351 EcdsaPrivateKey key1 = (EcdsaPrivateKey) privateKeyManager.newKey(keyFormat.toByteString()); 352 EcdsaPrivateKey key2 = (EcdsaPrivateKey) privateKeyManager.newKey(keyFormat.toByteString()); 353 assertThat(key1.getKeyValue().size()).isEqualTo(33); 354 assertThat(key1.getKeyValue()).isNotEqualTo(key2.getKeyValue()); 355 assertThat(key1.getPublicKey().getParams()).isEqualTo(keyFormat.getParams()); 356 } 357 358 @Test privateKeyManager_newKey_messageLite_works()359 public void privateKeyManager_newKey_messageLite_works() throws Exception { 360 EcdsaKeyFormat keyFormat = 361 EcdsaKeyFormat.newBuilder() 362 .setParams( 363 EcdsaParams.newBuilder() 364 .setHashType(HashType.SHA256) 365 .setCurve(EllipticCurveType.NIST_P256) 366 .setEncoding(EcdsaSignatureEncoding.IEEE_P1363)) 367 .build(); 368 369 EcdsaPrivateKey key1 = (EcdsaPrivateKey) privateKeyManager.newKey(keyFormat); 370 EcdsaPrivateKey key2 = (EcdsaPrivateKey) privateKeyManager.newKey(keyFormat); 371 assertThat(key1.getKeyValue().size()).isEqualTo(33); 372 assertThat(key1.getKeyValue()).isNotEqualTo(key2.getKeyValue()); 373 assertThat(key1.getPublicKey().getParams()).isEqualTo(keyFormat.getParams()); 374 } 375 376 @Test privateKeyManager_newKeyData_works()377 public void privateKeyManager_newKeyData_works() throws Exception { 378 EcdsaKeyFormat keyFormat = 379 EcdsaKeyFormat.newBuilder() 380 .setParams( 381 EcdsaParams.newBuilder() 382 .setHashType(HashType.SHA256) 383 .setCurve(EllipticCurveType.NIST_P256) 384 .setEncoding(EcdsaSignatureEncoding.IEEE_P1363)) 385 .build(); 386 387 KeyData keyData1 = privateKeyManager.newKeyData(keyFormat.toByteString()); 388 KeyData keyData2 = privateKeyManager.newKeyData(keyFormat.toByteString()); 389 assertThat(keyData1.getKeyMaterialType()).isEqualTo(KeyMaterialType.ASYMMETRIC_PRIVATE); 390 391 assertThat(keyData1.getTypeUrl()) 392 .isEqualTo("type.googleapis.com/google.crypto.tink.EcdsaPrivateKey"); 393 EcdsaPrivateKey protoKey1 = 394 EcdsaPrivateKey.parseFrom(keyData1.getValue(), ExtensionRegistryLite.getEmptyRegistry()); 395 EcdsaPrivateKey protoKey2 = 396 EcdsaPrivateKey.parseFrom(keyData2.getValue(), ExtensionRegistryLite.getEmptyRegistry()); 397 assertThat(protoKey1.getKeyValue().size()).isEqualTo(33); 398 assertThat(protoKey1.getKeyValue()).isNotEqualTo(protoKey2.getKeyValue()); 399 assertThat(protoKey1.getPublicKey().getParams()).isEqualTo(keyFormat.getParams()); 400 } 401 402 @Test privateKeyManager_doesSupport_works()403 public void privateKeyManager_doesSupport_works() throws Exception { 404 assertTrue( 405 privateKeyManager.doesSupport("type.googleapis.com/google.crypto.tink.EcdsaPrivateKey")); 406 assertFalse( 407 privateKeyManager.doesSupport("type.googleapis.com/google.crypto.tink.SomeOtherKey")); 408 } 409 410 @Test privateKeyManager_getKeyType_works()411 public void privateKeyManager_getKeyType_works() throws Exception { 412 413 assertThat(privateKeyManager.getKeyType()) 414 .isEqualTo("type.googleapis.com/google.crypto.tink.EcdsaPrivateKey"); 415 } 416 417 @Test privateKeyManager_getVersion_works()418 public void privateKeyManager_getVersion_works() throws Exception { 419 assertThat(privateKeyManager.getVersion()).isEqualTo(0); 420 } 421 422 @Test privateKeyManager_getPrimitiveClass_works()423 public void privateKeyManager_getPrimitiveClass_works() throws Exception { 424 assertThat(privateKeyManager.getPrimitiveClass()).isEqualTo(PublicKeySign.class); 425 } 426 427 @Test privateKeyManager_getPublicKey_works()428 public void privateKeyManager_getPublicKey_works() throws Exception { 429 KeyData publicKeyData = privateKeyManager.getPublicKeyData(getProtoPrivateKey().toByteString()); 430 assertThat(publicKeyData.getTypeUrl()) 431 .isEqualTo("type.googleapis.com/google.crypto.tink.EcdsaPublicKey"); 432 assertThat(publicKeyData.getKeyMaterialType()).isEqualTo(KeyMaterialType.ASYMMETRIC_PUBLIC); 433 434 EcdsaPublicKey publicKey = 435 EcdsaPublicKey.parseFrom( 436 publicKeyData.getValue(), ExtensionRegistryLite.getEmptyRegistry()); 437 assertThat(publicKey).isEqualTo(getProtoPrivateKey().getPublicKey()); 438 } 439 440 @Test privateKeyManager_getPublicKey_notAPrivateKey_throws()441 public void privateKeyManager_getPublicKey_notAPrivateKey_throws() throws Exception { 442 // To test how LegacyKeyManagerImpl.createPrivateKeyManager fails when we use it with a 443 // symmetric key, we simply use it with the same HmacKey as above. 444 PrivateKeyManager<Mac> privateKeyManager = 445 LegacyKeyManagerImpl.createPrivateKeyManager( 446 "type.googleapis.com/google.crypto.tink.HmacKey", Mac.class, HmacKey.parser()); 447 448 HmacKey key = 449 HmacKey.newBuilder() 450 .setVersion(0) 451 .setParams(HmacParams.newBuilder().setHash(HashType.SHA1).setTagSize(16)) 452 .setKeyValue( 453 ByteString.copyFrom( 454 Hex.decode("816aa4c3ee066310ac1e6666cf830c375355c3c8ba18cfe1f50a48c988b46272"))) 455 .build(); 456 457 GeneralSecurityException exception = 458 assertThrows( 459 GeneralSecurityException.class, 460 () -> privateKeyManager.getPublicKeyData(key.toByteString())); 461 assertThat(exception).hasMessageThat().contains("Key not private key"); 462 } 463 } 464