Open Smaz2024 opened 4 months ago
I have removed several AWS related names and arns here for confidentiality.
Hey @Smaz2024, Thank you for cutting the issue! It looks like you are running into a Base64 encoding problem between your encrypt and decrypt functions.
/**
*
* @param plaintext
* @param keyring
* @return
*/
private String encryptMessage(String plaintext, IKeyring keyring) {
// Instantiate the SDK
final AwsCrypto crypto = AwsCrypto.builder().withCommitmentPolicy(CommitmentPolicy.ForbidEncryptAllowDecrypt)
.withEncryptionAlgorithm(CryptoAlgorithm. ALG_AES_256_GCM_IV12_TAG16_NO_KDF).build();
logger.log(
"Aws Crypto - Encrypt .................................................................................. ");
// Create an encryption context
final Map<String, String> encryptionContext = Collections.singletonMap("ExampleContextKey",
"ExampleContextValue");
// Encrypt the data
final CryptoResult<byte[], ?> encryptResult = crypto.encryptData(keyring,
plaintext.getBytes(StandardCharsets.UTF_8), encryptionContext);
logger.log("Crypto Result post encryption..... " + encryptResult.getResult());
return Base64.getEncoder().encodeToString(encryptResult.getResult());
}
/**
*
* @param plaintext
* @param keyring
* @return
*/
private String decryptMessage(String ciphertext, IKeyring keyring) {
// Instantiate the SDK
final AwsCrypto crypto = AwsCrypto.builder().withCommitmentPolicy(CommitmentPolicy.ForbidEncryptAllowDecrypt)
.withEncryptionAlgorithm(CryptoAlgorithm. ALG_AES_256_GCM_IV12_TAG16_NO_KDF).build();
logger.log("Aws Crypto - Decrypt ...... " + ciphertext);
// Create an encryption context
final Map<String, String> encryptionContext = Collections.singletonMap("ExampleContextKey",
"ExampleContextValue");
// 5. Decrypt the data
final CryptoResult<byte[], ?> decryptResult = crypto.decryptData(keyring,
ciphertext.getBytes(StandardCharsets.UTF_8),
// Verify that the encryption context in the result contains the
// encryption context supplied to the encryptData method
encryptionContext);
logger.log("Crypto Result post decryption..... " + decryptResult.getResult());
return Base64.getEncoder().encodeToString(decryptResult.getResult());
}
It looks like you are Base64 encoding the ciphertext after you successfully encrypting it but not decoding it back to bytes before you decrypt it. If you base64 decode it before you pass it to the decryptData method the com.amazonaws.encryptionsdk.exception.BadCiphertextException: Invalid version
exception should go away.
Please let us know if you run into more issues. Thanks!
Hi @josecorella : Thanks a lot for your reply and helped. The solution worked for me . However I was experimenting more on the same codebase.
1) Tried saving public key of the pair in RAWRSA Keyring in Java and the corresponding private key in KMSKeyRing. Tried to encrypt the text with RAW RSA Keyring and decrypt the ciphertext using KMSKeyring. Ideally since both are part of same pair so should work, but it was failing.
String publicKeyPEM = publicKeyPem.replace("-----BEGIN PUBLIC KEY-----", "")
.replace("-----END PUBLIC KEY-----", "")
.replaceAll("\\s+", "");
byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyPEM);
X509EncodedKeySpec spec = new X509EncodedKeySpec(publicKeyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
RSAPublicKey generatePublic = (RSAPublicKey) kf.generatePublic(spec);
final AwsCrypto crypto = AwsCrypto.builder()
.withEncryptionAlgorithm(CryptoAlgorithm.ALG_AES_256_GCM_IV12_TAG16_HKDF_SHA256)
.withCommitmentPolicy(CommitmentPolicy.ForbidEncryptAllowDecrypt).build();
final MaterialProviders matProv = MaterialProviders.builder()
.MaterialProvidersConfig(MaterialProvidersConfig.builder().build()).build();
/*
* final CreateRawRsaKeyringInput encryptingKeyringInput =
* CreateRawRsaKeyringInput.builder()
* .keyName("rsa-key").keyNamespace("rsa-keyring").paddingScheme(PaddingScheme.
* PKCS1) .publicKey(publicKeyByteBuffer).build();
*/
JceMasterKey jcemasterKey = JceMasterKey.getInstance(
generatePublic, null, "", "",
// "RSA/ECB/PKCS1Padding"
"RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
// "RSA/ECB/PKCS1Padding"
final Map<String, String> encryptionContext = Collections.singletonMap("ExampleContextKey",
"ExampleContextValue");
final CryptoResult<byte[], ?> encryptResult = crypto.encryptData(jcemasterKey,
plaintext.getBytes(StandardCharsets.UTF_8), encryptionContext);
final byte[] ciphertext = encryptResult.getResult();
final CreateAwsKmsRsaKeyringInput kmsKeyRing = CreateAwsKmsRsaKeyringInput.builder()
.kmsClient(KmsClient.create()).kmsKeyId(rsaKeyArn)
// .publicKey(publicKeyByteBuffer)
.encryptionAlgorithm(EncryptionAlgorithmSpec.RSAES_OAEP_SHA_256).build();
IKeyring awsKmsRsaKeyring = matProv.CreateAwsKmsRsaKeyring(kmsKeyRing);
final CryptoResult<byte[], ?> decryptResult = crypto.decryptData(awsKmsRsaKeyring, ciphertext,
// Verify that the encryption context in the result contains the
// encryption context supplied to the encryptData method
encryptionContext);
logger.log(
"Final Output in decrypted text: " + new String(decryptResult.getResult(), StandardCharsets.UTF_8));
Unable to decrypt data key: No Encrypted Data Keys found to match. Expected: KeyProviderId: , KeyProviderInfo:
2) Next I tried with 2 separate KMSKeyRings but again it failed. (Created 2 separate key pairs and secrets)
final CreateAwsKmsRsaKeyringInput kmsKeyRingEncryption = CreateAwsKmsRsaKeyringInput.builder()
.kmsClient(KmsClient.create()).kmsKeyId(rsaKeyArn).publicKey(publicKeyByteBuffer2)
.encryptionAlgorithm(EncryptionAlgorithmSpec.RSAES_OAEP_SHA_256).build();
final CreateAwsKmsRsaKeyringInput kmsKeyRingDecryption = CreateAwsKmsRsaKeyringInput.builder()
.kmsClient(KmsClient.create()).kmsKeyId(rsaKeyArn2).publicKey(publicKeyByteBuffer)
.encryptionAlgorithm(EncryptionAlgorithmSpec.RSAES_OAEP_SHA_256).build();
logger.log("Material Providers ....................................................................");
IKeyring awsKmsRsaKeyringEncryption = matProv.CreateAwsKmsRsaKeyring(kmsKeyRingEncryption);
IKeyring awsKmsRsaKeyringDecryption = matProv.CreateAwsKmsRsaKeyring(kmsKeyRingDecryption);
logger.log("Raw Pub Rsa Keyring ....................................................................");
// Encrypt the message
String ciphertext = encryptMessage(plaintext, awsKmsRsaKeyringEncryption);
String decryptedtext = decryptMessage(ciphertext, awsKmsRsaKeyringDecryption);
Unable to decrypt data key: No Encrypted Data Keys found to match. Expected: KeyProviderId: aws-kms-rsa, KeyProviderInfo: arn:aws:kms:ap-south-1:732077235871:key/f2cbec0a-1ccd-4869-bc6b-bd51caadb6ca
The reason I am trying to do so because the encrypting and decrypting parties can be in different cloud/on-prem environment or different account in AWS. So separate key rings can be used.
Please help
@Smaz2024 ,
I am sorry Crypto Tools did not respond to your latest post sooner.
When a Keyring wraps a data key, it serializes information that describes the Keyring, such that at decryption, the decryptor knows which Keyring to use to decrypt it.
Because you are using different Keyrings at encrypt and decrypt, the description created at Encrypt does not match the Decrypt expectation.
Your options:
But they all boil down to a consistent description of what encrypted the data key.
Think of a regular physical key chain. You need to know which Key opens which lock.
The same principle applies here.
I am creating a POC where I have created a public and private key pair. The private key is stored in KMS. The public key is stored in Secrets Manager. I am using the following code for envelope encryption.
Java Code
package com.poc.envelope.encryption;
import java.io.StringWriter; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.security.KeyFactory; import java.security.PublicKey; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; import java.util.Collections; import java.util.Map;
import org.bouncycastle.util.io.pem.PemObject; import org.bouncycastle.util.io.pem.PemWriter;
import com.amazonaws.encryptionsdk.AwsCrypto; import com.amazonaws.encryptionsdk.CommitmentPolicy; import com.amazonaws.encryptionsdk.CryptoAlgorithm; import com.amazonaws.encryptionsdk.CryptoResult; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.LambdaLogger; import com.amazonaws.services.lambda.runtime.RequestHandler; import com.google.gson.JsonObject; import com.google.gson.JsonParser;
import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.kms.KmsClient; import software.amazon.awssdk.services.kms.model.EncryptionAlgorithmSpec; import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient; import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueRequest; import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueResponse; import software.amazon.cryptography.materialproviders.IKeyring; import software.amazon.cryptography.materialproviders.MaterialProviders; import software.amazon.cryptography.materialproviders.model.CreateAwsKmsRsaKeyringInput; import software.amazon.cryptography.materialproviders.model.MaterialProvidersConfig;
//https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/java-example-code.html public class HandleRequestForEnvelopeEncryption implements RequestHandler<Map<String, String>, String> { LambdaLogger logger;
}
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
=================
Error I am getting
com.amazonaws.encryptionsdk.exception.BadCiphertextException: Invalid version at com.amazonaws.encryptionsdk.model.CiphertextHeaders.deserialize(CiphertextHeaders.java:588) at com.amazonaws.encryptionsdk.ParsedCiphertext.(ParsedCiphertext.java:42)
at com.amazonaws.encryptionsdk.AwsCrypto.decryptData(AwsCrypto.java:752)
I have tried several options but it did not help. PLease share inputs