Skip to content

Commit 2871210

Browse files
author
Anirav Kareddy
committed
Added example for standard RSA key rotation with default instruction file suffix
1 parent 07056fc commit 2871210

File tree

1 file changed

+120
-8
lines changed

1 file changed

+120
-8
lines changed

src/examples/java/software/amazon/encryption/s3/examples/ReEncryptInstructionFileExample.java

Lines changed: 120 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import java.security.NoSuchAlgorithmException;
2424
import java.security.PrivateKey;
2525
import java.security.PublicKey;
26-
import java.security.SecureRandom;
2726

2827
import static org.junit.jupiter.api.Assertions.assertEquals;
2928
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -61,6 +60,7 @@ public static void main(final String[] args) throws NoSuchAlgorithmException {
6160
final String bucket = args[0];
6261
simpleAesKeyringReEncryptInstructionFile(bucket);
6362
simpleRsaKeyringReEncryptInstructionFile(bucket);
63+
simpleRsaKeyringReEncryptInstructionFileWithCustomSuffix(bucket);
6464
}
6565

6666
/**
@@ -81,7 +81,6 @@ public static void simpleAesKeyringReEncryptInstructionFile(final String bucket)
8181
// Create the original AES keyring with materials description
8282
AesKeyring oldKeyring = AesKeyring.builder()
8383
.wrappingKey(originalAesKey)
84-
.secureRandom(new SecureRandom())
8584
.materialsDescription(MaterialsDescription.builder()
8685
.put("version", "1.0")
8786
.put("rotated", "no")
@@ -113,7 +112,6 @@ public static void simpleAesKeyringReEncryptInstructionFile(final String bucket)
113112
// Create a new keyring with the new AES key and updated materials description
114113
AesKeyring newKeyring = AesKeyring.builder()
115114
.wrappingKey(newAesKey)
116-
.secureRandom(new SecureRandom())
117115
.materialsDescription(MaterialsDescription.builder()
118116
.put("version", "2.0")
119117
.put("rotated", "yes")
@@ -167,8 +165,8 @@ public static void simpleAesKeyringReEncryptInstructionFile(final String bucket)
167165
}
168166

169167
/**
170-
* This example demonstrates generating a custom instruction file to enable access to encrypted object by a third party.
171-
* This enables secure sharing of encrypted objects without sharing private keys.
168+
* This example demonstrates re-encrypting the encrypted data key in an instruction file with a new RSA wrapping key.
169+
* The other cryptographic parameters in the instruction file such as the IV and wrapping algorithm remain unchanged.
172170
*
173171
* @param bucket The name of the Amazon S3 bucket to perform operations on.
174172
* @throws NoSuchAlgorithmException if RSA algorithm is not available
@@ -178,6 +176,123 @@ public static void simpleRsaKeyringReEncryptInstructionFile(final String bucket)
178176
final String objectKey = appendTestSuffix("rsa-re-encrypt-instruction-file-test");
179177
final String input = "Testing re-encryption of instruction file with RSA Keyring";
180178

179+
// Generate the original RSA key pair for initial encryption
180+
KeyPair originalRsaKeyPair = generateRsaKeyPair();
181+
PublicKey originalPublicKey = originalRsaKeyPair.getPublic();
182+
PrivateKey originalPrivateKey = originalRsaKeyPair.getPrivate();
183+
184+
// Create a partial RSA key pair for the original keyring
185+
PartialRsaKeyPair originalPartialRsaKeyPair = PartialRsaKeyPair.builder()
186+
.publicKey(originalPublicKey)
187+
.privateKey(originalPrivateKey)
188+
.build();
189+
190+
// Create the original RSA keyring with materials description
191+
RsaKeyring originalKeyring = RsaKeyring.builder()
192+
.wrappingKeyPair(originalPartialRsaKeyPair)
193+
.materialsDescription(MaterialsDescription.builder()
194+
.put("version", "1.0")
195+
.put("rotated", "no")
196+
.build())
197+
.build();
198+
199+
// Create a default S3 client for instruction file operations
200+
S3Client wrappedClient = S3Client.create();
201+
202+
// Create the S3 Encryption Client with instruction file support enabled
203+
// The client can perform both putObject and getObject operations using RSA keyring
204+
S3EncryptionClient originalClient = S3EncryptionClient.builder()
205+
.keyring(originalKeyring)
206+
.instructionFileConfig(InstructionFileConfig.builder()
207+
.instructionFileClient(wrappedClient)
208+
.enableInstructionFilePutObject(true)
209+
.build())
210+
.build();
211+
212+
// Upload both the encrypted object and instruction file to the specified bucket in S3
213+
originalClient.putObject(builder -> builder
214+
.bucket(bucket)
215+
.key(objectKey)
216+
.build(), RequestBody.fromString(input));
217+
218+
// Generate a new RSA key pair for the new RSA keyring
219+
KeyPair newKeyPair = generateRsaKeyPair();
220+
PublicKey newPublicKey = newKeyPair.getPublic();
221+
PrivateKey newPrivateKey = newKeyPair.getPrivate();
222+
223+
// Create a partial RSA key pair for the new RSA keyring
224+
PartialRsaKeyPair newPartialRsaKeyPair = PartialRsaKeyPair.builder()
225+
.publicKey(newPublicKey)
226+
.privateKey(newPrivateKey)
227+
.build();
228+
229+
// Create the new RSA keyring with updated materials description
230+
RsaKeyring newKeyring = RsaKeyring.builder()
231+
.wrappingKeyPair(newPartialRsaKeyPair)
232+
.materialsDescription(MaterialsDescription.builder()
233+
.put("version", "2.0")
234+
.put("rotated", "yes")
235+
.build())
236+
.build();
237+
238+
// Create the re-encryption of instruction file request to re-encrypt the encrypted data key with the new wrapping key
239+
// This updates the instruction file without touching the encrypted object
240+
ReEncryptInstructionFileRequest reEncryptInstructionFileRequest = ReEncryptInstructionFileRequest.builder()
241+
.bucket(bucket)
242+
.key(objectKey)
243+
.newKeyring(newKeyring)
244+
.build();
245+
246+
// Perform the re-encryption of the instruction file
247+
ReEncryptInstructionFileResponse reEncryptInstructionFileResponse = originalClient.reEncryptInstructionFile(reEncryptInstructionFileRequest);
248+
249+
// Verify that the original client can no longer decrypt the object
250+
// This proves that the instruction file has been successfully re-encrypted
251+
try {
252+
originalClient.getObjectAsBytes(builder -> builder
253+
.bucket(bucket)
254+
.key(objectKey)
255+
.build());
256+
throw new RuntimeException("Original client should not be able to decrypt the object in S3 post re-encryption of instruction file!");
257+
} catch (S3EncryptionClientException e) {
258+
assertTrue(e.getMessage().contains("Unable to RSA-OAEP-SHA1 unwrap"));
259+
}
260+
261+
// Create a new client with the rotated AES key
262+
S3EncryptionClient newClient = S3EncryptionClient.builder()
263+
.keyring(newKeyring)
264+
.instructionFileConfig(InstructionFileConfig.builder()
265+
.instructionFileClient(wrappedClient)
266+
.enableInstructionFilePutObject(true)
267+
.build())
268+
.build();
269+
270+
// Verify that the new client can successfully decrypt the object
271+
// This proves that the instruction file has been successfully re-encrypted
272+
ResponseBytes<GetObjectResponse> decryptedObject = newClient.getObjectAsBytes(builder -> builder
273+
.bucket(bucket)
274+
.key(objectKey)
275+
.build());
276+
277+
// Assert that the decrypted object's content matches the original input
278+
assertEquals(input, decryptedObject.asUtf8String());
279+
280+
// Call deleteObject to delete the object from given S3 Bucket
281+
deleteObject(bucket, objectKey, originalClient);
282+
}
283+
284+
/**
285+
* This example demonstrates generating a custom instruction file to enable access to encrypted object by a third party.
286+
* This enables secure sharing of encrypted objects without sharing private keys.
287+
*
288+
* @param bucket The name of the Amazon S3 bucket to perform operations on.
289+
* @throws NoSuchAlgorithmException if RSA algorithm is not available
290+
*/
291+
public static void simpleRsaKeyringReEncryptInstructionFileWithCustomSuffix(final String bucket) throws NoSuchAlgorithmException {
292+
// Set up the S3 object key and content to be encrypted
293+
final String objectKey = appendTestSuffix("rsa-re-encrypt-instruction-file-test-with-custom-suffix");
294+
final String input = "Testing re-encryption of instruction file with RSA Keyring";
295+
181296
// Generate RSA key pair for the original client
182297
KeyPair clientRsaKeyPair = generateRsaKeyPair();
183298
PublicKey clientPublicKey = clientRsaKeyPair.getPublic();
@@ -192,7 +307,6 @@ public static void simpleRsaKeyringReEncryptInstructionFile(final String bucket)
192307
// Create the client's RSA keyring with materials description
193308
RsaKeyring clientKeyring = RsaKeyring.builder()
194309
.wrappingKeyPair(clientPartialRsaKeyPair)
195-
.secureRandom(new SecureRandom())
196310
.materialsDescription(MaterialsDescription.builder()
197311
.put("isOwner", "yes")
198312
.put("access-level", "admin")
@@ -232,7 +346,6 @@ public static void simpleRsaKeyringReEncryptInstructionFile(final String bucket)
232346
// Create the third party's RSA keyring with updated materials description
233347
RsaKeyring thirdPartyKeyring = RsaKeyring.builder()
234348
.wrappingKeyPair(thirdPartyPartialRsaKeyPair)
235-
.secureRandom(new SecureRandom())
236349
.materialsDescription(MaterialsDescription.builder()
237350
.put("isOwner", "no")
238351
.put("access-level", "user")
@@ -255,7 +368,6 @@ public static void simpleRsaKeyringReEncryptInstructionFile(final String bucket)
255368
// Create the third party's S3 Encryption Client
256369
S3EncryptionClient thirdPartyClient = S3EncryptionClient.builder()
257370
.keyring(thirdPartyKeyring)
258-
.secureRandom(new SecureRandom())
259371
.instructionFileConfig(InstructionFileConfig.builder()
260372
.instructionFileClient(wrappedClient)
261373
.enableInstructionFilePutObject(true)

0 commit comments

Comments
 (0)