Skip to content

Commit c24325c

Browse files
authored
Fixes to local and remote cryptography in Key Vault Keys (Azure#19485)
* Fixed issue that caused an NPE when attempting to use a CryptographyClient for GCM encryption. * Fixed issue where properties of responses received when using a CryptographyClient for encryption/decryption were not serialized/deserialized and populated properly into the EncryptResult and DecryptResult classes. * Fixed local GCM encryption/decryption, as it was implemented incorrectly. Also made sure that EncryptResult and DecryptResult produced by these operations contain the right data. * Fixed checkstyle issues. * Applied PR feedback. * Applied PR feedback.
1 parent 191eafd commit c24325c

File tree

8 files changed

+202
-86
lines changed

8 files changed

+202
-86
lines changed

sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/cryptography/AesGcm.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
import java.util.Arrays;
1717
import java.util.Objects;
1818

19+
import static com.azure.security.keyvault.keys.cryptography.SymmetricKeyCryptographyClient.AES_BLOCK_SIZE;
20+
1921
abstract class AesGcm extends SymmetricEncryptionAlgorithm {
2022
final int keySizeInBytes;
2123
final int keySize;
@@ -42,8 +44,14 @@ static class AesGcmEncryptor implements ICryptoTransform {
4244
cipher = Cipher.getInstance("AES/GCM/NoPadding", provider);
4345
}
4446

47+
int tagLength = (authenticationTag == null) ? AES_BLOCK_SIZE : authenticationTag.length;
48+
4549
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"),
46-
new GCMParameterSpec(authenticationTag.length << 3, iv));
50+
new GCMParameterSpec(tagLength << 3, iv));
51+
52+
if (additionalAuthenticatedData != null) {
53+
cipher.updateAAD(additionalAuthenticatedData);
54+
}
4755
}
4856

4957
@Override
@@ -67,11 +75,14 @@ static class AesGcmDecryptor implements ICryptoTransform {
6775
cipher = Cipher.getInstance("AES/GCM/NoPadding", provider);
6876
}
6977

70-
7178
Objects.requireNonNull(authenticationTag, "'authenticationTag' cannot be null");
7279

7380
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"),
7481
new GCMParameterSpec(authenticationTag.length << 3, iv));
82+
83+
if (additionalAuthenticatedData != null) {
84+
cipher.updateAAD(additionalAuthenticatedData);
85+
}
7586
}
7687

7788
@Override

sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/cryptography/CryptographyAsyncClient.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -714,8 +714,9 @@ private boolean checkKeyPermissions(List<KeyOperation> operations, KeyOperation
714714

715715
private Mono<Boolean> ensureValidKeyAvailable() {
716716
boolean keyNotAvailable = (key == null && keyCollection != null);
717+
boolean keyNotValid = (key != null && !key.isValid());
717718

718-
if (keyNotAvailable) {
719+
if (keyNotAvailable || keyNotValid) {
719720
if (keyCollection.equals(SECRETS_COLLECTION)) {
720721
return getSecretKey().map(jsonWebKey -> {
721722
key = (jsonWebKey);

sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/cryptography/CryptographyServiceClient.java

Lines changed: 34 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -129,48 +129,44 @@ Mono<EncryptResult> encrypt(EncryptOptions encryptOptions, Context context) {
129129
Objects.requireNonNull(encryptOptions, "'encryptOptions' cannot be null.");
130130

131131
EncryptionAlgorithm algorithm = encryptOptions.getAlgorithm();
132-
byte[] iv = encryptOptions.getIv();
133-
byte[] authenticatedData = encryptOptions.getAdditionalAuthenticatedData();
134132
KeyOperationParameters parameters = new KeyOperationParameters()
135133
.setAlgorithm(algorithm)
136134
.setValue(encryptOptions.getPlainText())
137-
.setIv(iv)
138-
.setAdditionalAuthenticatedData(authenticatedData);
135+
.setIv(encryptOptions.getIv())
136+
.setAdditionalAuthenticatedData(encryptOptions.getAdditionalAuthenticatedData());
139137
context = context == null ? Context.NONE : context;
140138

141139
return service.encrypt(vaultUrl, keyName, version, apiVersion, ACCEPT_LANGUAGE, parameters,
142140
CONTENT_TYPE_HEADER_VALUE, context.addData(AZ_TRACING_NAMESPACE_KEY, KEYVAULT_TRACING_NAMESPACE_VALUE))
143-
.doOnRequest(ignored -> logger.info("Encrypting content with algorithm - {}", algorithm.toString()))
144-
.doOnSuccess(response -> logger.info("Retrieved encrypted content with algorithm- {}",
145-
algorithm.toString()))
146-
.doOnError(error -> logger.warning("Failed to encrypt content with algorithm - {}", algorithm.toString(),
147-
error))
148-
.flatMap(keyOperationResultResponse ->
149-
Mono.just(new EncryptResult(keyOperationResultResponse.getValue().getResult(), algorithm, keyId)));
141+
.doOnRequest(ignored -> logger.info("Encrypting content with algorithm - {}", algorithm))
142+
.doOnSuccess(response -> logger.info("Retrieved encrypted content with algorithm - {}", algorithm))
143+
.doOnError(error -> logger.warning("Failed to encrypt content with algorithm - {}", algorithm, error))
144+
.map(keyOperationResultResponse -> {
145+
KeyOperationResult keyOperationResult = keyOperationResultResponse.getValue();
146+
147+
return new EncryptResult(keyOperationResult.getResult(), algorithm, keyId,
148+
keyOperationResult.getIv(), keyOperationResult.getAdditionalAuthenticatedData(),
149+
keyOperationResult.getAuthenticationTag());
150+
});
150151
}
151152

152153
Mono<DecryptResult> decrypt(DecryptOptions decryptOptions, Context context) {
153154
Objects.requireNonNull(decryptOptions, "'decryptOptions' cannot be null.");
154155

155156
EncryptionAlgorithm algorithm = decryptOptions.getAlgorithm();
156-
byte[] iv = decryptOptions.getIv();
157-
byte[] additionalAuthenticatedData = decryptOptions.getAdditionalAuthenticatedData();
158-
byte[] authenticationTag = decryptOptions.getAuthenticationTag();
159157
KeyOperationParameters parameters = new KeyOperationParameters()
160158
.setAlgorithm(algorithm)
161159
.setValue(decryptOptions.getCipherText())
162-
.setIv(iv)
163-
.setAdditionalAuthenticatedData(additionalAuthenticatedData)
164-
.setAuthenticationTag(authenticationTag);
160+
.setIv(decryptOptions.getIv())
161+
.setAdditionalAuthenticatedData(decryptOptions.getAdditionalAuthenticatedData())
162+
.setAuthenticationTag(decryptOptions.getAuthenticationTag());
165163
context = context == null ? Context.NONE : context;
166164

167165
return service.decrypt(vaultUrl, keyName, version, apiVersion, ACCEPT_LANGUAGE, parameters,
168166
CONTENT_TYPE_HEADER_VALUE, context.addData(AZ_TRACING_NAMESPACE_KEY, KEYVAULT_TRACING_NAMESPACE_VALUE))
169-
.doOnRequest(ignored -> logger.info("Decrypting content with algorithm - {}", algorithm.toString()))
170-
.doOnSuccess(response -> logger.info("Retrieved decrypted content with algorithm- {}",
171-
algorithm.toString()))
172-
.doOnError(error -> logger.warning("Failed to decrypt content with algorithm - {}", algorithm.toString(),
173-
error))
167+
.doOnRequest(ignored -> logger.info("Decrypting content with algorithm - {}", algorithm))
168+
.doOnSuccess(response -> logger.info("Retrieved decrypted content with algorithm - {}", algorithm))
169+
.doOnError(error -> logger.warning("Failed to decrypt content with algorithm - {}", algorithm, error))
174170
.flatMap(keyOperationResultResponse -> Mono.just(
175171
new DecryptResult(keyOperationResultResponse.getValue().getResult(), algorithm, keyId)));
176172
}
@@ -180,27 +176,25 @@ Mono<SignResult> sign(SignatureAlgorithm algorithm, byte[] digest, Context conte
180176
context = context == null ? Context.NONE : context;
181177
return service.sign(vaultUrl, keyName, version, apiVersion, ACCEPT_LANGUAGE, parameters,
182178
CONTENT_TYPE_HEADER_VALUE, context.addData(AZ_TRACING_NAMESPACE_KEY, KEYVAULT_TRACING_NAMESPACE_VALUE))
183-
.doOnRequest(ignored -> logger.info("Signing content with algorithm - {}", algorithm.toString()))
184-
.doOnSuccess(response -> logger.info("Retrieved signed content with algorithm- {}", algorithm.toString()))
185-
.doOnError(error -> logger.warning("Failed to sign content with algorithm - {}", algorithm.toString(),
186-
error))
179+
.doOnRequest(ignored -> logger.info("Signing content with algorithm - {}", algorithm))
180+
.doOnSuccess(response -> logger.info("Retrieved signed content with algorithm - {}", algorithm))
181+
.doOnError(error -> logger.warning("Failed to sign content with algorithm - {}", algorithm, error))
187182
.flatMap(keyOperationResultResponse ->
188183
Mono.just(new SignResult(keyOperationResultResponse.getValue().getResult(), algorithm, keyId)));
189184
}
190185

191186
Mono<VerifyResult> verify(SignatureAlgorithm algorithm, byte[] digest, byte[] signature, Context context) {
192187

193-
KeyVerifyRequest parameters = new KeyVerifyRequest().setAlgorithm(algorithm).setDigest(digest).setSignature(signature);
188+
KeyVerifyRequest parameters =
189+
new KeyVerifyRequest().setAlgorithm(algorithm).setDigest(digest).setSignature(signature);
194190
context = context == null ? Context.NONE : context;
195191

196192
return service.verify(vaultUrl, keyName, version, apiVersion, ACCEPT_LANGUAGE, parameters,
197193
CONTENT_TYPE_HEADER_VALUE, context.addData(AZ_TRACING_NAMESPACE_KEY, KEYVAULT_TRACING_NAMESPACE_VALUE))
198-
.doOnRequest(ignored -> logger.info("Verifying content with algorithm - {}", algorithm.toString()))
199-
.doOnSuccess(response -> logger.info("Retrieved verified content with algorithm- {}", algorithm.toString()))
200-
.doOnError(error -> logger.warning("Failed to verify content with algorithm - {}", algorithm.toString(),
201-
error))
202-
.flatMap(response ->
203-
Mono.just(new VerifyResult(response.getValue().getValue(), algorithm, keyId)));
194+
.doOnRequest(ignored -> logger.info("Verifying content with algorithm - {}", algorithm))
195+
.doOnSuccess(response -> logger.info("Retrieved verified content with algorithm - {}", algorithm))
196+
.doOnError(error -> logger.warning("Failed to verify content with algorithm - {}", algorithm, error))
197+
.flatMap(response -> Mono.just(new VerifyResult(response.getValue().getValue(), algorithm, keyId)));
204198
}
205199

206200
Mono<WrapResult> wrapKey(KeyWrapAlgorithm algorithm, byte[] key, Context context) {
@@ -211,31 +205,25 @@ Mono<WrapResult> wrapKey(KeyWrapAlgorithm algorithm, byte[] key, Context context
211205

212206
return service.wrapKey(vaultUrl, keyName, version, apiVersion, ACCEPT_LANGUAGE, parameters,
213207
CONTENT_TYPE_HEADER_VALUE, context.addData(AZ_TRACING_NAMESPACE_KEY, KEYVAULT_TRACING_NAMESPACE_VALUE))
214-
.doOnRequest(ignored -> logger.info("Wrapping key content with algorithm - {}", algorithm.toString()))
215-
.doOnSuccess(response -> logger.info("Retrieved wrapped key content with algorithm- {}",
216-
algorithm.toString()))
217-
.doOnError(error -> logger.warning("Failed to verify content with algorithm - {}", algorithm.toString(),
218-
error))
208+
.doOnRequest(ignored -> logger.info("Wrapping key content with algorithm - {}", algorithm))
209+
.doOnSuccess(response -> logger.info("Retrieved wrapped key content with algorithm - {}", algorithm))
210+
.doOnError(error -> logger.warning("Failed to verify content with algorithm - {}", algorithm, error))
219211
.flatMap(keyOperationResultResponse ->
220212
Mono.just(new WrapResult(keyOperationResultResponse.getValue().getResult(), algorithm, keyId)));
221213
}
222214

223215
Mono<UnwrapResult> unwrapKey(KeyWrapAlgorithm algorithm, byte[] encryptedKey, Context context) {
224-
225216
KeyWrapUnwrapRequest parameters = new KeyWrapUnwrapRequest()
226217
.setAlgorithm(algorithm)
227218
.setValue(encryptedKey);
228219
context = context == null ? Context.NONE : context;
229220

230221
return service.unwrapKey(vaultUrl, keyName, version, apiVersion, ACCEPT_LANGUAGE, parameters,
231222
CONTENT_TYPE_HEADER_VALUE, context.addData(AZ_TRACING_NAMESPACE_KEY, KEYVAULT_TRACING_NAMESPACE_VALUE))
232-
.doOnRequest(ignored -> logger.info("Unwrapping key content with algorithm - {}", algorithm.toString()))
233-
.doOnSuccess(response -> logger.info("Retrieved unwrapped key content with algorithm- {}",
234-
algorithm.toString()))
235-
.doOnError(error -> logger.warning("Failed to unwrap key content with algorithm - {}",
236-
algorithm.toString(), error))
237-
.flatMap(response ->
238-
Mono.just(new UnwrapResult(response.getValue().getResult(), algorithm, keyId)));
223+
.doOnRequest(ignored -> logger.info("Unwrapping key content with algorithm - {}", algorithm))
224+
.doOnSuccess(response -> logger.info("Retrieved unwrapped key content with algorithm - {}", algorithm))
225+
.doOnError(error -> logger.warning("Failed to unwrap key content with algorithm - {}", algorithm, error))
226+
.flatMap(response -> Mono.just(new UnwrapResult(response.getValue().getResult(), algorithm, keyId)));
239227
}
240228

241229

sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/cryptography/KeyOperationParameters.java

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111
* The key operations parameters.
1212
*/
1313
class KeyOperationParameters {
14+
private static final byte[] EMPTY_ARRAY = new byte[0];
15+
1416
/**
15-
* algorithm identifier. Possible values include: 'RSA-OAEP',
17+
* Algorithm identifier. Possible values include: 'RSA-OAEP',
1618
* 'RSA-OAEP-256', 'RSA1_5'.
1719
*/
1820
@JsonProperty(value = "alg", required = true)
@@ -28,19 +30,19 @@ class KeyOperationParameters {
2830
* Initialization vector for symmetric algorithms.
2931
*/
3032
@JsonProperty(value = "iv")
31-
private byte[] iv;
33+
private Base64Url iv;
3234

3335
/**
3436
* Additional data to authenticate but not encrypt/decrypt when using authenticated crypto algorithms.
3537
*/
3638
@JsonProperty(value = "aad")
37-
private byte[] additionalAuthenticatedData;
39+
private Base64Url additionalAuthenticatedData;
3840

3941
/**
4042
* The tag to authenticate when performing decryption with an authenticated algorithm.
4143
*/
4244
@JsonProperty(value = "tag")
43-
private byte[] authenticationTag;
45+
private Base64Url authenticationTag;
4446

4547
/**
4648
* Get the algorithm value.
@@ -59,6 +61,7 @@ public EncryptionAlgorithm getAlgorithm() {
5961
*/
6062
public KeyOperationParameters setAlgorithm(EncryptionAlgorithm algorithm) {
6163
this.algorithm = algorithm;
64+
6265
return this;
6366
}
6467

@@ -69,8 +72,9 @@ public KeyOperationParameters setAlgorithm(EncryptionAlgorithm algorithm) {
6972
*/
7073
public byte[] getValue() {
7174
if (this.value == null) {
72-
return new byte[0];
75+
return EMPTY_ARRAY;
7376
}
77+
7478
return this.value.decodedBytes();
7579
}
7680

@@ -81,11 +85,8 @@ public byte[] getValue() {
8185
* @return the KeyOperationsParameters object itself.
8286
*/
8387
public KeyOperationParameters setValue(byte[] value) {
84-
if (value == null) {
85-
this.value = null;
86-
} else {
87-
this.value = Base64Url.encode(value);
88-
}
88+
this.value = value != null ? Base64Url.encode(value) : null;
89+
8990
return this;
9091
}
9192

@@ -95,7 +96,11 @@ public KeyOperationParameters setValue(byte[] value) {
9596
* @return The initialization vector.
9697
*/
9798
public byte[] getIv() {
98-
return iv;
99+
if (this.iv == null) {
100+
return EMPTY_ARRAY;
101+
}
102+
103+
return this.iv.decodedBytes();
99104
}
100105

101106
/**
@@ -105,7 +110,8 @@ public byte[] getIv() {
105110
* @return The updated {@link KeyOperationParameters} object.
106111
*/
107112
public KeyOperationParameters setIv(byte[] iv) {
108-
this.iv = iv;
113+
this.iv = iv != null ? Base64Url.encode(iv) : null;
114+
109115
return this;
110116
}
111117

@@ -115,7 +121,11 @@ public KeyOperationParameters setIv(byte[] iv) {
115121
* @return The additional authenticated data.
116122
*/
117123
public byte[] getAdditionalAuthenticatedData() {
118-
return additionalAuthenticatedData;
124+
if (this.additionalAuthenticatedData == null) {
125+
return EMPTY_ARRAY;
126+
}
127+
128+
return this.additionalAuthenticatedData.decodedBytes();
119129
}
120130

121131
/**
@@ -125,7 +135,9 @@ public byte[] getAdditionalAuthenticatedData() {
125135
* @return The updated {@link KeyOperationParameters} object.
126136
*/
127137
public KeyOperationParameters setAdditionalAuthenticatedData(byte[] additionalAuthenticatedData) {
128-
this.additionalAuthenticatedData = additionalAuthenticatedData;
138+
this.additionalAuthenticatedData =
139+
additionalAuthenticatedData != null ? Base64Url.encode(additionalAuthenticatedData) : null;
140+
129141
return this;
130142
}
131143

@@ -135,7 +147,11 @@ public KeyOperationParameters setAdditionalAuthenticatedData(byte[] additionalAu
135147
* @return The authentication tag.
136148
*/
137149
public byte[] getAuthenticationTag() {
138-
return authenticationTag;
150+
if (this.authenticationTag == null) {
151+
return EMPTY_ARRAY;
152+
}
153+
154+
return this.authenticationTag.decodedBytes();
139155
}
140156

141157
/**
@@ -145,7 +161,8 @@ public byte[] getAuthenticationTag() {
145161
* @return The updated {@link KeyOperationParameters} object.
146162
*/
147163
public KeyOperationParameters setAuthenticationTag(byte[] authenticationTag) {
148-
this.authenticationTag = authenticationTag;
164+
this.authenticationTag = authenticationTag != null ? Base64Url.encode(authenticationTag) : null;
165+
149166
return this;
150167
}
151168
}

0 commit comments

Comments
 (0)