0
votes

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?

3
Can you show the code where you read the ciphertext in from the file? My gut says that there's an encoding problem. - hjfreyer
I added that in the question - Tamer Saleh
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
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
and the OS I used to run this encrypting command is MAC OS - Tamer Saleh

3 Answers

2
votes

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.

0
votes

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));
0
votes

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