/** * Uses AES/GCM with AESWrap key wrapping to encrypt the key. Uses v2 metadata schema. Note that authenticated * encryption requires the bouncy castle provider to be on the classpath. Also, for authenticated encryption the size * of the data can be no longer than 64 GB. */ public void authenticatedEncryption_CustomerManagedKey() throws NoSuchAlgorithmException { SecretKey secretKey = KeyGenerator.getInstance("AES").generateKey(); AmazonS3Encryption s3Encryption = AmazonS3EncryptionClientBuilder .standard() .withRegion(Regions.US_WEST_2) .withCryptoConfiguration(new CryptoConfiguration(CryptoMode.AuthenticatedEncryption)) .withEncryptionMaterials(new StaticEncryptionMaterialsProvider(new EncryptionMaterials(secretKey))) .build(); AmazonS3 s3NonEncrypt = AmazonS3ClientBuilder.defaultClient(); s3Encryption.putObject(BUCKET_NAME, ENCRYPTED_KEY, "some contents"); s3NonEncrypt.putObject(BUCKET_NAME, NON_ENCRYPTED_KEY, "some other contents"); System.out.println(s3Encryption.getObjectAsString(BUCKET_NAME, ENCRYPTED_KEY)); System.out.println(s3Encryption.getObjectAsString(BUCKET_NAME, NON_ENCRYPTED_KEY)); }
/** * For ranged GET we do not use authenticated encryption since we aren't reading the entire message and can't produce the * MAC. Instead we use AES/CTR, an unauthenticated encryption algorithm. If {@link CryptoMode#StrictAuthenticatedEncryption} * is enabled, ranged GETs will not be allowed since they do not use authenticated encryption.. */ public void authenticatedEncryption_RangeGet_CustomerManagedKey() throws NoSuchAlgorithmException { SecretKey secretKey = KeyGenerator.getInstance("AES").generateKey(); AmazonS3Encryption s3Encryption = AmazonS3EncryptionClientBuilder .standard() .withRegion(Regions.US_WEST_2) .withCryptoConfiguration(new CryptoConfiguration(CryptoMode.AuthenticatedEncryption)) .withEncryptionMaterials(new StaticEncryptionMaterialsProvider(new EncryptionMaterials(secretKey))) .build(); AmazonS3 s3NonEncrypt = AmazonS3ClientBuilder.defaultClient(); s3Encryption.putObject(BUCKET_NAME, ENCRYPTED_KEY, "some contents"); s3NonEncrypt.putObject(BUCKET_NAME, NON_ENCRYPTED_KEY, "some other contents"); System.out.println(s3Encryption.getObjectAsString(BUCKET_NAME, ENCRYPTED_KEY)); System.out.println(s3Encryption.getObjectAsString(BUCKET_NAME, NON_ENCRYPTED_KEY)); }
/** * Same as {@link #authenticatedEncryption_CustomerManagedKey()} except uses an asymmetric key pair and * RSA/ECB/OAEPWithSHA-256AndMGF1Padding as the key wrapping algorithm. */ public void authenticatedEncryption_CustomerManagedAsymmetricKey() throws NoSuchAlgorithmException { KeyPair keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair(); AmazonS3Encryption s3Encryption = AmazonS3EncryptionClientBuilder .standard() .withRegion(Regions.US_WEST_2) .withCryptoConfiguration(new CryptoConfiguration(CryptoMode.AuthenticatedEncryption)) .withEncryptionMaterials(new StaticEncryptionMaterialsProvider(new EncryptionMaterials(keyPair))) .build(); AmazonS3 s3NonEncrypt = AmazonS3ClientBuilder.defaultClient(); s3Encryption.putObject(BUCKET_NAME, ENCRYPTED_KEY, "some contents"); s3NonEncrypt.putObject(BUCKET_NAME, NON_ENCRYPTED_KEY, "some other contents"); System.out.println(s3Encryption.getObjectAsString(BUCKET_NAME, ENCRYPTED_KEY)); System.out.println(s3Encryption.getObjectAsString(BUCKET_NAME, NON_ENCRYPTED_KEY)); }
/** * Uses AES/GCM with AESWrap key wrapping to encrypt the key. Uses v2 metadata schema. The only difference between this and * {@link #authenticatedEncryption_CustomerManagedKey()} is that attempting to retrieve an object non * encrypted with AES/GCM will thrown an exception instead of falling back to encryption only or plaintext GET. */ public void strictAuthenticatedEncryption_CustomerManagedKey() throws NoSuchAlgorithmException { SecretKey secretKey = KeyGenerator.getInstance("AES").generateKey(); AmazonS3Encryption s3Encryption = AmazonS3EncryptionClientBuilder .standard() .withRegion(Regions.US_WEST_2) .withCryptoConfiguration(new CryptoConfiguration(CryptoMode.StrictAuthenticatedEncryption)) .withEncryptionMaterials(new StaticEncryptionMaterialsProvider(new EncryptionMaterials(secretKey))) .build(); AmazonS3 s3NonEncrypt = AmazonS3ClientBuilder.defaultClient(); s3Encryption.putObject(BUCKET_NAME, ENCRYPTED_KEY, "some contents"); s3NonEncrypt.putObject(BUCKET_NAME, NON_ENCRYPTED_KEY, "some other contents"); System.out.println(s3Encryption.getObjectAsString(BUCKET_NAME, ENCRYPTED_KEY)); try { s3Encryption.getObjectAsString(BUCKET_NAME, NON_ENCRYPTED_KEY); } catch (SecurityException e) { // Strict authenticated encryption will throw an exception if an object is not encrypted with AES/GCM System.err.println(NON_ENCRYPTED_KEY + " was not encrypted with AES/GCM"); } }
/** * Strict authenticated encryption mode does not support ranged GETs. This is because we must use AES/CTR for ranged * GETs which is not an authenticated encryption algorithm. To do a partial get using authenticated encryption you have to * get the whole object and filter to the data you want. */ public void strictAuthenticatedEncryption_RangeGet_CustomerManagedKey() throws NoSuchAlgorithmException { SecretKey secretKey = KeyGenerator.getInstance("AES").generateKey(); AmazonS3Encryption s3Encryption = AmazonS3EncryptionClientBuilder .standard() .withRegion(Regions.US_WEST_2) .withCryptoConfiguration(new CryptoConfiguration(CryptoMode.StrictAuthenticatedEncryption)) .withEncryptionMaterials(new StaticEncryptionMaterialsProvider(new EncryptionMaterials(secretKey))) .build(); s3Encryption.putObject(BUCKET_NAME, ENCRYPTED_KEY, "some contents"); try { s3Encryption.getObject(new GetObjectRequest(BUCKET_NAME, ENCRYPTED_KEY).withRange(0, 2)); } catch (SecurityException e) { System.err.println("Range GET is not supported with authenticated encryption"); } }
/** * Uses AES/CBC algorithm, no key wrapping. */ public void encryptionOnly_CustomerManagedKey() throws NoSuchAlgorithmException { SecretKey secretKey = KeyGenerator.getInstance("AES").generateKey(); AmazonS3Encryption s3Encryption = AmazonS3EncryptionClientBuilder .standard() .withRegion(Regions.US_WEST_2) .withCryptoConfiguration(new CryptoConfiguration(CryptoMode.EncryptionOnly)) .withEncryptionMaterials(new StaticEncryptionMaterialsProvider(new EncryptionMaterials(secretKey))) .build(); AmazonS3 s3NonEncrypt = AmazonS3ClientBuilder.defaultClient(); s3Encryption.putObject(BUCKET_NAME, ENCRYPTED_KEY, "some contents"); s3NonEncrypt.putObject(BUCKET_NAME, NON_ENCRYPTED_KEY, "some other contents"); System.out.println(s3Encryption.getObjectAsString(BUCKET_NAME, ENCRYPTED_KEY)); System.out.println(s3Encryption.getObjectAsString(BUCKET_NAME, NON_ENCRYPTED_KEY)); }
/** * Uses an asymmetric key pair instead of a symmetric key. Note this does not change the algorithm used to encrypt * the content, that will still be a symmetric key algorithm (AES/CBC in this case) using the derived CEK. It does impact * the algorithm used to encrypt the CEK, in this case we use RSA/ECB/OAEPWithSHA-256AndMGF1Padding. */ public void encryptionOnly_CustomerManagedAsymetricKey() throws NoSuchAlgorithmException { KeyPair keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair(); AmazonS3Encryption s3Encryption = AmazonS3EncryptionClientBuilder .standard() .withRegion(Regions.US_WEST_2) .withCryptoConfiguration(new CryptoConfiguration(CryptoMode.EncryptionOnly)) .withEncryptionMaterials(new StaticEncryptionMaterialsProvider(new EncryptionMaterials(keyPair))) .build(); AmazonS3 s3NonEncrypt = AmazonS3ClientBuilder.defaultClient(); s3Encryption.putObject(BUCKET_NAME, ENCRYPTED_KEY, "some contents"); s3NonEncrypt.putObject(BUCKET_NAME, NON_ENCRYPTED_KEY, "some other contents"); System.out.println(s3Encryption.getObjectAsString(BUCKET_NAME, ENCRYPTED_KEY)); System.out.println(s3Encryption.getObjectAsString(BUCKET_NAME, NON_ENCRYPTED_KEY)); }
/** * Decrypts the secured CEK via KMS; involves network calls. * * @return the CEK (in plaintext). */ private static SecretKey cekByKMS(byte[] cekSecured, String keyWrapAlgo, EncryptionMaterials materials, ContentCryptoScheme contentCryptoScheme, AWSKMS kms) { DecryptRequest kmsreq = new DecryptRequest() .withEncryptionContext(materials.getMaterialsDescription()) .withCiphertextBlob(ByteBuffer.wrap(cekSecured)); DecryptResult result = kms.decrypt(kmsreq); return new SecretKeySpec(copyAllBytesFrom(result.getPlaintext()), contentCryptoScheme.getKeyGeneratorAlgorithm()); }
/** * Recreates a new content crypto material from the current material given a * new KEK material-descriptions. The purpose is to re-encrypt the CEK under * a different KEK. * * Note network calls are involved if the CEK has been or is to be protected * by KMS. * * @param newKEKMatDesc * material descriptions for the new KEK; never null * @param accessor * used to retrieve the KEK given the corresponding material * description * @param targetScheme * the target crypto scheme to be used for key wrapping, etc. * @param p * optional security provider; null means to use the default. * @throws SecurityException * if the old and new material description are the same; or if * the old and new KEK are the same */ ContentCryptoMaterial recreate(Map<String, String> newKEKMatDesc, EncryptionMaterialsAccessor accessor, S3CryptoScheme targetScheme, Provider p, AWSKMS kms, AmazonWebServiceRequest req) { if (!usesKMSKey() && newKEKMatDesc.equals(kekMaterialsDescription)) { throw new SecurityException( "Material description of the new KEK must differ from the current one"); } final EncryptionMaterials origKEK; if (usesKMSKey()) { origKEK = new KMSEncryptionMaterials(kekMaterialsDescription.get( KMSEncryptionMaterials.CUSTOMER_MASTER_KEY_ID)); } else { origKEK = accessor.getEncryptionMaterials(kekMaterialsDescription); } EncryptionMaterials newKEK = accessor.getEncryptionMaterials(newKEKMatDesc); if (newKEK == null) { throw new SdkClientException( "No material available with the description " + newKEKMatDesc + " from the encryption material provider"); } SecretKey cek = cek(encryptedCEK, keyWrappingAlgorithm, origKEK, p, getContentCryptoScheme(), kms); ContentCryptoMaterial output = create(cek, cipherLite.getIV(), newKEK, getContentCryptoScheme(), // must use same content crypto scheme targetScheme, p, kms, req); if (Arrays.equals(output.encryptedCEK, encryptedCEK)) { throw new SecurityException( "The new KEK must differ from the original"); } return output; }
/** * Recreates a new content crypto material from the current material given a * new KEK encryption materials. The purpose is to re-encrypt the CEK under * the new KEK. * * Note network calls are involved if the CEK has been or is to be protected * by KMS. * * @param newKEK * encryption materials for the new KEK; must not be null * @param accessor * used to retrieve the original KEK given the corresponding * material description * @param targetScheme * the target crypto scheme to use for recreating the content * crypto material * @param p * optional security provider; null means to use the default. * @throws SecurityException * if the old and new material description are the same; or if * the old and new KEK are the same */ ContentCryptoMaterial recreate(EncryptionMaterials newKEK, EncryptionMaterialsAccessor accessor, S3CryptoScheme targetScheme, Provider p, AWSKMS kms, AmazonWebServiceRequest req) { if (!usesKMSKey() && newKEK.getMaterialsDescription().equals(kekMaterialsDescription)) { throw new SecurityException( "Material description of the new KEK must differ from the current one"); } final EncryptionMaterials origKEK; if (usesKMSKey()) { origKEK = new KMSEncryptionMaterials(kekMaterialsDescription.get( KMSEncryptionMaterials.CUSTOMER_MASTER_KEY_ID)); } else { origKEK = accessor.getEncryptionMaterials(kekMaterialsDescription); } SecretKey cek = cek(encryptedCEK, keyWrappingAlgorithm, origKEK, p, getContentCryptoScheme(), kms); ContentCryptoMaterial output = create(cek, cipherLite.getIV(), newKEK, getContentCryptoScheme(), // must use same content crypto scheme targetScheme, // target scheme used to recreate the content crypto material p, kms, req); if (Arrays.equals(output.encryptedCEK, encryptedCEK)) { throw new SecurityException( "The new KEK must differ from the original"); } return output; }
static Map<String, String> mergeMaterialDescriptions( EncryptionMaterials materials, AmazonWebServiceRequest req) { Map<String,String> matdesc = materials.getMaterialsDescription(); if (req instanceof MaterialsDescriptionProvider) { MaterialsDescriptionProvider mdp = (MaterialsDescriptionProvider) req; Map<String, String> matdesc_req = mdp.getMaterialsDescription(); if (matdesc_req != null) { matdesc = new TreeMap<String, String>(matdesc); matdesc.putAll(matdesc_req); // request takes precedence } } return matdesc; }
/** * Creates and returns a non-null content crypto material for the given * request. * * @throws SdkClientException if no encryption material can be found. */ protected final ContentCryptoMaterial createContentCryptoMaterial( AmazonWebServiceRequest req) { if (req instanceof EncryptionMaterialsFactory) { // per request level encryption materials EncryptionMaterialsFactory f = (EncryptionMaterialsFactory)req; final EncryptionMaterials materials = f.getEncryptionMaterials(); if (materials != null) { return buildContentCryptoMaterial(materials, cryptoConfig.getCryptoProvider(), req); } } if (req instanceof MaterialsDescriptionProvider) { // per request level material description MaterialsDescriptionProvider mdp = (MaterialsDescriptionProvider) req; Map<String,String> matdesc_req = mdp.getMaterialsDescription(); ContentCryptoMaterial ccm = newContentCryptoMaterial( kekMaterialsProvider, matdesc_req, cryptoConfig.getCryptoProvider(), req); if (ccm != null) return ccm; if (matdesc_req != null) { // check to see if KMS is in use and if so we should fall thru // to the s3 client level encryption material EncryptionMaterials material = kekMaterialsProvider.getEncryptionMaterials(); if (!material.isKMSEnabled()) { throw new SdkClientException( "No material available from the encryption material provider for description " + matdesc_req); } } // if there is no material description, fall thru to use // the per s3 client level encryption materials } // per s3 client level encryption materials return newContentCryptoMaterial(this.kekMaterialsProvider, cryptoConfig.getCryptoProvider(), req); }
/** * Returns the content encryption material generated with the given kek * material, material description and security providers; or null if * the encryption material cannot be found for the specified description. */ private ContentCryptoMaterial newContentCryptoMaterial( EncryptionMaterialsProvider kekMaterialProvider, Map<String, String> materialsDescription, Provider provider, AmazonWebServiceRequest req) { EncryptionMaterials kekMaterials = kekMaterialProvider.getEncryptionMaterials(materialsDescription); if (kekMaterials == null) { return null; } return buildContentCryptoMaterial(kekMaterials, provider, req); }
/** * Returns a non-null content encryption material generated with the given kek * material and security providers. * * @throws SdkClientException if no encryption material can be found from * the given encryption material provider. */ private ContentCryptoMaterial newContentCryptoMaterial( EncryptionMaterialsProvider kekMaterialProvider, Provider provider, AmazonWebServiceRequest req) { EncryptionMaterials kekMaterials = kekMaterialProvider.getEncryptionMaterials(); if (kekMaterials == null) throw new SdkClientException("No material available from the encryption material provider"); return buildContentCryptoMaterial(kekMaterials, provider, req); }
/** * @param materials a non-null encryption material */ private ContentCryptoMaterial buildContentCryptoMaterial( EncryptionMaterials materials, Provider provider, AmazonWebServiceRequest req) { // Randomly generate the IV final byte[] iv = new byte[contentCryptoScheme.getIVLengthInBytes()]; cryptoScheme.getSecureRandom().nextBytes(iv); if (materials.isKMSEnabled()) { final Map<String, String> encryptionContext = ContentCryptoMaterial.mergeMaterialDescriptions(materials, req); GenerateDataKeyRequest keyGenReq = new GenerateDataKeyRequest() .withEncryptionContext(encryptionContext) .withKeyId(materials.getCustomerMasterKeyId()) .withKeySpec(contentCryptoScheme.getKeySpec()); keyGenReq .withGeneralProgressListener(req.getGeneralProgressListener()) .withRequestMetricCollector(req.getRequestMetricCollector()) ; GenerateDataKeyResult keyGenRes = kms.generateDataKey(keyGenReq); final SecretKey cek = new SecretKeySpec(copyAllBytesFrom(keyGenRes.getPlaintext()), contentCryptoScheme.getKeyGeneratorAlgorithm()); byte[] keyBlob = copyAllBytesFrom(keyGenRes.getCiphertextBlob()); return ContentCryptoMaterial.wrap(cek, iv, contentCryptoScheme, provider, new KMSSecuredCEK(keyBlob, encryptionContext)); } else { // Generate a one-time use symmetric key and initialize a cipher to encrypt object data return ContentCryptoMaterial.create( generateCEK(materials, provider), iv, materials, cryptoScheme, provider, kms, req); } }
/** * Non-authenticated encryption schemes can do range GETs without an issue. */ public void encryptionOnly_RangeGet_CustomerManagedKey() throws NoSuchAlgorithmException { SecretKey secretKey = KeyGenerator.getInstance("AES").generateKey(); AmazonS3Encryption s3Encryption = AmazonS3EncryptionClientBuilder .standard() .withRegion(Regions.US_WEST_2) .withCryptoConfiguration(new CryptoConfiguration(CryptoMode.EncryptionOnly)) .withEncryptionMaterials(new StaticEncryptionMaterialsProvider(new EncryptionMaterials(secretKey))) .build(); s3Encryption.putObject(BUCKET_NAME, ENCRYPTED_KEY, "some contents"); System.out.println(s3Encryption.getObject(new GetObjectRequest(BUCKET_NAME, ENCRYPTED_KEY) .withRange(0, 2))); }
@Override public EncryptionMaterials getEncryptionMaterials(Map<String, String> materialsDescription) { if (materialsDescription == null || materialsDescription.get(CSE_RSA_NAME) == null || descValue.equals(materialsDescription.get(CSE_RSA_NAME))) { return this.encryptionMaterials; } else { throw new RuntimeException( String.format("RSA key pair (%s: %s) doesn't match with the materials description", CSE_RSA_NAME, descValue)); } }
@Override public EncryptionMaterials getEncryptionMaterials() { if (this.encryptionMaterials != null) { return this.encryptionMaterials; } else { throw new RuntimeException("RSA key pair is not initialized."); } }
/** * @return a non-null content crypto material. */ private static ContentCryptoMaterial fromObjectMetadata0( ObjectMetadata metadata, EncryptionMaterialsAccessor kekMaterialAccessor, Provider securityProvider, long[] range, ExtraMaterialsDescription extra, boolean keyWrapExpected, AWSKMS kms) { // CEK and IV Map<String, String> userMeta = metadata.getUserMetadata(); String b64key = userMeta.get(Headers.CRYPTO_KEY_V2); if (b64key == null) { b64key = userMeta.get(Headers.CRYPTO_KEY); if (b64key == null) throw new SdkClientException( "Content encrypting key not found."); } byte[] cekWrapped = Base64.decode(b64key); byte[] iv = Base64.decode(userMeta.get(Headers.CRYPTO_IV)); if (cekWrapped == null || iv == null) { throw new SdkClientException( "Content encrypting key or IV not found."); } // Material description String matdescStr = userMeta.get(Headers.MATERIALS_DESCRIPTION); final String keyWrapAlgo = userMeta.get(Headers.CRYPTO_KEYWRAP_ALGORITHM); final boolean isKMS = isKMSKeyWrapped(keyWrapAlgo); final Map<String, String> core = matdescFromJson(matdescStr); final Map<String, String> merged = isKMS || extra == null ? core : extra.mergeInto(core); final EncryptionMaterials materials; if (isKMS) { materials = new KMSEncryptionMaterials( core.get(KMSEncryptionMaterials.CUSTOMER_MASTER_KEY_ID)); materials.addDescriptions(core); } else { materials = kekMaterialAccessor == null ? null : kekMaterialAccessor.getEncryptionMaterials(merged) ; if (materials == null) { throw new SdkClientException( "Unable to retrieve the client encryption materials"); } } // CEK algorithm String cekAlgo = userMeta.get(Headers.CRYPTO_CEK_ALGORITHM); boolean isRangeGet = range != null; // The content crypto scheme may vary depending on whether // it is a range get operation ContentCryptoScheme contentCryptoScheme = ContentCryptoScheme.fromCEKAlgo(cekAlgo, isRangeGet); if (isRangeGet) { // Adjust the IV as needed iv = contentCryptoScheme.adjustIV(iv, range[0]); } else { // Validate the tag length supported int tagLenExpected = contentCryptoScheme.getTagLengthInBits(); if (tagLenExpected > 0) { String s = userMeta.get(Headers.CRYPTO_TAG_LENGTH); int tagLenActual = Integer.parseInt(s); if (tagLenExpected != tagLenActual) { throw new SdkClientException("Unsupported tag length: " + tagLenActual + ", expected: " + tagLenExpected); } } } // Unwrap or decrypt the CEK if (keyWrapExpected && keyWrapAlgo == null) throw newKeyWrapException(); SecretKey cek = cek(cekWrapped, keyWrapAlgo, materials, securityProvider, contentCryptoScheme, kms); return new ContentCryptoMaterial(merged, cekWrapped, keyWrapAlgo, contentCryptoScheme.createCipherLite(cek, iv, Cipher.DECRYPT_MODE, securityProvider)); }
/** * @return a non-null content crypto material. */ private static ContentCryptoMaterial fromInstructionFile0( Map<String, String> instFile, EncryptionMaterialsAccessor kekMaterialAccessor, Provider securityProvider, long[] range, ExtraMaterialsDescription extra, boolean keyWrapExpected, AWSKMS kms) { // CEK and IV String b64key = instFile.get(Headers.CRYPTO_KEY_V2); if (b64key == null) { b64key = instFile.get(Headers.CRYPTO_KEY); if (b64key == null) throw new SdkClientException( "Content encrypting key not found."); } byte[] cekWrapped = Base64.decode(b64key); byte[] iv = Base64.decode(instFile.get(Headers.CRYPTO_IV)); if (cekWrapped == null || iv == null) { throw new SdkClientException( "Necessary encryption info not found in the instruction file " + instFile); } final String keyWrapAlgo = instFile.get(Headers.CRYPTO_KEYWRAP_ALGORITHM); final boolean isKMS = isKMSKeyWrapped(keyWrapAlgo); // Material description String matdescStr = instFile.get(Headers.MATERIALS_DESCRIPTION); final Map<String, String> core = matdescFromJson(matdescStr); final Map<String, String> merged = extra == null || isKMS ? core : extra.mergeInto(core); EncryptionMaterials materials; if (isKMS) { materials = new KMSEncryptionMaterials( core.get(KMSEncryptionMaterials.CUSTOMER_MASTER_KEY_ID)); materials.addDescriptions(core); } else { materials = kekMaterialAccessor == null ? null : kekMaterialAccessor.getEncryptionMaterials(merged); if (materials == null) { throw new SdkClientException( "Unable to retrieve the encryption materials that originally " + "encrypted object corresponding to instruction file " + instFile); } } // CEK algorithm final String cekAlgo = instFile.get(Headers.CRYPTO_CEK_ALGORITHM); final boolean isRangeGet = range != null; // The content crypto scheme may vary depending on whether // it is a range get operation ContentCryptoScheme contentCryptoScheme = ContentCryptoScheme .fromCEKAlgo(cekAlgo, isRangeGet); if (isRangeGet) { // Adjust the IV as needed iv = contentCryptoScheme.adjustIV(iv, range[0]); } else { // Validate the tag length supported int tagLenExpected = contentCryptoScheme.getTagLengthInBits(); if (tagLenExpected > 0) { String s = instFile.get(Headers.CRYPTO_TAG_LENGTH); int tagLenActual = Integer.parseInt(s); if (tagLenExpected != tagLenActual) { throw new SdkClientException("Unsupported tag length: " + tagLenActual + ", expected: " + tagLenExpected); } } } // Unwrap or decrypt the CEK if (keyWrapExpected && keyWrapAlgo == null) throw newKeyWrapException(); SecretKey cek = cek(cekWrapped, keyWrapAlgo, materials, securityProvider, contentCryptoScheme, kms); return new ContentCryptoMaterial(merged, cekWrapped, keyWrapAlgo, contentCryptoScheme.createCipherLite(cek, iv, Cipher.DECRYPT_MODE, securityProvider)); }
/** * Returns a new instance of <code>ContentCryptoMaterial</code> for the * given input parameters by using the specified content crypto scheme, and * S3 crypto scheme. * * Note network calls are involved if the CEK is to be protected by KMS. * * @param cek * content encrypting key * @param iv * initialization vector * @param kekMaterials * kek encryption material used to secure the CEK; can be KMS * enabled. * @param contentCryptoScheme * content crypto scheme to be used, which can differ from the * one of <code>targetS3CryptoScheme</code> * @param targetS3CryptoScheme * the target s3 crypto scheme to be used for providing the key * wrapping scheme and mechanism for secure randomness * @param provider * security provider * @param kms * reference to the KMS client * @param req * the originating AWS service request */ private static ContentCryptoMaterial doCreate(SecretKey cek, byte[] iv, EncryptionMaterials kekMaterials, ContentCryptoScheme contentCryptoScheme, S3CryptoScheme targetS3CryptoScheme, Provider provider, AWSKMS kms, AmazonWebServiceRequest req) { // Secure the envelope symmetric key either by encryption, key wrapping // or KMS. SecuredCEK cekSecured = secureCEK(cek, kekMaterials, targetS3CryptoScheme.getKeyWrapScheme(), targetS3CryptoScheme.getSecureRandom(), provider, kms, req); return wrap(cek, iv, contentCryptoScheme, provider, cekSecured); }
/** * @param kekMaterials non-null encryption materials */ protected final SecretKey generateCEK( final EncryptionMaterials kekMaterials, final Provider providerIn) { final String keygenAlgo = contentCryptoScheme.getKeyGeneratorAlgorithm(); KeyGenerator generator; try { generator = providerIn == null ? KeyGenerator.getInstance(keygenAlgo) : KeyGenerator.getInstance(keygenAlgo, providerIn); generator.init(contentCryptoScheme.getKeyLengthInBits(), cryptoScheme.getSecureRandom()); // Set to true iff the key encryption involves the use of BC's public key boolean involvesBCPublicKey = false; KeyPair keypair = kekMaterials.getKeyPair(); if (keypair != null) { String keyWrapAlgo = cryptoScheme.getKeyWrapScheme().getKeyWrapAlgorithm(keypair.getPublic()); if (keyWrapAlgo == null) { Provider provider = generator.getProvider(); String providerName = provider == null ? null : provider.getName(); involvesBCPublicKey = CryptoRuntime.BOUNCY_CASTLE_PROVIDER.equals(providerName); } } SecretKey secretKey = generator.generateKey(); if (!involvesBCPublicKey || secretKey.getEncoded()[0] != 0) return secretKey; for (int retry = 0; retry < 9; retry++) { // Regenerate the random key due to a bug/feature in BC: // https://github.com/aws/aws-sdk-android/issues/15 secretKey = generator.generateKey(); if (secretKey.getEncoded()[0] != 0) return secretKey; } // The probability of getting here is 2^80, which is impossible in practice. throw new SdkClientException("Failed to generate secret key"); } catch (NoSuchAlgorithmException e) { throw new SdkClientException( "Unable to generate envelope symmetric key:" + e.getMessage(), e); } }
@Override public final PutObjectResult putInstructionFileSecurely( PutInstructionFileRequest req) { final S3ObjectId id = req.getS3ObjectId(); final GetObjectRequest getreq = new GetObjectRequest(id); appendUserAgent(getreq, USER_AGENT); // Get the object from S3 final S3Object retrieved = s3.getObject(getreq); // We only need the meta-data already retrieved, not the data stream. // So close it immediately to prevent resource leakage. closeQuietly(retrieved, log); if (retrieved == null) { throw new IllegalArgumentException( "The specified S3 object (" + id + ") doesn't exist."); } S3ObjectWrapper wrapped = new S3ObjectWrapper(retrieved, id); try { final ContentCryptoMaterial origCCM = contentCryptoMaterialOf(wrapped); if (ContentCryptoScheme.AES_GCM.equals(origCCM.getContentCryptoScheme()) && cryptoConfig.getCryptoMode() == CryptoMode.EncryptionOnly) { throw new SecurityException( "Lowering the protection of encryption material is not allowed"); } securityCheck(origCCM, wrapped); // Re-ecnrypt the CEK in a new content crypto material final EncryptionMaterials newKEK = req.getEncryptionMaterials(); final ContentCryptoMaterial newCCM; if (newKEK == null) { newCCM = origCCM.recreate(req.getMaterialsDescription(), this.kekMaterialsProvider, cryptoScheme, cryptoConfig.getCryptoProvider(), kms, req); } else { newCCM = origCCM.recreate(newKEK, this.kekMaterialsProvider, cryptoScheme, cryptoConfig.getCryptoProvider(), kms, req); } PutObjectRequest putInstFileRequest = req.createPutObjectRequest(retrieved); // Put the new instruction file into S3 return s3.putObject(updateInstructionPutRequest(putInstFileRequest, newCCM)); } catch (RuntimeException ex) { // If we're unable to set up the decryption, make sure we close the // HTTP connection closeQuietly(retrieved, log); throw ex; } catch (Error error) { closeQuietly(retrieved, log); throw error; } }
public TestEncryptionMaterialsProvider() { encryptionMaterials = new EncryptionMaterials(new SecretKeySpec(new byte[] {1, 2, 3}, "AES")); }
@Override public EncryptionMaterials getEncryptionMaterials(Map<String, String> materialsDescription) { return encryptionMaterials; }
@Override public EncryptionMaterials getEncryptionMaterials() { return encryptionMaterials; }
/** * Returns a new instance of <code>ContentCryptoMaterial</code> for the * input parameters using the specified content crypto scheme, and the key * wrapping and secure randomness specified of the specified s3 crypto * scheme. * * Note network calls are involved if the CEK is to be protected by KMS. * * @param cek * content encrypting key; must not be null. * @param iv * initialization vector; must not be null. * @param contentCryptoScheme * content crypto scheme to be used * @param targetScheme * the target s3 crypto scheme to be used for recreating the * content crypto material by providing the key wrapping scheme * and mechanism for secure randomness * @param provider * optional security provider */ static ContentCryptoMaterial create(SecretKey cek, byte[] iv, EncryptionMaterials kekMaterials, ContentCryptoScheme contentCryptoScheme, S3CryptoScheme targetScheme, Provider provider, AWSKMS kms, AmazonWebServiceRequest req) { return doCreate(cek, iv, kekMaterials, contentCryptoScheme, targetScheme, provider, kms, req); }
/** * Returns a new instance of <code>ContentCryptoMaterial</code> * for the input parameters using the specified s3 crypto scheme. * Note network calls are involved if the CEK is to be protected by KMS. * * @param cek content encrypting key * @param iv initialization vector * @param kekMaterials kek encryption material used to secure the CEK; * can be KMS enabled. * @param scheme * s3 crypto scheme to be used for the content crypto material by * providing the content crypto scheme, key wrapping scheme and * mechanism for secure randomness * @param provider optional security provider * @param kms reference to the KMS client * @param req originating service request */ static ContentCryptoMaterial create(SecretKey cek, byte[] iv, EncryptionMaterials kekMaterials, S3CryptoScheme scheme, Provider provider, AWSKMS kms, AmazonWebServiceRequest req) { return doCreate(cek, iv, kekMaterials, scheme.getContentCryptoScheme(), scheme, provider, kms, req); }
/** * <p> * Constructs a new Amazon S3 Encryption client that will make <b>anonymous</b> * requests to Amazon S3. If {@link #getObject(String, String)} is called, * the object contents will be decrypted with the encryption materials provided. * The encryption implementation of the provided crypto provider will be * used to encrypt and decrypt data. * </p> * <p> * Only a subset of the Amazon S3 API will work with anonymous * <i>(i.e. unsigned)</i> requests, but this can prove useful in some situations. * For example: * <ul> * <li>If an Amazon S3 bucket has {@link Permission#Read} permission for the * {@link GroupGrantee#AllUsers} group, anonymous clients can call * {@link #listObjects(String)} to see what objects are stored in a bucket.</li> * <li>If an object has {@link Permission#Read} permission for the * {@link GroupGrantee#AllUsers} group, anonymous clients can call * {@link #getObject(String, String)} and * {@link #getObjectMetadata(String, String)} to pull object content and * metadata.</li> * <li>If a bucket has {@link Permission#Write} permission for the * {@link GroupGrantee#AllUsers} group, anonymous clients can upload objects * to the bucket.</li> * </ul> * </p> * * @param encryptionMaterials * The encryption materials to be used to encrypt and decrypt data. * @param cryptoConfig * The crypto configuration whose parameters will be used to encrypt and decrypt data. * @deprecated use {@link AmazonS3EncryptionClientBuilder#withEncryptionMaterials(EncryptionMaterialsProvider)} and * {@link AmazonS3EncryptionClientBuilder#withCryptoConfiguration(CryptoConfiguration)} */ @Deprecated public AmazonS3EncryptionClient(EncryptionMaterials encryptionMaterials, CryptoConfiguration cryptoConfig) { this(new StaticEncryptionMaterialsProvider(encryptionMaterials), cryptoConfig); }
/** * <p> * Constructs a new Amazon S3 Encryption client using the specified AWS credentials to * access Amazon S3. Object contents will be encrypted and decrypted with the encryption * materials provided. * </p> * * @param credentials * The AWS credentials to use when making requests to Amazon S3 * with this client. * @param encryptionMaterials * The encryption materials to be used to encrypt and decrypt data. * @deprecated use {@link AmazonS3EncryptionClientBuilder#withEncryptionMaterials(EncryptionMaterialsProvider)} and * {@link AmazonS3EncryptionClientBuilder#withCredentials(AWSCredentialsProvider)} */ @Deprecated public AmazonS3EncryptionClient(AWSCredentials credentials, EncryptionMaterials encryptionMaterials) { this(credentials, new StaticEncryptionMaterialsProvider( encryptionMaterials)); }
/** * <p> * Constructs a new Amazon S3 Encryption client using the specified AWS credentials to * access Amazon S3. Object contents will be encrypted and decrypted with the encryption * materials provided. The encryption implementation of the provided crypto provider will * be used to encrypt and decrypt data. * </p> * * @param credentials * The AWS credentials to use when making requests to Amazon S3 * with this client. * @param encryptionMaterials * The encryption materials to be used to encrypt and decrypt data. * @param cryptoConfig * The crypto configuration whose parameters will be used to encrypt and decrypt data. * @deprecated use {@link AmazonS3EncryptionClientBuilder#withEncryptionMaterials(EncryptionMaterialsProvider)} and * {@link AmazonS3EncryptionClientBuilder#withCredentials(AWSCredentialsProvider)} and * {@link AmazonS3EncryptionClientBuilder#withCryptoConfiguration(CryptoConfiguration)} */ @Deprecated public AmazonS3EncryptionClient(AWSCredentials credentials, EncryptionMaterials encryptionMaterials, CryptoConfiguration cryptoConfig) { this(credentials, new StaticEncryptionMaterialsProvider( encryptionMaterials), cryptoConfig); }
/** * <p> * Constructs a new Amazon S3 Encryption client using the specified AWS credentials and * client configuration to access Amazon S3. Object contents will be encrypted and decrypted * with the encryption materials provided. The crypto provider and storage mode denoted in * the specified crypto configuration will be used to encrypt and decrypt data. * </p> * * @param credentials * The AWS credentials to use when making requests to Amazon S3 * with this client. * @param encryptionMaterials * The encryption materials to be used to encrypt and decrypt data. * @param clientConfig * The client configuration options controlling how this client * connects to Amazon S3 (ex: proxy settings, retry counts, etc). * @param cryptoConfig * The crypto configuration whose parameters will be used to encrypt and decrypt data. * @throws IllegalArgumentException * If either of the encryption materials or crypto configuration parameters are null. * @deprecated use {@link AmazonS3EncryptionClientBuilder#withEncryptionMaterials(EncryptionMaterialsProvider)} and * {@link AmazonS3EncryptionClientBuilder#withCredentials(AWSCredentialsProvider)} and * {@link AmazonS3EncryptionClientBuilder#withCryptoConfiguration(CryptoConfiguration)} and * {@link AmazonS3EncryptionClientBuilder#withClientConfiguration(ClientConfiguration)} */ @Deprecated public AmazonS3EncryptionClient(AWSCredentials credentials, EncryptionMaterials encryptionMaterials, ClientConfiguration clientConfig, CryptoConfiguration cryptoConfig) { this(credentials, new StaticEncryptionMaterialsProvider( encryptionMaterials), clientConfig, cryptoConfig); }
/** * <p> * Constructs a new Amazon S3 Encryption client that will make <b>anonymous</b> * requests to Amazon S3. If {@link #getObject(String, String)} is called, * the object contents will be decrypted with the encryption materials provided. * </p> * <p> * Only a subset of the Amazon S3 API will work with anonymous * <i>(i.e. unsigned)</i> requests, but this can prove useful in some situations. * For example: * <ul> * <li>If an Amazon S3 bucket has {@link Permission#Read} permission for the * {@link GroupGrantee#AllUsers} group, anonymous clients can call * {@link #listObjects(String)} to see what objects are stored in a bucket.</li> * <li>If an object has {@link Permission#Read} permission for the * {@link GroupGrantee#AllUsers} group, anonymous clients can call * {@link #getObject(String, String)} and * {@link #getObjectMetadata(String, String)} to pull object content and * metadata.</li> * <li>If a bucket has {@link Permission#Write} permission for the * {@link GroupGrantee#AllUsers} group, anonymous clients can upload objects * to the bucket.</li> * </ul> * </p> * * @param encryptionMaterials * The encryption materials to be used to encrypt and decrypt data. * @deprecated use {@link AmazonS3EncryptionClientBuilder#withEncryptionMaterials(EncryptionMaterialsProvider)} */ @Deprecated public AmazonS3EncryptionClient(EncryptionMaterials encryptionMaterials) { this(new StaticEncryptionMaterialsProvider(encryptionMaterials)); }