Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for encryption algorithms for symmetric keys #17209

Merged
merged 13 commits into from
Nov 13, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2418,8 +2418,8 @@
<!-- Service accepts null byte arrays as input parameters -->
<Match>
<Or>
<Class name="com.azure.security.keyvault.keys.cryptography.DecryptOptions" />
<Class name="com.azure.security.keyvault.keys.cryptography.EncryptOptions" />
<Class name="com.azure.security.keyvault.keys.cryptography.options.DecryptOptions" />
<Class name="com.azure.security.keyvault.keys.cryptography.options.EncryptOptions" />
</Or>
<Bug pattern="PZLA_PREFER_ZERO_LENGTH_ARRAYS" />
</Match>
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import com.azure.security.keyvault.keys.cryptography.models.SignResult;
import com.azure.security.keyvault.keys.cryptography.models.VerifyResult;
import com.azure.security.keyvault.keys.cryptography.models.WrapResult;
import com.azure.security.keyvault.keys.cryptography.options.DecryptOptions;
vcolin7 marked this conversation as resolved.
Show resolved Hide resolved
import com.azure.security.keyvault.keys.cryptography.options.EncryptOptions;
import com.azure.security.keyvault.keys.models.KeyVaultKey;
import com.azure.security.keyvault.keys.models.JsonWebKey;
import com.azure.security.keyvault.keys.models.KeyOperation;
Expand Down Expand Up @@ -223,7 +225,7 @@ Mono<JsonWebKey> getSecretKey() {
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono<EncryptResult> encrypt(EncryptionAlgorithm algorithm, byte[] plaintext) {
return encrypt(algorithm, plaintext, null);
return encrypt(EncryptOptions.createOptions(algorithm, plaintext), null);
}

/**
Expand All @@ -248,43 +250,37 @@ public Mono<EncryptResult> encrypt(EncryptionAlgorithm algorithm, byte[] plainte
* <p><strong>Code Samples</strong></p>
* <p>Encrypts the content. Subscribes to the call asynchronously and prints out the encrypted content details when
* a response has been received.</p>
* {@codesnippet com.azure.security.keyvault.keys.cryptography.CryptographyAsyncClient.encrypt#EncryptionAlgorithm-byte-EncryptOptions}
* {@codesnippet com.azure.security.keyvault.keys.cryptography.CryptographyAsyncClient.encrypt#EncryptOptions}
*
* @param algorithm The algorithm to be used for encryption.
* @param plaintext The content to be encrypted.
* @param options Optional parameters for the encryption operation.
* @param encryptOptions The parameters to use in the encryption operation.
* @return A {@link Mono} containing a {@link EncryptResult} whose {@link EncryptResult#getCipherText() cipher text}
* contains the encrypted content.
* @throws ResourceNotFoundException If the key cannot be found for encryption.
* @throws UnsupportedOperationException If the encrypt operation is not supported or configured on the key.
* @throws NullPointerException If {@code algorithm} or {@code plainText} are {@code null}.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono<EncryptResult> encrypt(EncryptionAlgorithm algorithm, byte[] plaintext, EncryptOptions options) {
public Mono<EncryptResult> encrypt(EncryptOptions encryptOptions) {
try {
return withContext(context -> encrypt(algorithm, plaintext, options, context));
return withContext(context -> encrypt(encryptOptions, context));
} catch (RuntimeException ex) {
return monoError(logger, ex);
}
}


Mono<EncryptResult> encrypt(EncryptionAlgorithm algorithm, byte[] plaintext, EncryptOptions options,
Context context) {
Objects.requireNonNull(algorithm, "Encryption algorithm cannot be null.");
Objects.requireNonNull(plaintext, "Plain text content to be encrypted cannot be null.");

Mono<EncryptResult> encrypt(EncryptOptions encryptOptions, Context context) {
return ensureValidKeyAvailable().flatMap(available -> {
if (!available) {
return cryptographyServiceClient.encrypt(algorithm, plaintext, options, context);
return cryptographyServiceClient.encrypt(encryptOptions, context);
}

if (!checkKeyPermissions(this.key.getKeyOps(), KeyOperation.ENCRYPT)) {
return Mono.error(logger.logExceptionAsError(new UnsupportedOperationException(String.format(
"Encrypt Operation is missing permission/not supported for key with id %s", key.getId()))));
}

return localKeyCryptographyClient.encryptAsync(algorithm, plaintext, options, context, key);
return localKeyCryptographyClient.encryptAsync(encryptOptions, context, key);
});
}

Expand Down Expand Up @@ -321,7 +317,7 @@ Mono<EncryptResult> encrypt(EncryptionAlgorithm algorithm, byte[] plaintext, Enc
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono<DecryptResult> decrypt(EncryptionAlgorithm algorithm, byte[] cipherText) {
return decrypt(algorithm, cipherText, null);
return decrypt(DecryptOptions.createOptions(algorithm, cipherText));
}

/**
Expand All @@ -346,41 +342,35 @@ public Mono<DecryptResult> decrypt(EncryptionAlgorithm algorithm, byte[] cipherT
* <p><strong>Code Samples</strong></p>
* <p>Decrypts the encrypted content. Subscribes to the call asynchronously and prints out the decrypted content
* details when a response has been received.</p>
* {@codesnippet com.azure.security.keyvault.keys.cryptography.CryptographyAsyncClient.decrypt#EncryptionAlgorithm-byte-DecryptOptions}
* {@codesnippet com.azure.security.keyvault.keys.cryptography.CryptographyAsyncClient.decrypt#DecryptOptions}
*
* @param algorithm The algorithm to be used for decryption.
* @param cipherText The content to be decrypted.
* @param options Optional parameters for the decryption operation.
* @param decryptOptions The parameters to use in the decryption operation.
* @return A {@link Mono} containing the decrypted blob.
* @throws ResourceNotFoundException If the key cannot be found for decryption.
* @throws UnsupportedOperationException If the decrypt operation is not supported or configured on the key.
* @throws NullPointerException If {@code algorithm} or {@code cipherText} are {@code null}.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono<DecryptResult> decrypt(EncryptionAlgorithm algorithm, byte[] cipherText, DecryptOptions options) {
public Mono<DecryptResult> decrypt(DecryptOptions decryptOptions) {
try {
return withContext(context -> decrypt(algorithm, cipherText, options, context));
return withContext(context -> decrypt(decryptOptions, context));
} catch (RuntimeException ex) {
return monoError(logger, ex);
}
}

Mono<DecryptResult> decrypt(EncryptionAlgorithm algorithm, byte[] cipherText, DecryptOptions options,
Context context) {
Objects.requireNonNull(algorithm, "Encryption algorithm cannot be null.");
Objects.requireNonNull(cipherText, "Cipher text content to be decrypted cannot be null.");

Mono<DecryptResult> decrypt(DecryptOptions decryptOptions, Context context) {
return ensureValidKeyAvailable().flatMap(available -> {
if (!available) {
return cryptographyServiceClient.decrypt(algorithm, cipherText, options, context);
return cryptographyServiceClient.decrypt(decryptOptions, context);
}

if (!checkKeyPermissions(this.key.getKeyOps(), KeyOperation.DECRYPT)) {
return Mono.error(logger.logExceptionAsError(new UnsupportedOperationException(String.format(
"Decrypt Operation is not allowed for key with id %s", key.getId()))));
}

return localKeyCryptographyClient.decryptAsync(algorithm, cipherText, options, context, key);
return localKeyCryptographyClient.decryptAsync(decryptOptions, context, key);
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import com.azure.security.keyvault.keys.cryptography.models.SignResult;
import com.azure.security.keyvault.keys.cryptography.models.VerifyResult;
import com.azure.security.keyvault.keys.cryptography.models.WrapResult;
import com.azure.security.keyvault.keys.cryptography.options.DecryptOptions;
import com.azure.security.keyvault.keys.cryptography.options.EncryptOptions;
import com.azure.security.keyvault.keys.models.KeyVaultKey;


Expand Down Expand Up @@ -111,7 +113,7 @@ public Response<KeyVaultKey> getKeyWithResponse(Context context) {
* @throws NullPointerException If {@code algorithm} or {@code plainText} are {@code null}.
*/
public EncryptResult encrypt(EncryptionAlgorithm algorithm, byte[] plaintext, Context context) {
return encrypt(algorithm, plaintext, null, context);
return encrypt(EncryptOptions.createOptions(algorithm, plaintext), context);
}

/**
Expand Down Expand Up @@ -172,21 +174,18 @@ public EncryptResult encrypt(EncryptionAlgorithm algorithm, byte[] plaintext) {
* <p><strong>Code Samples</strong></p>
* <p>Encrypts the content. Subscribes to the call asynchronously and prints out the encrypted content details when
* a response has been received.</p>
* {@codesnippet com.azure.security.keyvault.keys.cryptography.CryptographyClient.encrypt#EncryptionAlgorithm-byte-EncryptOptions-Context}
* {@codesnippet com.azure.security.keyvault.keys.cryptography.CryptographyClient.encrypt#EncryptOptions-Context}
*
* @param algorithm The algorithm to be used for encryption.
* @param plaintext The content to be encrypted.
* @param options Optional parameters for the encryption operation.
* @param encryptOptions The parameters to use in the encryption operation.
* @param context Additional context that is passed through the Http pipeline during the service call.
* @return The {@link EncryptResult} whose {@link EncryptResult#getCipherText() cipher text} contains the encrypted
* content.
* @throws ResourceNotFoundException If the key cannot be found for encryption.
* @throws UnsupportedOperationException If the encrypt operation is not supported or configured on the key.
* @throws NullPointerException If {@code algorithm} or {@code plainText} are {@code null}.
*/
public EncryptResult encrypt(EncryptionAlgorithm algorithm, byte[] plaintext, EncryptOptions options,
Context context) {
return client.encrypt(algorithm, plaintext, options, context).block();
public EncryptResult encrypt(EncryptOptions encryptOptions, Context context) {
return client.encrypt(encryptOptions, context).block();
}

/**
Expand Down Expand Up @@ -222,7 +221,7 @@ public EncryptResult encrypt(EncryptionAlgorithm algorithm, byte[] plaintext, En
* @throws NullPointerException If {@code algorithm} or {@code cipherText} are {@code null}.
*/
public DecryptResult decrypt(EncryptionAlgorithm algorithm, byte[] cipherText, Context context) {
return decrypt(algorithm, cipherText, null, context);
return decrypt(DecryptOptions.createOptions(algorithm, cipherText), context);
}

/**
Expand Down Expand Up @@ -257,7 +256,7 @@ public DecryptResult decrypt(EncryptionAlgorithm algorithm, byte[] cipherText, C
* @throws NullPointerException If {@code algorithm} or {@code cipherText} are {@code null}.
*/
public DecryptResult decrypt(EncryptionAlgorithm algorithm, byte[] cipherText) {
return decrypt(algorithm, cipherText, Context.NONE);
return decrypt(DecryptOptions.createOptions(algorithm, cipherText), Context.NONE);
}

/**
Expand All @@ -282,20 +281,17 @@ public DecryptResult decrypt(EncryptionAlgorithm algorithm, byte[] cipherText) {
* <p><strong>Code Samples</strong></p>
* <p>Decrypts the encrypted content. Subscribes to the call asynchronously and prints out the decrypted content
* details when a response has been received.</p>
* {@codesnippet com.azure.security.keyvault.keys.cryptography.CryptographyClient.decrypt#EncryptionAlgorithm-byte-DecryptOptions-Context}
* {@codesnippet com.azure.security.keyvault.keys.cryptography.CryptographyClient.decrypt#DecryptOptions-Context}
*
* @param algorithm The algorithm to be used for decryption.
* @param cipherText The content to be decrypted.
* @param options Optional parameters for the decryption operation.
* @param decryptOptions The parameters to use in the decryption operation.
* @param context Additional context that is passed through the Http pipeline during the service call.
* @return The decrypted blob.
* @throws ResourceNotFoundException If the key cannot be found for encryption.
* @throws UnsupportedOperationException If the decrypt operation is not supported or configured on the key.
* @throws NullPointerException If {@code algorithm} or {@code cipherText} are {@code null}.
*/
public DecryptResult decrypt(EncryptionAlgorithm algorithm, byte[] cipherText, DecryptOptions options,
Context context) {
return client.decrypt(algorithm, cipherText, options, context).block();
public DecryptResult decrypt(DecryptOptions decryptOptions, Context context) {
return client.decrypt(decryptOptions, context).block();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
import com.azure.security.keyvault.keys.cryptography.models.SignResult;
import com.azure.security.keyvault.keys.cryptography.models.VerifyResult;
import com.azure.security.keyvault.keys.cryptography.models.WrapResult;
import com.azure.security.keyvault.keys.cryptography.options.DecryptOptions;
import com.azure.security.keyvault.keys.cryptography.options.EncryptOptions;
import com.azure.security.keyvault.keys.models.JsonWebKey;
import com.azure.security.keyvault.keys.models.KeyOperation;
import com.azure.security.keyvault.keys.models.KeyType;
Expand Down Expand Up @@ -125,19 +127,17 @@ JsonWebKey transformSecretKey(SecretKey secretKey) throws JsonProcessingExceptio
return mapper.readValue(jsonString, JsonWebKey.class);
}

Mono<EncryptResult> encrypt(EncryptionAlgorithm algorithm, byte[] plaintext, EncryptOptions options,
Context context) {
byte[] iv = null;
byte[] authenticatedData = null;

if (options != null) {
iv = options.getIv();
authenticatedData = options.getAdditionalAuthenticatedData();
}
Mono<EncryptResult> encrypt(EncryptOptions encryptOptions, Context context) {
Objects.requireNonNull(encryptOptions, "'encryptOptions' cannot be null.");
Objects.requireNonNull(encryptOptions.getAlgorithm(), "Encryption algorithm cannot be null.");
Objects.requireNonNull(encryptOptions.getPlainText(), "Plain text content to be encrypted cannot be null.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: it's actually "plaintext" in crypto-speak.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll keep it as "plaintext" in the new code. Unfortunately, there's a couple APIs [1][2] that have already GA'd using plainText,

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After talking to @JonathanGiles, in this case he thinks is it's better we remain consistent with what's already been GA'd, given that the difference in capitalization does not make it confusing to understand what the terms refer to.


EncryptionAlgorithm algorithm = encryptOptions.getAlgorithm();
byte[] iv = encryptOptions.getIv();
byte[] authenticatedData = encryptOptions.getAdditionalAuthenticatedData();
KeyOperationParameters parameters = new KeyOperationParameters()
.setAlgorithm(algorithm)
.setValue(plaintext)
.setValue(encryptOptions.getPlainText())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On that note, I guess I missed this before, but just getPlaintext (it's one word).

.setIv(iv)
.setAdditionalAuthenticatedData(authenticatedData);
context = context == null ? Context.NONE : context;
Expand All @@ -153,21 +153,18 @@ Mono<EncryptResult> encrypt(EncryptionAlgorithm algorithm, byte[] plaintext, Enc
Mono.just(new EncryptResult(keyOperationResultResponse.getValue().getResult(), algorithm, keyId)));
}

Mono<DecryptResult> decrypt(EncryptionAlgorithm algorithm, byte[] cipherText, DecryptOptions options,
Context context) {
byte[] iv = null;
byte[] additionalAuthenticatedData = null;
byte[] authenticationTag = null;

if (options != null) {
iv = options.getIv();
additionalAuthenticatedData = options.getAdditionalAuthenticatedData();
authenticationTag = options.getAuthenticationTag();
}
Mono<DecryptResult> decrypt(DecryptOptions decryptOptions, Context context) {
Objects.requireNonNull(decryptOptions, "'decryptOptions' cannot be null.");
Objects.requireNonNull(decryptOptions.getAlgorithm(), "Encryption algorithm cannot be null.");
Objects.requireNonNull(decryptOptions.getCipherText(), "Cipher text content to be decrypted cannot be null.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getCiphertext (one word)


EncryptionAlgorithm algorithm = decryptOptions.getAlgorithm();
byte[] iv = decryptOptions.getIv();
byte[] additionalAuthenticatedData = decryptOptions.getAdditionalAuthenticatedData();
byte[] authenticationTag = decryptOptions.getAuthenticationTag();
KeyOperationParameters parameters = new KeyOperationParameters()
.setAlgorithm(algorithm)
.setValue(cipherText)
.setValue(decryptOptions.getCipherText())
.setIv(iv)
.setAdditionalAuthenticatedData(additionalAuthenticatedData)
.setAuthenticationTag(authenticationTag);
Expand Down
Loading