0

Im new to Cloud KMS, and I started following exactly what's written here

I encrypted my data file which is saved in UTF-8 format by running this command

gcloud kms encrypt --location global --keyring ring --key key --plaintext-file /path_to_file --ciphertext-file /path_to_enc --project myProject 

then as a result my encrypted data has been presented in this format in my new created encrypted file

$�]ˋLݿ���yHI�lS�`&�Nt�b{%�U��   �&�A���XaL��d

here is how I read the encrypted file data:

 static Properties properties = new Properties();

static {

    try {

        InputStream in = new Credentials().getClass().getResourceAsStream("path_to_enc_file");
        byte[] encryptedData = IOUtils.toByteArray(in);

        byte[] decryptedBytes = decrypt(EnvironmentVariable.getProjectId(), "global", "ring", "key", encryptedData);
        ByteArrayInputStream bis = new ByteArrayInputStream(decryptedBytes);

        properties.load(bis);           
        in.close();
        bis.close();
    } catch (IOException e1) {
        e1.printStackTrace();
    }
}

and now whenever I try to decrypt it by this function:

public static byte[] decrypt(
    String projectId, String locationId, String keyRingId, String cryptoKeyId, byte[] ciphertext)
    throws IOException {

  // Create the KeyManagementServiceClient using try-with-resources to manage client cleanup.
  try (KeyManagementServiceClient client = KeyManagementServiceClient.create()) {

    // The resource name of the cryptoKey
    String resourceName = CryptoKeyName.format(projectId, locationId, keyRingId, cryptoKeyId);

    // Decrypt the ciphertext with Cloud KMS.
    DecryptResponse response = client.decrypt(resourceName, ByteString.copyFrom(ciphertext));

    // Extract the plaintext from the response.
    return response.getPlaintext().toByteArray();
  }
}

it throw this

{
  "code" : 400,
  "errors" : [ {
    "domain" : "global",
    "message" : "Decryption failed: the ciphertext is invalid.",
    "reason" : "badRequest"
  } ],
  "message" : "Decryption failed: the ciphertext is invalid.",
  "status" : "INVALID_ARGUMENT"
}

the key type is: Symmetric encrypt/decrypt Default Algorithm: Google symmetric key

the ring location: global

Can you plz help me out and tell me what's missing in google docs?

Tamer Saleh
  • 473
  • 9
  • 21
  • Can you show the code where you read the ciphertext in from the file? My gut says that there's an encoding problem. – hjfreyer Mar 10 '19 at 16:59
  • I added that in the question – Tamer Saleh Mar 10 '19 at 17:02
  • Hmm, the ciphertext you have in the middle indeed looks corrupted (perhaps just from copy-pasting into SO, though). Are you doing anything to the file between the `gcloud` command and the java code where you're reading it in? Like, you're not copy-pasting it from one file to the other, are you? Also, what OS? Also I can confirm the corruption is real if you can give me a base64 version of the ciphertext. – hjfreyer Mar 10 '19 at 17:29
  • I actually have no clue about that base64, I just followed what google docs says exactly, and no there is no any thing between encrypting using the gcloud kms command and decrypting it using the provided code and the file that holding the encrypted data is in UTF8 encoding – Tamer Saleh Mar 10 '19 at 19:56
  • and the OS I used to run this encrypting command is MAC OS – Tamer Saleh Mar 10 '19 at 20:11
  • I tried to decrypt the file using the glcoud kms decrypt command and it works successfully and I got my plain text data back without any errors, so why it failed by the code ? – Tamer Saleh Mar 10 '19 at 20:16
  • Hmm, I'm not a Java expert, but I still think something about the data is getting corrupted during the file loading. Can you run `cat path_to_enc_file | openssl base64`, and run your program printing out `ciphertext` before the decrypt, and put both the results in a github gist? – hjfreyer Mar 10 '19 at 20:43
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/189779/discussion-between-tamer-saleh-and-hjfreyer). – Tamer Saleh Mar 10 '19 at 20:51

4 Answers4

2

Update: As bdhess says in the comment, this is probably due to Maven being "helpful" and corrupting the data during the build process. See the Maven docs for how to avoid this.

The solution below also works, but is less straightforward.


Tamer and I chatted for a while and got a workaround:

  • Encode the output from gcloud in base64 before including it in a file in src/main/resources.
  • Decode the file after reading it with java.util.Base64.
  • Pass the decoded bytes to the KMS API.

For some reason the bytes were getting corrupted between creating the file with gcloud and reading the bytes in with getResourceAsStream(). From the code above I can't see where the corruption would be happening, and it seems like reading in binary resources should be totally supported. But something is breaking somewhere in Tamer's case.

I'll try to reproduce it sometime this week.

hjfreyer
  • 539
  • 3
  • 11
  • 2
    Assuming this is built with Maven, the likely culprit is resource filtering in `maven-resources-plugin` at build time, which treats most things under `src/main/resources` as text. The [documentation](https://maven.apache.org/plugins/maven-resources-plugin/examples/binaries-filtering.html) shows how to specify an additional file extension so that binary data like Cloud KMS ciphertexts aren't corrupted by resource filtering. – bdhess Mar 11 '19 at 00:22
0

To decrypt a secret from a file to a plaintext file:

cat secret.enc | gcloud kms decrypt \
  --location=global \
  --keyring=keyring \
  --key=key \
  --ciphertext-file=- \
  --plaintext-file=decrypted_secret.txt
Cloudkollektiv
  • 11,852
  • 3
  • 44
  • 71
0

You'd need to decode the encrypted key first with base64, and then pipe the output to the whole gcloud kms command, e.g:

cat my-token.enc | base64 --decode | gcloud kms decrypt --plaintext-file=plaintextfile --ciphertext-file=- --location=global   --keyring=yourkeyringname   --key=yourkeyname
-1

I did that modifications then it worked like a charm with a great help from @hjfreyer

1- to encrypt the plain text secret I did that

  • run this command -->

    gcloud kms encrypt --location global --plaintext-file PATH_TO_SECRET_FILE --ciphertext-file PATH_TO_TMP_FILE --project myProject --key key --keyring ring

  • Encode the result base64 -->

    base64 PATH_TO_TMP_FILE > PATH_TO_FINAL_ENC_FILE

  • remove new line from the FINAL_ENC_FILE file

2- to decrypt the data back first I need to base64 decode it then pass it to the decrypt KMS function

InputStream in = new Credentials().getClass().getResourceAsStream("PATH_TO_FINAL_ENC_FILE");
            byte[] encryptedData = IOUtils.toByteArray(in);


            byte[] decryptedBytes = decrypt(EnvironmentVariable.getProjectId(), "global", "ring", "key", Base64.getDecoder().decode(encryptedData));
Tamer Saleh
  • 473
  • 9
  • 21
  • for me this doesn't work. I just run `val in = new FileInputStream("ciphertext/in/base64")` `val encryptedData = IOUtils.toByteArray(in)` `Base64.getDecoder().decode(encryptedData)` this gives error `java.lang.IllegalArgumentException: Illegal base64 character a` – Alistair McIntyre Feb 09 '21 at 21:32