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

com.google.crypto.tink.hybrid.internal.HpkeUtil Maven / Gradle / Ivy

// Copyright 2021 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.internal;

import static com.google.crypto.tink.internal.Util.UTF_8;

import com.google.crypto.tink.hybrid.HpkeParameters;
import com.google.crypto.tink.subtle.Bytes;
import com.google.crypto.tink.subtle.EllipticCurves;
import java.security.GeneralSecurityException;

/** Collection of helper functions for HPKE. */
public final class HpkeUtil {
  // HPKE mode identifiers.
  public static final byte[] BASE_MODE = intToByteArray(1, 0x0);
  public static final byte[] AUTH_MODE = intToByteArray(1, 0x2);

  // HPKE KEM algorithm identifiers.
  public static final byte[] X25519_HKDF_SHA256_KEM_ID = intToByteArray(2, 0x20);
  public static final byte[] P256_HKDF_SHA256_KEM_ID = intToByteArray(2, 0x10);
  public static final byte[] P384_HKDF_SHA384_KEM_ID = intToByteArray(2, 0x11);
  public static final byte[] P521_HKDF_SHA512_KEM_ID = intToByteArray(2, 0x12);

  // HPKE KDF algorithm identifiers.
  public static final byte[] HKDF_SHA256_KDF_ID = intToByteArray(2, 0x1);
  public static final byte[] HKDF_SHA384_KDF_ID = intToByteArray(2, 0x2);
  public static final byte[] HKDF_SHA512_KDF_ID = intToByteArray(2, 0x3);

  // HPKE AEAD algorithm identifiers.
  public static final byte[] AES_128_GCM_AEAD_ID = intToByteArray(2, 0x1);
  public static final byte[] AES_256_GCM_AEAD_ID = intToByteArray(2, 0x2);
  public static final byte[] CHACHA20_POLY1305_AEAD_ID = intToByteArray(2, 0x3);

  public static final byte[] EMPTY_SALT = new byte[0];

  private static final byte[] KEM = "KEM".getBytes(UTF_8);
  private static final byte[] HPKE = "HPKE".getBytes(UTF_8);
  private static final byte[] HPKE_V1 = "HPKE-v1".getBytes(UTF_8);

