diff --git a/sdk/keyvault/azure-security-keyvault-keys/CHANGELOG.md b/sdk/keyvault/azure-security-keyvault-keys/CHANGELOG.md index 69c58f77e782..8d96ecee184c 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/CHANGELOG.md +++ b/sdk/keyvault/azure-security-keyvault-keys/CHANGELOG.md @@ -9,6 +9,7 @@ ### Bugs Fixed - Fixed an issue where certain `HttpResponseException.getResponse()` calls could cause a `NullPointerException`. ([#47801](https://github.com/Azure/azure-sdk-for-java/issues/47801)) +- Fixed an issue where cryptographic operation results (`SignResult`, `EncryptResult`, `DecryptResult`, `WrapResult`, `UnwrapResult`) returned a versionless key ID instead of the full versioned key ID returned by the service. This caused issues when attempting roundtrip scenarios, as callers couldn't determine which key version was used for the original operation. ([#47822](https://github.com/Azure/azure-sdk-for-java/issues/47822)) ### Other Changes diff --git a/sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/cryptography/implementation/CryptographyClientImpl.java b/sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/cryptography/implementation/CryptographyClientImpl.java index d5d633cb079c..72e94129db39 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/cryptography/implementation/CryptographyClientImpl.java +++ b/sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/cryptography/implementation/CryptographyClientImpl.java @@ -159,7 +159,7 @@ private Mono encryptAsync(EncryptionAlgorithm algorithm, byte[] p .map(response -> { KeyOperationResult result = response.getValue().toObject(KeyOperationResult.class); - return new EncryptResult(result.getResult(), algorithm, keyId, result.getIv(), + return new EncryptResult(result.getResult(), algorithm, result.getKid(), result.getIv(), result.getAuthenticationTag(), result.getAdditionalAuthenticatedData()); }); } @@ -191,8 +191,8 @@ private EncryptResult encrypt(EncryptionAlgorithm algorithm, byte[] plainText, b .getValue() .toObject(KeyOperationResult.class); - return new EncryptResult(result.getResult(), algorithm, keyId, result.getIv(), result.getAuthenticationTag(), - result.getAdditionalAuthenticatedData()); + return new EncryptResult(result.getResult(), algorithm, result.getKid(), result.getIv(), + result.getAuthenticationTag(), result.getAdditionalAuthenticatedData()); } public Mono decryptAsync(EncryptionAlgorithm algorithm, byte[] ciphertext, Context context) { @@ -224,7 +224,7 @@ private Mono decryptAsync(EncryptionAlgorithm algorithm, byte[] c .map(response -> { KeyOperationResult result = response.getValue().toObject(KeyOperationResult.class); - return new DecryptResult(result.getResult(), algorithm, keyId); + return new DecryptResult(result.getResult(), algorithm, result.getKid()); }); } @@ -257,7 +257,7 @@ private DecryptResult decrypt(EncryptionAlgorithm algorithm, byte[] ciphertext, .getValue() .toObject(KeyOperationResult.class); - return new DecryptResult(result.getResult(), algorithm, keyId); + return new DecryptResult(result.getResult(), algorithm, result.getKid()); } public Mono signAsync(SignatureAlgorithm algorithm, byte[] digest, Context context) { @@ -272,7 +272,7 @@ public Mono signAsync(SignatureAlgorithm algorithm, byte[] digest, C .map(response -> { KeyOperationResult result = response.getValue().toObject(KeyOperationResult.class); - return new SignResult(result.getResult(), algorithm, keyId); + return new SignResult(result.getResult(), algorithm, result.getKid()); }); } @@ -289,7 +289,7 @@ public SignResult sign(SignatureAlgorithm algorithm, byte[] digest, Context cont .getValue() .toObject(KeyOperationResult.class); - return new SignResult(result.getResult(), algorithm, keyId); + return new SignResult(result.getResult(), algorithm, result.getKid()); } public Mono verifyAsync(SignatureAlgorithm algorithm, byte[] digest, byte[] signature, @@ -341,7 +341,7 @@ public Mono wrapKeyAsync(KeyWrapAlgorithm algorithm, byte[] key, Con .map(response -> { KeyOperationResult result = response.getValue().toObject(KeyOperationResult.class); - return new WrapResult(result.getResult(), algorithm, keyId); + return new WrapResult(result.getResult(), algorithm, result.getKid()); }); } @@ -358,7 +358,7 @@ public WrapResult wrapKey(KeyWrapAlgorithm algorithm, byte[] key, Context contex .getValue() .toObject(KeyOperationResult.class); - return new WrapResult(result.getResult(), algorithm, keyId); + return new WrapResult(result.getResult(), algorithm, result.getKid()); } public Mono unwrapKeyAsync(KeyWrapAlgorithm algorithm, byte[] encryptedKey, Context context) { @@ -374,7 +374,7 @@ public Mono unwrapKeyAsync(KeyWrapAlgorithm algorithm, byte[] encr .map(response -> { KeyOperationResult result = response.getValue().toObject(KeyOperationResult.class); - return new UnwrapResult(result.getResult(), algorithm, keyId); + return new UnwrapResult(result.getResult(), algorithm, result.getKid()); }); } @@ -392,7 +392,7 @@ public UnwrapResult unwrapKey(KeyWrapAlgorithm algorithm, byte[] encryptedKey, C .getValue() .toObject(KeyOperationResult.class); - return new UnwrapResult(result.getResult(), algorithm, keyId); + return new UnwrapResult(result.getResult(), algorithm, result.getKid()); } public Mono signDataAsync(SignatureAlgorithm algorithm, byte[] data, Context context) { diff --git a/sdk/keyvault/azure-security-keyvault-keys/src/test/java/com/azure/security/keyvault/keys/cryptography/CryptographyClientTest.java b/sdk/keyvault/azure-security-keyvault-keys/src/test/java/com/azure/security/keyvault/keys/cryptography/CryptographyClientTest.java index 5ee4f5727ab7..c0cc876535b9 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/src/test/java/com/azure/security/keyvault/keys/cryptography/CryptographyClientTest.java +++ b/sdk/keyvault/azure-security-keyvault-keys/src/test/java/com/azure/security/keyvault/keys/cryptography/CryptographyClientTest.java @@ -7,16 +7,23 @@ import com.azure.core.util.logging.ClientLogger; import com.azure.core.util.logging.LogLevel; import com.azure.security.keyvault.keys.KeyClient; +import com.azure.security.keyvault.keys.cryptography.models.DecryptResult; import com.azure.security.keyvault.keys.cryptography.models.EncryptParameters; +import com.azure.security.keyvault.keys.cryptography.models.EncryptResult; import com.azure.security.keyvault.keys.cryptography.models.EncryptionAlgorithm; import com.azure.security.keyvault.keys.cryptography.models.KeyWrapAlgorithm; import com.azure.security.keyvault.keys.cryptography.models.SignResult; import com.azure.security.keyvault.keys.cryptography.models.SignatureAlgorithm; +import com.azure.security.keyvault.keys.cryptography.models.UnwrapResult; +import com.azure.security.keyvault.keys.cryptography.models.VerifyResult; +import com.azure.security.keyvault.keys.cryptography.models.WrapResult; import com.azure.security.keyvault.keys.models.CreateEcKeyOptions; import com.azure.security.keyvault.keys.models.JsonWebKey; import com.azure.security.keyvault.keys.models.KeyCurveName; import com.azure.security.keyvault.keys.models.KeyOperation; import com.azure.security.keyvault.keys.models.KeyVaultKey; +import com.azure.security.keyvault.keys.models.KeyVaultKeyIdentifier; + import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -38,6 +45,8 @@ import static com.azure.security.keyvault.keys.TestUtils.buildSyncAssertingClient; import static com.azure.security.keyvault.keys.cryptography.TestHelper.DISPLAY_NAME_WITH_ARGUMENTS; import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -87,15 +96,21 @@ public void encryptDecryptRsa(HttpClient httpClient, CryptographyServiceVersion new Random(0x1234567L).nextBytes(plaintext); - byte[] ciphertext = cryptoClient.encrypt(algorithm, plaintext).getCipherText(); - byte[] decryptedText = cryptoClient.decrypt(algorithm, ciphertext).getPlainText(); + EncryptResult encryptResult = cryptoClient.encrypt(algorithm, plaintext); + + assertEquals(encryptResult.getAlgorithm(), algorithm); + assertNotNull(encryptResult.getCipherText()); + + String keyId = encryptResult.getKeyId(); + + assertNotNull(keyId); - assertArrayEquals(decryptedText, plaintext); + // Ensure the keyId includes the key version + assertNotNull(new KeyVaultKeyIdentifier(keyId).getVersion(), "keyId does not contain key version."); - ciphertext = cryptoClient.encrypt(algorithm, plaintext).getCipherText(); - decryptedText = cryptoClient.decrypt(algorithm, ciphertext).getPlainText(); + DecryptResult decryptResult = cryptoClient.decrypt(algorithm, encryptResult.getCipherText()); - assertArrayEquals(decryptedText, plaintext); + assertArrayEquals(decryptResult.getPlainText(), plaintext); } }); } @@ -114,10 +129,10 @@ public void encryptDecryptRsaLocal() throws Exception { new Random(0x1234567L).nextBytes(plainText); - byte[] cipherText = cryptoClient.encrypt(algorithm, plainText).getCipherText(); - byte[] decryptedText = cryptoClient.decrypt(algorithm, cipherText).getPlainText(); + EncryptResult encryptResult = cryptoClient.encrypt(algorithm, plainText); + DecryptResult decryptResult = cryptoClient.decrypt(algorithm, encryptResult.getCipherText()); - assertArrayEquals(decryptedText, plainText); + assertArrayEquals(decryptResult.getPlainText(), plainText); } }); } @@ -142,17 +157,22 @@ public void wrapUnwrapRsa(HttpClient httpClient, CryptographyServiceVersion serv new Random(0x1234567L).nextBytes(plaintext); - byte[] encryptedKey = cryptoClient.wrapKey(algorithm, plaintext).getEncryptedKey(); - byte[] decryptedKey = cryptoClient.unwrapKey(algorithm, encryptedKey).getKey(); + WrapResult wrapResult = cryptoClient.wrapKey(algorithm, plaintext); - assertArrayEquals(decryptedKey, plaintext); + assertEquals(wrapResult.getAlgorithm(), algorithm); + assertNotNull(wrapResult.getEncryptedKey()); - encryptedKey = cryptoClient.wrapKey(algorithm, plaintext).getEncryptedKey(); - decryptedKey = cryptoClient.unwrapKey(algorithm, encryptedKey).getKey(); + String keyId = wrapResult.getKeyId(); - assertArrayEquals(decryptedKey, plaintext); - } + assertNotNull(keyId); + + // Ensure the keyId includes the key version + assertNotNull(new KeyVaultKeyIdentifier(keyId).getVersion(), "keyId does not contain key version."); + UnwrapResult unwrapResult = cryptoClient.unwrapKey(algorithm, wrapResult.getEncryptedKey()); + + assertArrayEquals(unwrapResult.getKey(), plaintext); + } }); } @@ -169,12 +189,11 @@ public void wrapUnwrapRsaLocal() throws Exception { new Random(0x1234567L).nextBytes(plainText); - byte[] encryptedKey = cryptoClient.wrapKey(algorithm, plainText).getEncryptedKey(); - byte[] decryptedKey = cryptoClient.unwrapKey(algorithm, encryptedKey).getKey(); + WrapResult wrapResult = cryptoClient.wrapKey(algorithm, plainText); + UnwrapResult unwrapResult = cryptoClient.unwrapKey(algorithm, wrapResult.getEncryptedKey()); - assertArrayEquals(decryptedKey, plainText); + assertArrayEquals(unwrapResult.getKey(), plainText); } - }); } @@ -208,6 +227,16 @@ public void signVerifyEc(HttpClient httpClient, CryptographyServiceVersion servi SignResult signResult = cryptographyClient.sign(curveToSignature.get(curve), digest); + assertEquals(signResult.getAlgorithm(), curveToSignature.get(curve)); + assertNotNull(signResult.getSignature()); + + String keyId = signResult.getKeyId(); + + assertNotNull(keyId); + + // Ensure the keyId includes the key version + assertNotNull(new KeyVaultKeyIdentifier(keyId).getVersion(), "keyId does not contain key version."); + Boolean verifyStatus = cryptographyClient.verify(curveToSignature.get(curve), digest, signResult.getSignature()) .isValid(); @@ -239,10 +268,21 @@ public void signDataVerifyEc(HttpClient httpClient, CryptographyServiceVersion s new Random(0x1234567L).nextBytes(plaintext); - byte[] signature = cryptographyClient.signData(curveToSignature.get(curve), plaintext).getSignature(); + SignResult signResult = cryptographyClient.signData(curveToSignature.get(curve), plaintext); + + assertEquals(signResult.getAlgorithm(), curveToSignature.get(curve)); + assertNotNull(signResult.getSignature()); + + String keyId = signResult.getKeyId(); + + assertNotNull(keyId); + + // Ensure the keyId includes the key version + assertNotNull(new KeyVaultKeyIdentifier(keyId).getVersion(), "keyId does not contain key version."); Boolean verifyStatus - = cryptographyClient.verifyData(curveToSignature.get(curve), plaintext, signature).isValid(); + = cryptographyClient.verifyData(curveToSignature.get(curve), plaintext, signResult.getSignature()) + .isValid(); assertTrue(verifyStatus); }); @@ -281,9 +321,20 @@ public void signVerifyRsa(HttpClient httpClient, CryptographyServiceVersion serv byte[] digest = md.digest(); SignResult signResult = cryptoClient.sign(algorithm, digest); - Boolean verifyStatus = cryptoClient.verify(algorithm, digest, signResult.getSignature()).isValid(); - assertTrue(verifyStatus); + assertEquals(signResult.getAlgorithm(), algorithm); + assertNotNull(signResult.getSignature()); + + String keyId = signResult.getKeyId(); + + assertNotNull(keyId); + + // Ensure the keyId includes the key version + assertNotNull(new KeyVaultKeyIdentifier(keyId).getVersion(), "keyId does not contain key version."); + + VerifyResult verifyResult = cryptoClient.verify(algorithm, digest, signResult.getSignature()); + + assertTrue(verifyResult.isValid()); } catch (NoSuchAlgorithmException e) { fail(e); } @@ -310,10 +361,21 @@ public void signDataVerifyRsa(HttpClient httpClient, CryptographyServiceVersion new Random(0x1234567L).nextBytes(plaintext); - byte[] signature = cryptoClient.signData(algorithm, plaintext).getSignature(); - Boolean verifyStatus = cryptoClient.verifyData(algorithm, plaintext, signature).isValid(); + SignResult signResult = cryptoClient.signData(algorithm, plaintext); - assertTrue(verifyStatus); + assertEquals(signResult.getAlgorithm(), algorithm); + assertNotNull(signResult.getSignature()); + + String keyId = signResult.getKeyId(); + + assertNotNull(keyId); + + // Ensure the keyId includes the key version + assertNotNull(new KeyVaultKeyIdentifier(keyId).getVersion(), "keyId does not contain key version."); + + VerifyResult verifyResult = cryptoClient.verifyData(algorithm, plaintext, signResult.getSignature()); + + assertTrue(verifyResult.isValid()); } }); } @@ -369,11 +431,11 @@ public void signDataVerifyEcLocal() { new Random(0x1234567L).nextBytes(plainText); - byte[] signature = cryptographyClient.signData(curveToSignature.get(curve), plainText).getSignature(); - Boolean verifyStatus - = cryptographyClient.verifyData(curveToSignature.get(curve), plainText, signature).isValid(); + SignResult signResult = cryptographyClient.signData(curveToSignature.get(curve), plainText); + VerifyResult verifyResult + = cryptographyClient.verifyData(curveToSignature.get(curve), plainText, signResult.getSignature()); - assertTrue(verifyStatus); + assertTrue(verifyResult.isValid()); }); }