diff options
author | tholenst <tholenst@google.com> | 2023-07-21 07:10:17 -0700 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2023-07-21 07:11:31 -0700 |
commit | 0b93273056d1d2e82d652d9871125add33623e52 (patch) | |
tree | e63c4e458498fab2e1b9f7027d83f3dcc7fef615 /java_src/src/test | |
parent | 7eab20215cd36782545257b9683d4d66d14f58bd (diff) | |
download | tink-0b93273056d1d2e82d652d9871125add33623e52.tar.gz |
Add serialization for Ecies Public Keys.
PiperOrigin-RevId: 549938077
Diffstat (limited to 'java_src/src/test')
-rw-r--r-- | java_src/src/test/java/com/google/crypto/tink/hybrid/BUILD.bazel | 8 | ||||
-rw-r--r-- | java_src/src/test/java/com/google/crypto/tink/hybrid/EciesProtoSerializationTest.java | 425 |
2 files changed, 428 insertions, 5 deletions
diff --git a/java_src/src/test/java/com/google/crypto/tink/hybrid/BUILD.bazel b/java_src/src/test/java/com/google/crypto/tink/hybrid/BUILD.bazel index b88aced42..c8e4506e5 100644 --- a/java_src/src/test/java/com/google/crypto/tink/hybrid/BUILD.bazel +++ b/java_src/src/test/java/com/google/crypto/tink/hybrid/BUILD.bazel @@ -385,16 +385,24 @@ java_test( "//proto:ecies_aead_hkdf_java_proto", "//proto:tink_java_proto", "//proto:xchacha20_poly1305_java_proto", + "//src/main/java/com/google/crypto/tink:insecure_secret_key_access", + "//src/main/java/com/google/crypto/tink:key", + "//src/main/java/com/google/crypto/tink:key_templates", "//src/main/java/com/google/crypto/tink:parameters", "//src/main/java/com/google/crypto/tink/aead:aead_config", "//src/main/java/com/google/crypto/tink/aead:x_cha_cha20_poly1305_parameters", "//src/main/java/com/google/crypto/tink/hybrid:ecies_parameters", "//src/main/java/com/google/crypto/tink/hybrid:ecies_proto_serialization", + "//src/main/java/com/google/crypto/tink/hybrid:ecies_public_key", + "//src/main/java/com/google/crypto/tink/internal:key_template_proto_converter", "//src/main/java/com/google/crypto/tink/internal:mutable_serialization_registry", + "//src/main/java/com/google/crypto/tink/internal:proto_key_serialization", "//src/main/java/com/google/crypto/tink/internal:proto_parameters_serialization", "//src/main/java/com/google/crypto/tink/internal:tink_bug_exception", "//src/main/java/com/google/crypto/tink/internal/testing:asserts", "//src/main/java/com/google/crypto/tink/subtle:hex", + "//src/main/java/com/google/crypto/tink/subtle:random", + "//src/main/java/com/google/crypto/tink/subtle:x25519", "//src/main/java/com/google/crypto/tink/util:bytes", "@maven//:com_google_code_findbugs_jsr305", "@maven//:com_google_protobuf_protobuf_java", diff --git a/java_src/src/test/java/com/google/crypto/tink/hybrid/EciesProtoSerializationTest.java b/java_src/src/test/java/com/google/crypto/tink/hybrid/EciesProtoSerializationTest.java index c63747de5..0028cc4af 100644 --- a/java_src/src/test/java/com/google/crypto/tink/hybrid/EciesProtoSerializationTest.java +++ b/java_src/src/test/java/com/google/crypto/tink/hybrid/EciesProtoSerializationTest.java @@ -21,27 +21,37 @@ import static com.google.crypto.tink.internal.TinkBugException.exceptionIsBug; import static com.google.crypto.tink.internal.testing.Asserts.assertEqualWhenValueParsed; import static org.junit.Assert.assertThrows; +import com.google.crypto.tink.InsecureSecretKeyAccess; +import com.google.crypto.tink.Key; +import com.google.crypto.tink.KeyTemplates; import com.google.crypto.tink.Parameters; import com.google.crypto.tink.aead.AeadConfig; import com.google.crypto.tink.aead.XChaCha20Poly1305Parameters; +import com.google.crypto.tink.internal.KeyTemplateProtoConverter; import com.google.crypto.tink.internal.MutableSerializationRegistry; +import com.google.crypto.tink.internal.ProtoKeySerialization; import com.google.crypto.tink.internal.ProtoParametersSerialization; import com.google.crypto.tink.proto.EcPointFormat; import com.google.crypto.tink.proto.EciesAeadDemParams; import com.google.crypto.tink.proto.EciesAeadHkdfKeyFormat; import com.google.crypto.tink.proto.EciesAeadHkdfParams; +import com.google.crypto.tink.proto.EciesAeadHkdfPublicKey; import com.google.crypto.tink.proto.EciesHkdfKemParams; import com.google.crypto.tink.proto.EllipticCurveType; import com.google.crypto.tink.proto.HashType; +import com.google.crypto.tink.proto.KeyData.KeyMaterialType; import com.google.crypto.tink.proto.KeyTemplate; import com.google.crypto.tink.proto.OutputPrefixType; import com.google.crypto.tink.proto.XChaCha20Poly1305KeyFormat; import com.google.crypto.tink.subtle.Hex; +import com.google.crypto.tink.subtle.Random; +import com.google.crypto.tink.subtle.X25519; import com.google.crypto.tink.util.Bytes; import com.google.protobuf.ByteString; +import java.math.BigInteger; import java.security.GeneralSecurityException; +import java.security.spec.ECPoint; import javax.annotation.Nullable; -import org.junit.BeforeClass; import org.junit.Test; import org.junit.experimental.theories.DataPoints; import org.junit.experimental.theories.FromDataPoints; @@ -118,10 +128,13 @@ public final class EciesProtoSerializationTest { .build(); } - @BeforeClass - public static void setUp() throws Exception { - AeadConfig.register(); - EciesProtoSerialization.register(registry); + static { + try { + AeadConfig.register(); + EciesProtoSerialization.register(registry); + } catch (Exception e) { + throw new RuntimeException(e); + } } @Test @@ -408,4 +421,406 @@ public final class EciesProtoSerializationTest { assertThrows( GeneralSecurityException.class, () -> registry.parseParameters(serializedParameters)); } + + // PUBLIC KEY SERIALIZATION ====================================================================== + private static EciesAeadHkdfParams validParamsForCurve(EllipticCurveType curveType) + throws GeneralSecurityException { + EciesHkdfKemParams kemParams = + EciesHkdfKemParams.newBuilder() + .setCurveType(curveType) + .setHkdfHashType(HashType.SHA256) + .setHkdfSalt(ByteString.copyFrom(SALT.toByteArray())) + .build(); + KeyTemplate demKeyTemplate = + KeyTemplateProtoConverter.toProto(KeyTemplates.get("XCHACHA20_POLY1305_RAW")); + EciesAeadDemParams demParams = + EciesAeadDemParams.newBuilder().setAeadDem(demKeyTemplate).build(); + return EciesAeadHkdfParams.newBuilder() + .setKemParams(kemParams) + .setDemParams(demParams) + .setEcPointFormat(com.google.crypto.tink.proto.EcPointFormat.COMPRESSED) + .build(); + } + + @Test + public void serializeParsePublicKey_p256_tink_equal() throws Exception { + String pointXHex = "700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287"; + String pointYHex = "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac"; + ECPoint someP256PublicPoint = + new ECPoint(new BigInteger(pointXHex, 16), new BigInteger(pointYHex, 16)); + + // Java object + EciesParameters parameters = + EciesParameters.builder() + .setCurveType(EciesParameters.CurveType.NIST_P256) + .setHashType(EciesParameters.HashType.SHA256) + .setNistCurvePointFormat(EciesParameters.PointFormat.COMPRESSED) + .setVariant(EciesParameters.Variant.TINK) + .setDemParameters(DEM_PARAMETERS) + .setSalt(SALT) + .build(); + EciesPublicKey publicKey = + EciesPublicKey.createForNistCurve(parameters, someP256PublicPoint, 101); + + // Proto object + EciesAeadHkdfPublicKey protoPublicKey = + EciesAeadHkdfPublicKey.newBuilder() + .setVersion(0) + .setParams( + validParamsForCurve(com.google.crypto.tink.proto.EllipticCurveType.NIST_P256)) + .setX(ByteString.copyFrom(Hex.decode("00" + pointXHex))) + .setY(ByteString.copyFrom(Hex.decode("00" + pointYHex))) + .build(); + ProtoKeySerialization serialization = + ProtoKeySerialization.create( + "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPublicKey", + protoPublicKey.toByteString(), + KeyMaterialType.ASYMMETRIC_PUBLIC, + OutputPrefixType.TINK, + /* idRequirement= */ 101); + + // Comparison + Key parsed = registry.parseKey(serialization, /* access= */ null); + assertThat(parsed.getParameters()).isEqualTo(publicKey.getParameters()); + assertThat(parsed.equalsKey(publicKey)).isTrue(); + + ProtoKeySerialization serialized = + registry.serializeKey(publicKey, ProtoKeySerialization.class, /* access= */ null); + + assertEqualWhenValueParsed( + com.google.crypto.tink.proto.EciesAeadHkdfPublicKey.parser(), serialized, serialization); + } + + @Test + public void serializeParsePublicKey_p256_crunchy_equal() throws Exception { + String pointXHex = "700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287"; + String pointYHex = "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac"; + ECPoint someP256PublicPoint = + new ECPoint(new BigInteger(pointXHex, 16), new BigInteger(pointYHex, 16)); + + // Java object + EciesParameters parameters = + EciesParameters.builder() + .setCurveType(EciesParameters.CurveType.NIST_P256) + .setHashType(EciesParameters.HashType.SHA256) + .setNistCurvePointFormat(EciesParameters.PointFormat.COMPRESSED) + .setVariant(EciesParameters.Variant.CRUNCHY) + .setDemParameters(DEM_PARAMETERS) + .setSalt(SALT) + .build(); + EciesPublicKey publicKey = + EciesPublicKey.createForNistCurve(parameters, someP256PublicPoint, 101); + + // Proto object + EciesAeadHkdfPublicKey protoPublicKey = + EciesAeadHkdfPublicKey.newBuilder() + .setVersion(0) + .setParams(validParamsForCurve(EllipticCurveType.NIST_P256)) + .setX(ByteString.copyFrom(Hex.decode("00" + pointXHex))) + .setY(ByteString.copyFrom(Hex.decode("00" + pointYHex))) + .build(); + ProtoKeySerialization serialization = + ProtoKeySerialization.create( + "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPublicKey", + protoPublicKey.toByteString(), + KeyMaterialType.ASYMMETRIC_PUBLIC, + OutputPrefixType.CRUNCHY, + /* idRequirement= */ 101); + + // Comparison + Key parsed = registry.parseKey(serialization, /* access= */ null); + assertThat(parsed.getParameters()).isEqualTo(publicKey.getParameters()); + assertThat(parsed.equalsKey(publicKey)).isTrue(); + + ProtoKeySerialization serialized = + registry.serializeKey(publicKey, ProtoKeySerialization.class, /* access= */ null); + + assertEqualWhenValueParsed( + com.google.crypto.tink.proto.EciesAeadHkdfPublicKey.parser(), serialized, serialization); + } + + @Test + public void serializeParsePublicKey_p384_tink_equal() throws Exception { + String pointXHex = + "a7c76b970c3b5fe8b05d2838ae04ab47697b9eaf52e764592efda27fe7513272" + + "734466b400091adbf2d68c58e0c50066"; + String pointYHex = + "ac68f19f2e1cb879aed43a9969b91a0839c4c38a49749b661efedf243451915e" + + "d0905a32b060992b468c64766fc8437a"; + + // Java object + EciesParameters parameters = + EciesParameters.builder() + .setCurveType(EciesParameters.CurveType.NIST_P384) + .setHashType(EciesParameters.HashType.SHA256) + .setNistCurvePointFormat(EciesParameters.PointFormat.COMPRESSED) + .setVariant(EciesParameters.Variant.TINK) + .setDemParameters(DEM_PARAMETERS) + .setSalt(SALT) + .build(); + EciesPublicKey publicKey = + EciesPublicKey.createForNistCurve( + parameters, + new ECPoint(new BigInteger(pointXHex, 16), new BigInteger(pointYHex, 16)), + 101); + + // Proto object + EciesAeadHkdfPublicKey protoPublicKey = + EciesAeadHkdfPublicKey.newBuilder() + .setVersion(0) + .setParams( + validParamsForCurve(com.google.crypto.tink.proto.EllipticCurveType.NIST_P384)) + .setX(ByteString.copyFrom(Hex.decode("00" + pointXHex))) + .setY(ByteString.copyFrom(Hex.decode("00" + pointYHex))) + .build(); + ProtoKeySerialization serialization = + ProtoKeySerialization.create( + "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPublicKey", + protoPublicKey.toByteString(), + KeyMaterialType.ASYMMETRIC_PUBLIC, + OutputPrefixType.TINK, + /* idRequirement= */ 101); + + // Comparison + Key parsed = registry.parseKey(serialization, /* access= */ null); + assertThat(parsed.getParameters()).isEqualTo(publicKey.getParameters()); + assertThat(parsed.equalsKey(publicKey)).isTrue(); + + ProtoKeySerialization serialized = + registry.serializeKey(publicKey, ProtoKeySerialization.class, /* access= */ null); + + assertEqualWhenValueParsed( + com.google.crypto.tink.proto.EciesAeadHkdfPublicKey.parser(), serialized, serialization); + } + + @Test + public void serializeParsePublicKey_p521_tink_equal() throws Exception { + String pointXHex = + "00685a48e86c79f0f0875f7bc18d25eb5fc8c0b07e5da4f4370f3a9490340" + + "854334b1e1b87fa395464c60626124a4e70d0f785601d37c09870ebf176666877a2" + + "046d"; + String pointYHex = + "01ba52c56fc8776d9e8f5db4f0cc27636d0b741bbe05400697942e80b7398" + + "84a83bde99e0f6716939e632bc8986fa18dccd443a348b6c3e522497955a4f3c302" + + "f676"; + ECPoint someP521PublicPoint = + new ECPoint(new BigInteger(pointXHex, 16), new BigInteger(pointYHex, 16)); + + // Java object + EciesParameters parameters = + EciesParameters.builder() + .setCurveType(EciesParameters.CurveType.NIST_P521) + .setHashType(EciesParameters.HashType.SHA256) + .setNistCurvePointFormat(EciesParameters.PointFormat.COMPRESSED) + .setVariant(EciesParameters.Variant.TINK) + .setDemParameters(DEM_PARAMETERS) + .setSalt(SALT) + .build(); + EciesPublicKey publicKey = + EciesPublicKey.createForNistCurve(parameters, someP521PublicPoint, 101); + + // Proto object + EciesAeadHkdfPublicKey protoPublicKey = + EciesAeadHkdfPublicKey.newBuilder() + .setVersion(0) + .setParams( + validParamsForCurve(com.google.crypto.tink.proto.EllipticCurveType.NIST_P521)) + .setX(ByteString.copyFrom(Hex.decode("00" + pointXHex))) + .setY(ByteString.copyFrom(Hex.decode("00" + pointYHex))) + .build(); + ProtoKeySerialization serialization = + ProtoKeySerialization.create( + "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPublicKey", + protoPublicKey.toByteString(), + KeyMaterialType.ASYMMETRIC_PUBLIC, + OutputPrefixType.TINK, + /* idRequirement= */ 101); + + // Comparison + Key parsed = registry.parseKey(serialization, /* access= */ null); + assertThat(parsed.getParameters()).isEqualTo(publicKey.getParameters()); + assertThat(parsed.equalsKey(publicKey)).isTrue(); + + ProtoKeySerialization serialized = + registry.serializeKey(publicKey, ProtoKeySerialization.class, /* access= */ null); + + assertEqualWhenValueParsed( + com.google.crypto.tink.proto.EciesAeadHkdfPublicKey.parser(), serialized, serialization); + } + + @Test + public void parsePublicKey_parsingIgnoresZeroes_works() throws Exception { + String pointXHex = + "0000000000685a48e86c79f0f0875f7bc18d25eb5fc8c0b07e5da4f4370f3a9490340" + + "854334b1e1b87fa395464c60626124a4e70d0f785601d37c09870ebf176666877a2" + + "046d"; + String pointYHex = + "0000000001ba52c56fc8776d9e8f5db4f0cc27636d0b741bbe05400697942e80b7398" + + "84a83bde99e0f6716939e632bc8986fa18dccd443a348b6c3e522497955a4f3c302" + + "f676"; + ECPoint someP521PublicPoint = + new ECPoint(new BigInteger(pointXHex, 16), new BigInteger(pointYHex, 16)); + + // Java object + EciesParameters parameters = + EciesParameters.builder() + .setCurveType(EciesParameters.CurveType.NIST_P521) + .setHashType(EciesParameters.HashType.SHA256) + .setNistCurvePointFormat(EciesParameters.PointFormat.COMPRESSED) + .setVariant(EciesParameters.Variant.TINK) + .setDemParameters(DEM_PARAMETERS) + .setSalt(SALT) + .build(); + EciesPublicKey publicKey = + EciesPublicKey.createForNistCurve(parameters, someP521PublicPoint, 101); + + // Proto object + EciesAeadHkdfPublicKey protoPublicKey = + EciesAeadHkdfPublicKey.newBuilder() + .setVersion(0) + .setParams( + validParamsForCurve(com.google.crypto.tink.proto.EllipticCurveType.NIST_P521)) + .setX(ByteString.copyFrom(Hex.decode("00" + pointXHex))) + .setY(ByteString.copyFrom(Hex.decode("00" + pointYHex))) + .build(); + ProtoKeySerialization serialization = + ProtoKeySerialization.create( + "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPublicKey", + protoPublicKey.toByteString(), + KeyMaterialType.ASYMMETRIC_PUBLIC, + OutputPrefixType.TINK, + /* idRequirement= */ 101); + + // Comparison + Key parsed = registry.parseKey(serialization, /* access= */ null); + assertThat(parsed.getParameters()).isEqualTo(publicKey.getParameters()); + assertThat(parsed.equalsKey(publicKey)).isTrue(); + } + + @Test + public void serializeParsePublicKey_x25519_equal() throws Exception { + Bytes publicPointBytes = Bytes.copyFrom(X25519.publicFromPrivate(X25519.generatePrivateKey())); + + // Java object + EciesParameters parameters = + EciesParameters.builder() + .setCurveType(EciesParameters.CurveType.X25519) + .setHashType(EciesParameters.HashType.SHA256) + .setVariant(EciesParameters.Variant.TINK) + .setDemParameters(DEM_PARAMETERS) + .setSalt(SALT) + .build(); + EciesPublicKey publicKey = + EciesPublicKey.createForCurveX25519(parameters, publicPointBytes, 101); + + // Proto object + EciesAeadHkdfPublicKey protoPublicKey = + EciesAeadHkdfPublicKey.newBuilder() + .setVersion(0) + .setParams(validParamsForCurve(EllipticCurveType.CURVE25519)) + .setX(ByteString.copyFrom(publicPointBytes.toByteArray())) + .build(); + ProtoKeySerialization serialization = + ProtoKeySerialization.create( + "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPublicKey", + protoPublicKey.toByteString(), + KeyMaterialType.ASYMMETRIC_PUBLIC, + OutputPrefixType.TINK, + /* idRequirement= */ 101); + + // Comparison + Key parsed = registry.parseKey(serialization, /* access= */ null); + assertThat(parsed.getParameters()).isEqualTo(publicKey.getParameters()); + assertThat(parsed.equalsKey(publicKey)).isTrue(); + + ProtoKeySerialization serialized = + registry.serializeKey(publicKey, ProtoKeySerialization.class, /* access= */ null); + + assertEqualWhenValueParsed( + com.google.crypto.tink.proto.EciesAeadHkdfPublicKey.parser(), serialized, serialization); + } + + private static ProtoKeySerialization[] createInvalidPublicKeySerializations() { + try { + String pointXHex = "700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287"; + String pointYHex = "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac"; + + return new ProtoKeySerialization[] { + // Point not on curve. + ProtoKeySerialization.create( + "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPublicKey", + EciesAeadHkdfPublicKey.newBuilder() + .setVersion(0) + .setParams(validParamsForCurve(EllipticCurveType.NIST_P256)) + // pointXHex + 1 + .setX( + ByteString.copyFrom( + Hex.decode( + "00700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d288"))) + .setY(ByteString.copyFrom(Hex.decode("00" + pointYHex))) + .build() + .toByteString(), + KeyMaterialType.ASYMMETRIC_PUBLIC, + OutputPrefixType.TINK, + /* idRequirement= */ 101), + // Bad version + ProtoKeySerialization.create( + "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPublicKey", + EciesAeadHkdfPublicKey.newBuilder() + .setVersion(1) + .setParams(validParamsForCurve(EllipticCurveType.NIST_P256)) + .setX(ByteString.copyFrom(Hex.decode("00" + pointXHex))) + .setY(ByteString.copyFrom(Hex.decode("00" + pointYHex))) + .build() + .toByteString(), + KeyMaterialType.ASYMMETRIC_PUBLIC, + OutputPrefixType.TINK, + /* idRequirement= */ 101), + // X25519 Curve with Y set + ProtoKeySerialization.create( + "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPublicKey", + EciesAeadHkdfPublicKey.newBuilder() + .setVersion(0) + .setParams(validParamsForCurve(EllipticCurveType.CURVE25519)) + .setX(ByteString.copyFrom(Random.randBytes(32))) + .setY(ByteString.copyFrom(Random.randBytes(32))) + .build() + .toByteString(), + KeyMaterialType.ASYMMETRIC_PUBLIC, + OutputPrefixType.TINK, + /* idRequirement= */ 101), + // X25519 Curve with EC Point Format uncompressed + ProtoKeySerialization.create( + "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPublicKey", + EciesAeadHkdfPublicKey.newBuilder() + .setVersion(0) + .setParams( + validParamsForCurve(EllipticCurveType.CURVE25519).toBuilder() + .setEcPointFormat(EcPointFormat.UNCOMPRESSED) + .build()) + .setX(ByteString.copyFrom(Random.randBytes(32))) + .build() + .toByteString(), + KeyMaterialType.ASYMMETRIC_PUBLIC, + OutputPrefixType.TINK, + /* idRequirement= */ 101), + }; + + } catch (GeneralSecurityException e) { + throw new RuntimeException(e); + } + } + + @DataPoints("invalidPublicKeySerializations") + public static final ProtoKeySerialization[] INVALID_PUBLIC_KEY_SERIALIZATIONS = + createInvalidPublicKeySerializations(); + + @Theory + public void testParseInvalidPublicKeys_throws( + @FromDataPoints("invalidPublicKeySerializations") ProtoKeySerialization serialization) + throws Exception { + assertThrows( + GeneralSecurityException.class, + () -> registry.parseKey(serialization, InsecureSecretKeyAccess.get())); + } } |