All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.crypto.tink.hybrid.EciesPrivateKey Maven / Gradle / Ivy

// 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);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy