aboutsummaryrefslogtreecommitdiff
path: root/java_src/src/main/java/com/google/crypto/tink/hybrid/EciesPrivateKey.java
diff options
context:
space:
mode:
authorioannanedelcu <ioannanedelcu@google.com>2023-08-04 06:00:09 -0700
committerCopybara-Service <copybara-worker@google.com>2023-08-04 06:01:06 -0700
commit8e991c57cecf6794b774e32ce531a80fe6ad3110 (patch)
tree1fecf8960b845ee332b0ab6bec9f7c00d180b466 /java_src/src/main/java/com/google/crypto/tink/hybrid/EciesPrivateKey.java
parent4fa7e0322848bcf34eb200510da0619ae0b3636b (diff)
downloadtink-8e991c57cecf6794b774e32ce531a80fe6ad3110.tar.gz
Add EciesPrivateKey class in Java
PiperOrigin-RevId: 553782644
Diffstat (limited to 'java_src/src/main/java/com/google/crypto/tink/hybrid/EciesPrivateKey.java')
-rw-r--r--java_src/src/main/java/com/google/crypto/tink/hybrid/EciesPrivateKey.java204
1 files changed, 204 insertions, 0 deletions
diff --git a/java_src/src/main/java/com/google/crypto/tink/hybrid/EciesPrivateKey.java b/java_src/src/main/java/com/google/crypto/tink/hybrid/EciesPrivateKey.java
new file mode 100644
index 000000000..ca199f847
--- /dev/null
+++ b/java_src/src/main/java/com/google/crypto/tink/hybrid/EciesPrivateKey.java
@@ -0,0 +1,204 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.google.crypto.tink.hybrid;
+
+import com.google.crypto.tink.AccessesPartialKey;
+import com.google.crypto.tink.InsecureSecretKeyAccess;
+import com.google.crypto.tink.Key;
+import com.google.crypto.tink.internal.EllipticCurvesUtil;
+import com.google.crypto.tink.subtle.EllipticCurves;
+import com.google.crypto.tink.subtle.X25519;
+import com.google.crypto.tink.util.SecretBigInteger;
+import com.google.crypto.tink.util.SecretBytes;
+import com.google.errorprone.annotations.Immutable;
+import com.google.errorprone.annotations.RestrictedApi;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.util.Arrays;
+import javax.annotation.Nullable;
+
+/** Representation of the decryption function for an ECIES hybrid encryption primitive. */
+@Immutable
+public final class EciesPrivateKey extends HybridPrivateKey {
+ private final EciesPublicKey publicKey;
+
+ /** Exactly one of nistPrivateKeyValue and x25519PrivateKeyBytes is non-null. */
+ @Nullable private final SecretBigInteger nistPrivateKeyValue;
+
+ @Nullable private final SecretBytes x25519PrivateKeyBytes;
+
+ private EciesPrivateKey(
+ EciesPublicKey publicKey,
+ @Nullable SecretBigInteger nistPrivateKeyValue,
+ @Nullable SecretBytes x25519PrivateKeyBytes) {
+ this.publicKey = publicKey;
+ this.nistPrivateKeyValue = nistPrivateKeyValue;
+ this.x25519PrivateKeyBytes = x25519PrivateKeyBytes;
+ }
+
+ private static ECParameterSpec toParameterSpecNistCurve(EciesParameters.CurveType curveType) {
+ if (curveType == EciesParameters.CurveType.NIST_P256) {
+ return EllipticCurves.getNistP256Params();
+ }
+ if (curveType == EciesParameters.CurveType.NIST_P384) {
+ return EllipticCurves.getNistP384Params();
+ }
+ if (curveType == EciesParameters.CurveType.NIST_P521) {
+ return EllipticCurves.getNistP521Params();
+ }
+ throw new IllegalArgumentException("Unable to determine NIST curve type for " + curveType);
+ }
+
+ private static void validateNistPrivateKeyValue(
+ BigInteger privateValue, ECPoint publicPoint, EciesParameters.CurveType curveType)
+ throws GeneralSecurityException {
+ BigInteger order = toParameterSpecNistCurve(curveType).getOrder();
+ if ((privateValue.signum() <= 0) || (privateValue.compareTo(order) >= 0)) {
+ throw new GeneralSecurityException("Invalid private value");
+ }
+ ECPoint p =
+ EllipticCurvesUtil.multiplyByGenerator(privateValue, toParameterSpecNistCurve(curveType));
+ if (!p.equals(publicPoint)) {
+ throw new GeneralSecurityException("Invalid private value");
+ }
+ }
+
+ private static void validateX25519PrivateKeyBytes(byte[] privateKeyBytes, byte[] publicKeyBytes)
+ throws GeneralSecurityException {
+ if (privateKeyBytes.length != 32) {
+ throw new GeneralSecurityException("Private key bytes length for X25519 curve must be 32");
+ }
+ byte[] expectedPublicKeyBytes = X25519.publicFromPrivate(privateKeyBytes);
+ if (!Arrays.equals(expectedPublicKeyBytes, publicKeyBytes)) {
+ throw new GeneralSecurityException("Invalid private key for public key.");
+ }
+ }
+
+ /**
+ * Creates a new ECIES private key using Curve25519.
+ *
+ * @param publicKey Corresponding ECIES public key for this private key
+ * @param x25519PrivateKeyBytes private key bytes
+ */
+ @AccessesPartialKey
+ @RestrictedApi(
+ explanation = "Accessing parts of keys can produce unexpected incompatibilities, annotate the function with @AccessesPartialKey",
+ link = "https://developers.google.com/tink/design/access_control#accessing_partial_keys",
+ allowedOnPath = ".*Test\\.java",
+ allowlistAnnotations = {AccessesPartialKey.class})
+ public static EciesPrivateKey createForCurveX25519(
+ EciesPublicKey publicKey, SecretBytes x25519PrivateKeyBytes) throws GeneralSecurityException {
+ if (publicKey == null) {
+ throw new GeneralSecurityException(
+ "ECIES private key cannot be constructed without an ECIES public key");
+ }
+ if (publicKey.getX25519CurvePointBytes() == null) {
+ throw new GeneralSecurityException(
+ "ECIES private key for X25519 curve cannot be constructed with NIST-curve public key");
+ }
+ if (x25519PrivateKeyBytes == null) {
+ throw new GeneralSecurityException("ECIES private key cannot be constructed without secret");
+ }
+ validateX25519PrivateKeyBytes(
+ x25519PrivateKeyBytes.toByteArray(InsecureSecretKeyAccess.get()),
+ publicKey.getX25519CurvePointBytes().toByteArray());
+
+ return new EciesPrivateKey(publicKey, null, x25519PrivateKeyBytes);
+ }
+
+ /**
+ * Creates a new ECIES private key using NIST Curves.
+ *
+ * @param publicKey Corresponding ECIES public key for this private key
+ * @param nistPrivateKeyValue private big integer value in bigendian representation
+ */
+ @AccessesPartialKey
+ @RestrictedApi(
+ explanation = "Accessing parts of keys can produce unexpected incompatibilities, annotate the function with @AccessesPartialKey",
+ link = "https://developers.google.com/tink/design/access_control#accessing_partial_keys",
+ allowedOnPath = ".*Test\\.java",
+ allowlistAnnotations = {AccessesPartialKey.class})
+ public static EciesPrivateKey createForNistCurve(
+ EciesPublicKey publicKey, SecretBigInteger nistPrivateKeyValue)
+ throws GeneralSecurityException {
+ if (publicKey == null) {
+ throw new GeneralSecurityException(
+ "ECIES private key cannot be constructed without an ECIES public key");
+ }
+ if (publicKey.getNistCurvePoint() == null) {
+ throw new GeneralSecurityException(
+ "ECIES private key for NIST curve cannot be constructed with X25519-curve public key");
+ }
+ if (nistPrivateKeyValue == null) {
+ throw new GeneralSecurityException("ECIES private key cannot be constructed without secret");
+ }
+ validateNistPrivateKeyValue(
+ nistPrivateKeyValue.getBigInteger(InsecureSecretKeyAccess.get()),
+ publicKey.getNistCurvePoint(),
+ publicKey.getParameters().getCurveType());
+
+ return new EciesPrivateKey(publicKey, nistPrivateKeyValue, null);
+ }
+
+ @RestrictedApi(
+ explanation = "Accessing parts of keys can produce unexpected incompatibilities, annotate the function with @AccessesPartialKey",
+ link = "https://developers.google.com/tink/design/access_control#accessing_partial_keys",
+ allowedOnPath = ".*Test\\.java",
+ allowlistAnnotations = {AccessesPartialKey.class})
+ @Nullable
+ public SecretBytes getX25519PrivateKeyBytes() {
+ return x25519PrivateKeyBytes;
+ }
+
+ @RestrictedApi(
+ explanation = "Accessing parts of keys can produce unexpected incompatibilities, annotate the function with @AccessesPartialKey",
+ link = "https://developers.google.com/tink/design/access_control#accessing_partial_keys",
+ allowedOnPath = ".*Test\\.java",
+ allowlistAnnotations = {AccessesPartialKey.class})
+ @Nullable
+ public SecretBigInteger getNistPrivateKeyValue() {
+ return nistPrivateKeyValue;
+ }
+
+ @Override
+ public EciesParameters getParameters() {
+ return publicKey.getParameters();
+ }
+
+ @Override
+ public EciesPublicKey getPublicKey() {
+ return publicKey;
+ }
+
+ @Override
+ public boolean equalsKey(Key o) {
+ if (!(o instanceof EciesPrivateKey)) {
+ return false;
+ }
+ EciesPrivateKey other = (EciesPrivateKey) o;
+ if (!publicKey.equalsKey(other.publicKey)) {
+ return false;
+ }
+ if (x25519PrivateKeyBytes == null && other.x25519PrivateKeyBytes == null) {
+ return nistPrivateKeyValue.equalsSecretBigInteger(other.nistPrivateKeyValue);
+ }
+
+ return x25519PrivateKeyBytes.equalsSecretBytes(other.x25519PrivateKeyBytes);
+ }
+}