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

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

/*
 * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except
 * in compliance with the License. A copy of the License is located at
 *
 * http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file 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.amazonaws.encryptionsdk.internal;

import com.amazonaws.encryptionsdk.EncryptedDataKey;
import com.amazonaws.encryptionsdk.exception.AwsCryptoException;
import com.amazonaws.encryptionsdk.model.KeyBlob;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Map;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import org.apache.commons.lang3.ArrayUtils;

/** Abstract class for encrypting and decrypting JCE data keys. */
public abstract class JceKeyCipher {

  private final Key wrappingKey;
  private final Key unwrappingKey;
  private static final Charset KEY_NAME_ENCODING = StandardCharsets.UTF_8;

  /**
   * Returns a new instance of a JceKeyCipher based on the Advanced Encryption Standard in
   * Galois/Counter Mode.
   *
   * @param secretKey The secret key to use for encrypt/decrypt operations.
   * @return The JceKeyCipher.
   */
  public static JceKeyCipher aesGcm(SecretKey secretKey) {
    return new AesGcmJceKeyCipher(secretKey);
  }

  /**
   * Returns a new instance of a JceKeyCipher based on RSA.
   *
   * @param wrappingKey The public key to use for encrypting the key.
   * @param unwrappingKey The private key to use for decrypting the key.
   * @param transformation The transformation.
   * @return The JceKeyCipher.
   */
  public static JceKeyCipher rsa(
      PublicKey wrappingKey, PrivateKey unwrappingKey, String transformation) {
    return new RsaJceKeyCipher(wrappingKey, unwrappingKey, transformation);
  }

  JceKeyCipher(Key wrappingKey, Key unwrappingKey) {
    this.wrappingKey = wrappingKey;
    this.unwrappingKey = unwrappingKey;
  }

  abstract WrappingData buildWrappingCipher(Key key, Map encryptionContext)
      throws GeneralSecurityException;

  abstract Cipher buildUnwrappingCipher(
      Key key, byte[] extraInfo, int offset, Map encryptionContext)
      throws GeneralSecurityException;

  /**
   * Encrypts the given key, incorporating the given keyName and encryptionContext.
   *
   * @param key The key to encrypt.
   * @param keyName A UTF-8 encoded representing a name for the key.
   * @param keyNamespace A UTF-8 encoded value that namespaces the key.
   * @param encryptionContext A key-value mapping of arbitrary, non-secret, UTF-8 encoded strings
   *     used during encryption and decryption to provide additional authenticated data (AAD).
   * @return The encrypted data key.
   */
  public EncryptedDataKey encryptKey(
      final byte[] key,
      final String keyName,
      final String keyNamespace,
      final Map encryptionContext) {

    final byte[] keyNameBytes = keyName.getBytes(KEY_NAME_ENCODING);

    try {
      final JceKeyCipher.WrappingData wData = buildWrappingCipher(wrappingKey, encryptionContext);
      final Cipher cipher = wData.cipher;
      final byte[] encryptedKey = cipher.doFinal(key);

      final byte[] provInfo;
      if (wData.extraInfo.length == 0) {
        provInfo = keyNameBytes;
      } else {
        provInfo = new byte[keyNameBytes.length + wData.extraInfo.length];
        System.arraycopy(keyNameBytes, 0, provInfo, 0, keyNameBytes.length);
        System.arraycopy(wData.extraInfo, 0, provInfo, keyNameBytes.length, wData.extraInfo.length);
      }

      return new KeyBlob(keyNamespace, provInfo, encryptedKey);
    } catch (final GeneralSecurityException gsex) {
      throw new AwsCryptoException(gsex);
    }
  }

  /**
   * Decrypts the given encrypted data key.
   *
   * @param edk The encrypted data key.
   * @param keyName A UTF-8 encoded String representing a name for the key.
   * @param encryptionContext A key-value mapping of arbitrary, non-secret, UTF-8 encoded strings
   *     used during encryption and decryption to provide additional authenticated data (AAD).
   * @return The decrypted key.
   * @throws GeneralSecurityException If a problem occurred decrypting the key.
   */
  public byte[] decryptKey(
      final EncryptedDataKey edk, final String keyName, final Map encryptionContext)
      throws GeneralSecurityException {
    final byte[] keyNameBytes = keyName.getBytes(KEY_NAME_ENCODING);

    final Cipher cipher =
        buildUnwrappingCipher(
            unwrappingKey, edk.getProviderInformation(), keyNameBytes.length, encryptionContext);
    return cipher.doFinal(edk.getEncryptedDataKey());
  }

  static class WrappingData {
    public final Cipher cipher;
    public final byte[] extraInfo;

    WrappingData(final Cipher cipher, final byte[] extraInfo) {
      this.cipher = cipher;
      this.extraInfo = extraInfo != null ? extraInfo : ArrayUtils.EMPTY_BYTE_ARRAY;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy