Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2016 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.jce;
import com.amazonaws.encryptionsdk.CryptoAlgorithm;
import com.amazonaws.encryptionsdk.DataKey;
import com.amazonaws.encryptionsdk.EncryptedDataKey;
import com.amazonaws.encryptionsdk.MasterKey;
import com.amazonaws.encryptionsdk.exception.AwsCryptoException;
import com.amazonaws.encryptionsdk.exception.UnsupportedProviderException;
import com.amazonaws.encryptionsdk.internal.JceKeyCipher;
import com.amazonaws.encryptionsdk.internal.Utils;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
/**
* Represents a {@link MasterKey} backed by one (or more) JCE {@link Key}s. Instances of this should
* only be acquired using {@link #getInstance(SecretKey, String, String, String)} or {@link
* #getInstance(PublicKey, PrivateKey, String, String, String)}.
*/
public class JceMasterKey extends MasterKey {
private final String providerName_;
private final String keyId_;
private final byte[] keyIdBytes_;
private final JceKeyCipher jceKeyCipher_;
/**
* Returns a {@code JceMasterKey} backed by {@code key} using {@code wrappingAlgorithm}. Currently
* "{@code AES/GCM/NoPadding}" is the only supported value for {@code wrappingAlgorithm}.
*
* @param key key used to wrap/unwrap (encrypt/decrypt) {@link DataKey}s
* @param provider
* @param keyId
* @param wrappingAlgorithm
* @return
*/
public static JceMasterKey getInstance(
final SecretKey key,
final String provider,
final String keyId,
final String wrappingAlgorithm) {
switch (wrappingAlgorithm.toUpperCase()) {
case "AES/GCM/NOPADDING":
return new JceMasterKey(provider, keyId, JceKeyCipher.aesGcm(key));
default:
throw new IllegalArgumentException("Right now only AES/GCM/NoPadding is supported");
}
}
/**
* Returns a {@code JceMasterKey} backed by {@code unwrappingKey} and {@code wrappingKey} using
* {@code wrappingAlgorithm}. Currently only RSA algorithms are supported for {@code
* wrappingAlgorithm}. {@code wrappingAlgorithm}. If {@code unwrappingKey} is {@code null} then
* the returned {@link JceMasterKey} can only be used for encryption.
*
* @param wrappingKey key used to wrap (encrypt) {@link DataKey}s
* @param unwrappingKey (Optional) key used to unwrap (decrypt) {@link DataKey}s.
*/
public static JceMasterKey getInstance(
final PublicKey wrappingKey,
final PrivateKey unwrappingKey,
final String provider,
final String keyId,
final String wrappingAlgorithm) {
if (wrappingAlgorithm.toUpperCase().startsWith("RSA/ECB/")) {
return new JceMasterKey(
provider, keyId, JceKeyCipher.rsa(wrappingKey, unwrappingKey, wrappingAlgorithm));
}
throw new UnsupportedOperationException(
"Currently only RSA asymmetric algorithms are supported");
}
protected JceMasterKey(
final String providerName, final String keyId, final JceKeyCipher jceKeyCipher) {
providerName_ = providerName;
keyId_ = keyId;
keyIdBytes_ = keyId_.getBytes(StandardCharsets.UTF_8);
jceKeyCipher_ = jceKeyCipher;
}
@Override
public String getProviderId() {
return providerName_;
}
@Override
public String getKeyId() {
return keyId_;
}
@Override
public DataKey generateDataKey(
final CryptoAlgorithm algorithm, final Map encryptionContext) {
final byte[] rawKey = new byte[algorithm.getDataKeyLength()];
Utils.getSecureRandom().nextBytes(rawKey);
EncryptedDataKey encryptedDataKey =
jceKeyCipher_.encryptKey(rawKey, keyId_, providerName_, encryptionContext);
return new DataKey<>(
new SecretKeySpec(rawKey, algorithm.getDataKeyAlgo()),
encryptedDataKey.getEncryptedDataKey(),
encryptedDataKey.getProviderInformation(),
this);
}
@Override
public DataKey encryptDataKey(
final CryptoAlgorithm algorithm,
final Map encryptionContext,
final DataKey> dataKey) {
final SecretKey key = dataKey.getKey();
if (!key.getFormat().equals("RAW")) {
throw new IllegalArgumentException(
"Can only re-encrypt data keys which are in RAW format, not "
+ dataKey.getKey().getFormat());
}
if (!key.getAlgorithm().equalsIgnoreCase(algorithm.getDataKeyAlgo())) {
throw new IllegalArgumentException(
"Incorrect key algorithm. Expected "
+ key.getAlgorithm()
+ " but got "
+ algorithm.getKeyAlgo());
}
EncryptedDataKey encryptedDataKey =
jceKeyCipher_.encryptKey(key.getEncoded(), keyId_, providerName_, encryptionContext);
return new DataKey<>(
key,
encryptedDataKey.getEncryptedDataKey(),
encryptedDataKey.getProviderInformation(),
this);
}
@Override
public DataKey decryptDataKey(
final CryptoAlgorithm algorithm,
final Collection extends EncryptedDataKey> encryptedDataKeys,
final Map encryptionContext)
throws UnsupportedProviderException, AwsCryptoException {
final List exceptions = new ArrayList<>();
// Find an encrypted key who's provider and info match us
for (final EncryptedDataKey edk : encryptedDataKeys) {
try {
if (edk.getProviderId().equals(getProviderId())
&& Utils.arrayPrefixEquals(
edk.getProviderInformation(), keyIdBytes_, keyIdBytes_.length)) {
final byte[] decryptedKey = jceKeyCipher_.decryptKey(edk, keyId_, encryptionContext);
// Validate that the decrypted key length is as expected
if (decryptedKey.length == algorithm.getDataKeyLength()) {
return new DataKey<>(
new SecretKeySpec(decryptedKey, algorithm.getDataKeyAlgo()),
edk.getEncryptedDataKey(),
edk.getProviderInformation(),
this);
}
}
} catch (final Exception ex) {
exceptions.add(ex);
}
}
throw buildCannotDecryptDksException(exceptions);
}
}