/** * 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)); }
/** * This uses the V2 metadata schema with a key wrap algorithm of 'kms' and a CEK algorithm of AES/CBC/PKCS5Padding. */ public void encryptionOnly_KmsManagedKey() throws NoSuchAlgorithmException { AmazonS3Encryption s3Encryption = AmazonS3EncryptionClientBuilder .standard() .withRegion(Regions.US_WEST_2) .withCryptoConfiguration(new CryptoConfiguration(CryptoMode.EncryptionOnly)) // Can either be Key ID or alias (prefixed with 'alias/') .withEncryptionMaterials(new KMSEncryptionMaterialsProvider("alias/s3-kms-key")) .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)); }
/** * This uses the V2 metadata schema with a key wrap algorithm of 'kms' and a CEK algorithm of AES/GCM/NoPadding. */ public void authenticatedEncryption_KmsManagedKey() throws NoSuchAlgorithmException { AmazonS3Encryption s3Encryption = AmazonS3EncryptionClientBuilder .standard() .withRegion(Regions.US_WEST_2) .withCryptoConfiguration(new CryptoConfiguration(CryptoMode.AuthenticatedEncryption)) // Can either be Key ID or alias (prefixed with 'alias/') .withEncryptionMaterials(new KMSEncryptionMaterialsProvider("alias/s3-kms-key")) .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 authenticatedEncryption_KmsManagedKey except throws an exception when trying to get objects not encrypted with * AES/GCM. */ public void strictAuthenticatedEncryption_KmsManagedKey() throws NoSuchAlgorithmException { AmazonS3Encryption s3Encryption = AmazonS3EncryptionClientBuilder .standard() .withRegion(Regions.US_WEST_2) .withCryptoConfiguration(new CryptoConfiguration(CryptoMode.AuthenticatedEncryption)) // Can either be Key ID or alias (prefixed with 'alias/') .withEncryptionMaterials(new KMSEncryptionMaterialsProvider("alias/s3-kms-key")) .build(); AmazonS3 s3NonEncrypt = AmazonS3ClientBuilder.defaultClient(); s3Encryption.putObject(BUCKET_NAME, ENCRYPTED_KEY, "some contents"); s3NonEncrypt.putObject(BUCKET_NAME, NON_ENCRYPTED_KEY, "some other contents"); 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"); } }
static S3CryptoScheme from(CryptoMode mode) { switch (mode) { case EncryptionOnly: return new S3CryptoScheme(ContentCryptoScheme.AES_CBC, S3KeyWrapScheme.NONE); case AuthenticatedEncryption: case StrictAuthenticatedEncryption: return new S3CryptoScheme(ContentCryptoScheme.AES_GCM, new S3KeyWrapScheme()); default: throw new IllegalStateException(); } }
/** * @param cryptoConfig a read-only copy of the crypto configuration. */ S3CryptoModuleAE(AWSKMS kms, S3Direct s3, AWSCredentialsProvider credentialsProvider, EncryptionMaterialsProvider encryptionMaterialsProvider, CryptoConfiguration cryptoConfig) { super(kms, s3, credentialsProvider, encryptionMaterialsProvider, cryptoConfig); CryptoMode mode = cryptoConfig.getCryptoMode(); if (mode != StrictAuthenticatedEncryption && mode != AuthenticatedEncryption) { throw new IllegalArgumentException(); } }
/** * 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))); }
/** * Returns the given metadata updated with this content crypto material. */ ObjectMetadata toObjectMetadata(ObjectMetadata metadata, CryptoMode mode) { return mode == CryptoMode.EncryptionOnly && !usesKMSKey() ? toObjectMetadataEO(metadata) : toObjectMetadata(metadata); }
/** * Returns the json string in backward compatibility (old) format, so it can * be read by older version of the AWS SDK. */ String toJsonString(CryptoMode mode) { return mode == CryptoMode.EncryptionOnly && !usesKMSKey() ? toJsonStringEO() : toJsonString(); }
@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 CryptoModuleDispatcher(AWSKMS kms, S3Direct s3, AWSCredentialsProvider credentialsProvider, EncryptionMaterialsProvider encryptionMaterialsProvider, CryptoConfiguration cryptoConfig) { cryptoConfig = cryptoConfig.clone(); // make a clone CryptoMode cryptoMode = cryptoConfig.getCryptoMode(); if (cryptoMode == null) { cryptoMode = EncryptionOnly; cryptoConfig.setCryptoMode(cryptoMode); // defaults to EO } cryptoConfig = cryptoConfig.readOnly(); // make read-only this.defaultCryptoMode = cryptoConfig.getCryptoMode(); switch(this.defaultCryptoMode) { case StrictAuthenticatedEncryption: this.ae = new S3CryptoModuleAEStrict(kms, s3, credentialsProvider, encryptionMaterialsProvider, cryptoConfig); this.eo = null; break; case AuthenticatedEncryption: this.ae = new S3CryptoModuleAE(kms, s3, credentialsProvider, encryptionMaterialsProvider, cryptoConfig); this.eo = null; break; case EncryptionOnly: this.eo = new S3CryptoModuleEO(kms, s3, credentialsProvider, encryptionMaterialsProvider, cryptoConfig); CryptoConfiguration aeConfig = cryptoConfig.clone(); try { aeConfig.setCryptoMode(AuthenticatedEncryption); } catch(UnsupportedOperationException ex) { // BC not available during runtime; but EO can still work. // Hence ignoring. } this.ae = new S3CryptoModuleAE(kms, s3, credentialsProvider, encryptionMaterialsProvider, aeConfig.readOnly()); break; default: throw new IllegalStateException(); } }