Skip to content

Commit 6a6d63d

Browse files
committed
Add AESWrap legacy keyring
1 parent 113b784 commit 6a6d63d

File tree

1 file changed

+94
-0
lines changed

1 file changed

+94
-0
lines changed
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package software.amazon.encryption.s3.legacy.materials;
2+
3+
import java.security.Key;
4+
import java.util.List;
5+
import javax.crypto.Cipher;
6+
import javax.crypto.SecretKey;
7+
import software.amazon.encryption.s3.S3EncryptionClientException;
8+
import software.amazon.encryption.s3.materials.DecryptionMaterials;
9+
import software.amazon.encryption.s3.materials.EncryptedDataKey;
10+
import software.amazon.encryption.s3.materials.EncryptionMaterials;
11+
import software.amazon.encryption.s3.materials.Keyring;
12+
13+
/**
14+
* AesWrapKeyring is a legacy, decrypt-only keyring and will use an AES key to unwrap the data key
15+
* used to encrypt content.
16+
*/
17+
public class AesWrapKeyring implements Keyring {
18+
19+
private static final String KEY_ALGORITHM = "AES";
20+
private static final String KEY_PROVIDER_ID = "AESWrap";
21+
private static final String CIPHER_ALGORITHM = "AESWrap";
22+
23+
private final SecretKey _wrappingKey;
24+
private final Keyring _nonLegacyKeyring;
25+
26+
private AesWrapKeyring(Builder builder) {
27+
_wrappingKey = builder._wrappingKey;
28+
_nonLegacyKeyring = builder._nonLegacyKeyring;
29+
}
30+
31+
public static Builder builder() {
32+
return new Builder();
33+
}
34+
35+
@Override
36+
public EncryptionMaterials onEncrypt(EncryptionMaterials materials) {
37+
return _nonLegacyKeyring.onEncrypt(materials);
38+
}
39+
40+
@Override
41+
public DecryptionMaterials onDecrypt(DecryptionMaterials materials, List<EncryptedDataKey> encryptedDataKeys) {
42+
materials = _nonLegacyKeyring.onDecrypt(materials, encryptedDataKeys);
43+
44+
if (materials.plaintextDataKey() != null) {
45+
return materials;
46+
}
47+
48+
for (EncryptedDataKey encryptedDataKey : encryptedDataKeys) {
49+
if (!encryptedDataKey.keyProviderId().equals(KEY_PROVIDER_ID)) {
50+
continue;
51+
}
52+
53+
try {
54+
final Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
55+
cipher.init(Cipher.UNWRAP_MODE, _wrappingKey);
56+
57+
Key plaintextKey = cipher.unwrap(encryptedDataKey.ciphertext(), CIPHER_ALGORITHM, Cipher.SECRET_KEY);
58+
59+
return materials.toBuilder().plaintextDataKey(plaintextKey.getEncoded()).build();
60+
} catch (Exception e) {
61+
throw new S3EncryptionClientException("Unable to " + KEY_PROVIDER_ID + " unwrap", e);
62+
}
63+
}
64+
65+
return materials;
66+
}
67+
68+
public static class Builder {
69+
private SecretKey _wrappingKey;
70+
private Keyring _nonLegacyKeyring;
71+
72+
private Builder() {}
73+
74+
public Builder wrappingKey(SecretKey wrappingKey) {
75+
if (!wrappingKey.getAlgorithm().equals(KEY_ALGORITHM)) {
76+
throw new S3EncryptionClientException("Invalid algorithm '" + wrappingKey.getAlgorithm() + "', expecting " + KEY_ALGORITHM);
77+
}
78+
_wrappingKey = wrappingKey;
79+
return this;
80+
}
81+
82+
public Builder nonLegacyKeyring(Keyring nonLegacyKeyring) {
83+
_nonLegacyKeyring = nonLegacyKeyring;
84+
return this;
85+
}
86+
87+
public AesWrapKeyring build() {
88+
if (_nonLegacyKeyring == null) {
89+
// TODO: should we warn or throw an exception if no encryption method is supported?
90+
}
91+
return new AesWrapKeyring(this);
92+
}
93+
}
94+
}

0 commit comments

Comments
 (0)