11package software .amazon .encryption .s3 .materials ;
22
33import java .nio .charset .StandardCharsets ;
4- import java .security .NoSuchAlgorithmException ;
54import java .security .SecureRandom ;
65import java .util .ArrayList ;
76import java .util .List ;
87import javax .crypto .Cipher ;
9- import javax .crypto .NoSuchPaddingException ;
108import javax .crypto .SecretKey ;
119import javax .crypto .spec .GCMParameterSpec ;
10+ import software .amazon .encryption .s3 .algorithms .AlgorithmSuite ;
1211
1312public class AESKeyring implements Keyring {
1413
14+ private static final String KEY_ALGORITHM = "AES" ;
1515 private static final String KEY_PROVIDER_ID = "AES/GCM" ;
1616 private static final String CIPHER_ALGORITHM = "AES/GCM/NoPadding" ;
17- private static final int IV_LENGTH_IN_BYTES = 12 ;
18- private static final int TAG_LENGTH_IN_BYTES = 16 ;
19- private static final int TAG_LENGTH_IN_BITS = TAG_LENGTH_IN_BYTES * 8 ;
17+ private static final int NONCE_LENGTH_BYTES = 12 ;
18+ private static final int TAG_LENGTH_BYTES = 16 ;
19+ private static final int TAG_LENGTH_BITS = TAG_LENGTH_BYTES * 8 ;
2020 private final SecretKey _wrappingKey ;
2121
2222 public AESKeyring (SecretKey wrappingKey ) {
23- if (!wrappingKey .getAlgorithm ().equals ("AES" )) {
23+ if (!wrappingKey .getAlgorithm ().equals (KEY_ALGORITHM )) {
2424 // TODO: throw?
2525 }
2626
@@ -34,24 +34,24 @@ public EncryptionMaterials onEncrypt(EncryptionMaterials materials) {
3434 try {
3535 SecureRandom secureRandom = new SecureRandom ();
3636
37- byte [] iv = new byte [IV_LENGTH_IN_BYTES ];
38- secureRandom .nextBytes (iv );
39- GCMParameterSpec gcmParameterSpec = new GCMParameterSpec (TAG_LENGTH_IN_BITS , iv );
37+ AlgorithmSuite algorithmSuite = materials .algorithmSuite ();
38+ byte [] nonce = new byte [NONCE_LENGTH_BYTES ];
39+ secureRandom .nextBytes (nonce );
40+ GCMParameterSpec gcmParameterSpec = new GCMParameterSpec (TAG_LENGTH_BITS , nonce );
4041
4142 final Cipher cipher = Cipher .getInstance (CIPHER_ALGORITHM );
4243 cipher .init (Cipher .ENCRYPT_MODE , _wrappingKey , gcmParameterSpec , secureRandom );
4344
4445 // this is the CONTENT encryption, not the wrapping encryption
45- // TODO: get this from encryption context or preferably algorithm suite
46- cipher .updateAAD ("AES/GCM/NoPadding" .getBytes (StandardCharsets .UTF_8 ));
46+ cipher .updateAAD (algorithmSuite .cipherName ().getBytes (StandardCharsets .UTF_8 ));
4747
4848 // The encrypted data key is the IV prepended to the ciphertext
49- iv = cipher .getIV ();
49+ nonce = cipher .getIV ();
5050 byte [] ciphertext = cipher .doFinal (materials .plaintextDataKey ());
5151
52- byte [] encodedBytes = new byte [iv .length + ciphertext .length ];
53- System .arraycopy (iv , 0 , encodedBytes , 0 , iv .length );
54- System .arraycopy (ciphertext , 0 , encodedBytes , iv .length , ciphertext .length );
52+ byte [] encodedBytes = new byte [nonce .length + ciphertext .length ];
53+ System .arraycopy (nonce , 0 , encodedBytes , 0 , nonce .length );
54+ System .arraycopy (ciphertext , 0 , encodedBytes , nonce .length , ciphertext .length );
5555
5656 EncryptedDataKey encryptedDataKey = EncryptedDataKey .builder ()
5757 .keyProviderId (KEY_PROVIDER_ID )
@@ -65,30 +65,12 @@ public EncryptionMaterials onEncrypt(EncryptionMaterials materials) {
6565 .encryptedDataKeys (encryptedDataKeys )
6666 .build ();
6767 } catch (Exception e ) {
68- throw new UnsupportedOperationException ("Unable to AES/GCM/NoPadding wrap" , e );
68+ throw new UnsupportedOperationException ("Unable to " + CIPHER_ALGORITHM + " wrap" , e );
6969 }
7070 }
7171
7272 @ Override
7373 public DecryptionMaterials onDecrypt (final DecryptionMaterials materials , List <EncryptedDataKey > encryptedDataKeys ) {
74- /*
75- ByteBuffer encryptedCekBuff = ByteBuffer.wrap(encryptedCek);
76- // Split the IV from the front of the ciphertext
77- byte[] iv = new byte[IV_LENGTH_IN_BYTES];
78- byte[] taggedCek = new byte[encryptedCek.length - IV_LENGTH_IN_BYTES];
79- encryptedCekBuff.get(iv);
80- encryptedCekBuff.get(taggedCek);
81-
82- Cipher cipher = this.cipherProvider.createCipher();
83- GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(TAG_LENGTH_IN_BITS, iv);
84- try {
85- cipher.init(Cipher.DECRYPT_MODE, key, gcmParameterSpec);
86- cipher.updateAAD(this.cekAlgorithm.getBytes(StandardCharsets.UTF_8));
87- return cipher.doFinal(taggedCek);
88- } catch (Exception e) {
89- throw failure(e, "An exception was thrown when attempting to decrypt the Content Encryption Key");
90- }
91- */
9274 if (materials .plaintextDataKey () != null ) {
9375 return materials ;
9476 }
@@ -99,25 +81,26 @@ public DecryptionMaterials onDecrypt(final DecryptionMaterials materials, List<E
9981 }
10082
10183 byte [] encodedBytes = encryptedDataKey .ciphertext ();
102- byte [] iv = new byte [IV_LENGTH_IN_BYTES ];
103- byte [] ciphertext = new byte [encodedBytes .length - iv .length ];
84+ byte [] nonce = new byte [NONCE_LENGTH_BYTES ];
85+ byte [] ciphertext = new byte [encodedBytes .length - nonce .length ];
86+
87+ System .arraycopy (encodedBytes , 0 , nonce , 0 , nonce .length );
88+ System .arraycopy (encodedBytes , nonce .length , ciphertext , 0 , ciphertext .length );
10489
105- System .arraycopy (encodedBytes , 0 , iv , 0 , iv .length );
106- System .arraycopy (encodedBytes , iv .length , ciphertext , 0 , ciphertext .length );
10790
108- GCMParameterSpec gcmParameterSpec = new GCMParameterSpec (TAG_LENGTH_IN_BITS , iv );
91+ GCMParameterSpec gcmParameterSpec = new GCMParameterSpec (TAG_LENGTH_BITS , nonce );
10992 try {
11093 final Cipher cipher = Cipher .getInstance (CIPHER_ALGORITHM );
11194 cipher .init (Cipher .DECRYPT_MODE , _wrappingKey , gcmParameterSpec );
11295 // this is the CONTENT encryption, not the wrapping encryption
113- // TODO: get this from encryption context or preferably algorithm suite
114- cipher .updateAAD ("AES/GCM/NoPadding" .getBytes (StandardCharsets .UTF_8 ));
96+ AlgorithmSuite algorithmSuite = materials . algorithmSuite ();
97+ cipher .updateAAD (algorithmSuite . cipherName () .getBytes (StandardCharsets .UTF_8 ));
11598 byte [] plaintext = cipher .doFinal (ciphertext );
11699
117100 return materials .toBuilder ().plaintextDataKey (plaintext ).build ();
118101 } catch (Exception e ) {
119102 // TODO: maybe this should fall through?
120- throw new UnsupportedOperationException ("Unable to AES/GCM/NoPadding unwrap" , e );
103+ throw new UnsupportedOperationException ("Unable to " + CIPHER_ALGORITHM + " unwrap" , e );
121104 }
122105 }
123106
0 commit comments