  /**
   * Transforms a passed value to an MSB first byte array with the size of the specified capacity.
   * (i.e., {@link com.google.crypto.tink.subtle.Bytes#intToByteArray(int, int)} with MSB first
   * instead of LSB first).
   *
   * 

The HPKE standard defines this function as I2OSP(n, w) where w = capacity and n = value. * *

https://www.rfc-editor.org/rfc/rfc9180.html#name-notation * * @param capacity size of the resulting byte array * @param value that should be represented as a byte array */ public static byte[] intToByteArray(int capacity, int value) { if ((capacity > 4) || (capacity < 0)) { throw new IllegalArgumentException("capacity must be between 0 and 4"); } // Check that 0 <= value < 256^capacity. // For capacity == 4, all positive values are valid. if (value < 0 || (capacity < 4 && (value >= 1 << (8 * capacity)))) { throw new IllegalArgumentException("value too large"); } final byte[] result = new byte[capacity]; for (int i = 0; i < capacity; i++) { result[i] = (byte) ((value >> (8 * (capacity - i - 1))) & 0xFF); } return result; } /** * Generates KEM suite id from {@code kemId} according to the definition in * https://www.rfc-editor.org/rfc/rfc9180.html#section-4.1-5. Only used for KEM suite id. * * @throws GeneralSecurityException when byte concatenation fails. */ static byte[] kemSuiteId(byte[] kemId) throws GeneralSecurityException { return Bytes.concat(KEM, kemId); } /** * Generates HPKE suite id from {@code kemId}, {@code kdfId}, and {@code aeadId} according to the * definition in https://www.rfc-editor.org/rfc/rfc9180.html#section-5.1-8. Used for any non-KEM * suite id. * * @throws GeneralSecurityException when byte concatenation fails. */ static byte[] hpkeSuiteId(byte[] kemId, byte[] kdfId, byte[] aeadId) throws GeneralSecurityException { return Bytes.concat(HPKE, kemId, kdfId, aeadId); } /** * Transforms {@code ikm} into labeled ikm using {@code label} and {@code suiteId} according to * {@code LabeledExtract()} defined in https://www.rfc-editor.org/rfc/rfc9180.html#section-4. * * @throws GeneralSecurityException when byte concatenation fails. */ static byte[] labelIkm(String label, byte[] ikm, byte[] suiteId) throws GeneralSecurityException { return Bytes.concat(HPKE_V1, suiteId, label.getBytes(UTF_8), ikm); } /** * Transforms {@code info} into labeled info using {@code label}, {@code suiteId}, and {@code * length} according to {@code LabeledExpand()} defined in * https://www.rfc-editor.org/rfc/rfc9180.html#section-4. * * @throws GeneralSecurityException when byte concatenation fails. */ static byte[] labelInfo(String label, byte[] info, byte[] suiteId, int length) throws GeneralSecurityException { return Bytes.concat(intToByteArray(2, length), HPKE_V1, suiteId, label.getBytes(UTF_8), info); } static EllipticCurves.CurveType nistHpkeKemToCurve(HpkeParameters.KemId kemId) throws GeneralSecurityException { if (kemId == HpkeParameters.KemId.DHKEM_P256_HKDF_SHA256) { return EllipticCurves.CurveType.NIST_P256; } if (kemId == HpkeParameters.KemId.DHKEM_P384_HKDF_SHA384) { return EllipticCurves.CurveType.NIST_P384; } if (kemId == HpkeParameters.KemId.DHKEM_P521_HKDF_SHA512) { return EllipticCurves.CurveType.NIST_P521; } throw new GeneralSecurityException("Unrecognized NIST HPKE KEM identifier"); } /** Lengths from 'Npk' column in https://www.rfc-editor.org/rfc/rfc9180.html#table-2. */ public static int getEncodedPublicKeyLength(HpkeParameters.KemId kemId) throws GeneralSecurityException { if (kemId == HpkeParameters.KemId.DHKEM_X25519_HKDF_SHA256) { return 32; } if (kemId == HpkeParameters.KemId.DHKEM_P256_HKDF_SHA256) { return 65; } if (kemId == HpkeParameters.KemId.DHKEM_P384_HKDF_SHA384) { return 97; } if (kemId == HpkeParameters.KemId.DHKEM_P521_HKDF_SHA512) { return 133; } throw new GeneralSecurityException("Unrecognized HPKE KEM identifier"); } /** * Returns the encapsulated key length (in bytes) for the specified {@code kemId}. This value * corresponds to the 'Nenc' column in the following table. * *

https://www.rfc-editor.org/rfc/rfc9180.html#name-key-encapsulation-mechanism. */ public static int encodingSizeInBytes(HpkeParameters.KemId kemId) { if (kemId == HpkeParameters.KemId.DHKEM_X25519_HKDF_SHA256) { return 32; } if (kemId == HpkeParameters.KemId.DHKEM_P256_HKDF_SHA256) { return 65; } if (kemId == HpkeParameters.KemId.DHKEM_P384_HKDF_SHA384) { return 97; } if (kemId == HpkeParameters.KemId.DHKEM_P521_HKDF_SHA512) { return 133; } throw new IllegalArgumentException("Unable to determine KEM-encoding length for " + kemId); } /** Lengths from 'Nsk' column in https://www.rfc-editor.org/rfc/rfc9180.html#table-2. */ public static int getEncodedPrivateKeyLength(HpkeParameters.KemId kemId) throws GeneralSecurityException { if (kemId == HpkeParameters.KemId.DHKEM_X25519_HKDF_SHA256) { return 32; } if (kemId == HpkeParameters.KemId.DHKEM_P256_HKDF_SHA256) { return 32; } if (kemId == HpkeParameters.KemId.DHKEM_P384_HKDF_SHA384) { return 48; } if (kemId == HpkeParameters.KemId.DHKEM_P521_HKDF_SHA512) { return 66; } throw new GeneralSecurityException("Unrecognized HPKE KEM identifier"); } private HpkeUtil() {} }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy