Search code examples
javaencryptionbytebufferamazon-kms

Decrypting data key in Java AWS SDK yields gibberish


So I've been reading and reading and looking at examples and...failing miserably. Here's my situation:

I have a CMK in KMS and I've generated a data key, like so:

$ aws kms generate-data-key --key-id 64a62e3e-7e38-4f86-8ef2-3d00929e6260 --key-spec AES_256
{
   "Plaintext": "+SjeaxtD5TIhOcY16+A2NA493MbxnYozbzZx4i3/BfA=", 
   "KeyId": "arn:aws:kms:us-west-2:040512153658:key/64a62e3e-7e38-4f86-8ef2-3d00929e6260", 
   "CiphertextBlob": "AQIDAHgrvfqfgn9D0tTUJOISzFCz7ejMPZ6/HGX0kGAlzKYZ7wEiyHdpuGaOjpq4UQazPAgeAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMU5JtbI6lxLOv/p4KAgEQgDsX97Pk+ywqLU2VymLRgDSz0exOyzRgLMgd7WEf3sLUh4GnbYllIrxNSdK/DSZrYUhBo78KYugnkTj89g=="
}

I then verify it by decrypting from the CLI:

$ aws kms decrypt --ciphertext-blob fileb://<(echo 'AQIDAHgrvfqfgn9D0tTUJOISzFCz7ejMPZ6/HGX0kGAlzKYZ7wEiyHdpuGaOjpq4UQazPAgeAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMU5JtbI6lxLOv/p4KAgEQgDsX97Pk+ywqLU2VymLRgDSz0exOyzRgLMgd7WEf3sLUh4GnbYllIrxNSdK/DSZrYUhBo78KYugnkTj89g==' | base64 -d) --query Plaintext
"+SjeaxtD5TIhOcY16+A2NA493MbxnYozbzZx4i3/BfA="

Lo and behold! I get the Plaintext value back all nice and clean. I then try to grind that same ciphertext blob through the SDK using Java with the following code:

    .
    .
    .
    final String encryptedCipherText = "AQIDAHgrvfqfgn9D0tTUJOISzFCz7ejMPZ6/HGX0kGAlzKYZ7wEiyHdpuGaOjpq4UQazPAgeAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMU5JtbI6lxLOv/p4KAgEQgDsX97Pk+ywqLU2VymLRgDSz0exOyzRgLMgd7WEf3sLUh4GnbYllIrxNSdK/DSZrYUhBo78KYugnkTj89g==";
    final String expectedPlainText = "+SjeaxtD5TIhOcY16+A2NA493MbxnYozbzZx4i3/BfA=";

    AWSKMS kmsClient;
    String returnValue;

    kmsClient = AWSKMSClientBuilder
            .standard()
            .withRegion("us-west-2")
            .build();

    ByteBuffer cipherTextBlob = ByteBuffer.wrap(Base64.getDecoder().decode(encryptedCipherText));
    DecryptRequest decryptRequest = new DecryptRequest().withCiphertextBlob(cipherTextBlob);
    ByteBuffer key = kmsClient.decrypt(decryptRequest).getPlaintext();
    final byte[] bytes = new byte[key.remaining()];
    key.duplicate().get(bytes);
    String result = new String(bytes);
    if (expectedPlainText.equals(result)) {
        LOG.info("decrypted plaintext matches expected");
    } else {
        LOG.error("decrypted plaintext unexpected value: " + result);
    }
    .
    .
    .

And the LOG entry dumped out was:

23:08:33.210 [main] ERROR com.eyefinity.magicmissile.aws.AwsClientConfig - decrypted plaintext unexpected value: �(�k�2!9�5��64=���3o6q�-��

I've tried encoding the result with every Charset available to me, and no Charset produces my original Plaintext key. As near as I can tell from all the examples I've seen, my code is correct. So what am I doing wrong or what am I missing here? All I want is to end up with a Java String variable that contains "+SjeaxtD5TIhOcY16+A2NA493MbxnYozbzZx4i3/BfA=".


Solution

  • I stumbled on my own solution: I was SO CLOSE! All that's required in the code above to extract the same Plaintext value that is returned from KMS, and the ASCII string I received on the aws-cli command line when generating the datakey, is to take the byte array and Base64 encode it. So referencing my sample code above, all the way at the top, replace the line that reads...

    String result = new String(bytes);
    

    with something like this:

    String result = Base64.getEncoder().encodeToString(bytes);