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

com.amazonaws.encryptionsdk.internal.CommittedKey Maven / Gradle / Ivy

// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package com.amazonaws.encryptionsdk.internal;

import com.amazonaws.encryptionsdk.CryptoAlgorithm;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.management.openmbean.InvalidKeyException;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;

public final class CommittedKey {

    private final SecretKey key_;
    private final byte[] commitment_;

    CommittedKey(SecretKey key, byte[] commitment) {
        key_ = key;
        commitment_ = commitment;
    }

    public SecretKey getKey() {
        return key_;
    }

    public byte[] getCommitment() {
        return commitment_.clone();
    }

    /**
     * The template for creating the label/info for deriving the encryption key from the data key.
     *
     * Note that this value must be cloned and modified prior to use.
     * Cloned to prevent modification of the template and threading issues.
     * Modified to insert the algorithm id into the first two bytes.
     */
    private static byte[] DERIVE_KEY_LABEL_TEMPLATE = "__DERIVEKEY".getBytes(StandardCharsets.UTF_8);

    /**
     * Full label/info for deriving the key commitment value from the data key.
     *
     * Unlike {@link #DERIVE_KEY_LABEL_TEMPLATE} this value does not need to be cloned or modified
     * prior to use.
     */
    private static byte[] COMMITKEY_LABEL = "COMMITKEY".getBytes(StandardCharsets.UTF_8);

    private static final String RAW_DATA_FORMAT = "RAW";
    private static final String HKDF_SHA_512 = "HkdfSHA512";
    private static final String HMAC_SHA_512 = "HmacSHA512";

    /**
     * Generates an encryption key along with associated commitment value.
     */
    public static CommittedKey generate(CryptoAlgorithm alg, SecretKey dataKey, byte[] nonce)
            throws InvalidKeyException {
        if (!alg.isCommitting()) {
            throw new IllegalArgumentException("Algorithm does not support key commitment.");
        }
        if (nonce.length != alg.getCommitmentNonceLength()) {
            throw new IllegalArgumentException("Invalid nonce size");
        }
        if (dataKey.getFormat() == null || !dataKey.getFormat().equalsIgnoreCase(RAW_DATA_FORMAT)) {
            throw new IllegalArgumentException(
                    "Currently only RAW format keys are supported for HKDF algorithms. Actual format was "
                            + dataKey.getFormat());
        }
        if (dataKey.getAlgorithm() == null || !dataKey.getAlgorithm().equalsIgnoreCase(alg.getDataKeyAlgo())) {
            throw new IllegalArgumentException("DataKey of incorrect algorithm. Expected " + alg.getDataKeyAlgo() + " but was "
                    + dataKey.getAlgorithm());
        }
        final byte[] rawDataKey = dataKey.getEncoded();
        if (rawDataKey.length != alg.getDataKeyLength()) {
            throw new IllegalArgumentException("DataKey of incorrect length. Expected " + alg.getDataKeyLength() + " but was "
                    + rawDataKey.length);
        }

        final String macAlgorithm;
        switch (alg.getKeyCommitmentAlgo_()) {
            case HKDF_SHA_512:
                macAlgorithm = HMAC_SHA_512;
                break;
            default:
                throw new UnsupportedOperationException("Support for commitment with " + alg.getKeyCommitmentAlgo_() + " not yet built.");
        }

        HmacKeyDerivationFunction kdf = null;
        try {
            kdf = HmacKeyDerivationFunction.getInstance(macAlgorithm);
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalStateException(e);
        }
        kdf.init(rawDataKey, nonce);

        final byte[] commitment = kdf.deriveKey(COMMITKEY_LABEL, alg.getCommitmentLength());

        // Clone to prevent modification of the master copy
        final byte[] deriveKeyLabel = DERIVE_KEY_LABEL_TEMPLATE.clone();
        final short algId = alg.getValue();
        deriveKeyLabel[0] = (byte) ((algId >> 8) & 0xFF);
        deriveKeyLabel[1] = (byte) (algId & 0xFF);
        SecretKey ek = new SecretKeySpec(kdf.deriveKey(deriveKeyLabel, alg.getKeyLength()), alg.getKeyAlgo());

        return new CommittedKey(ek, commitment);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy