1

I'm using AES to encrypt something, through calling the java crypto libraries from Clojure. As a part of this I'm generating a new key that I'm using for the encryption (in my case a "DataKey" from Amazon's KMS). Amazon recommends removing the data key from memory as soon as it's been used.

As a code example, kms-generated-key is the response I get from the KMS api (via the aws-api library) when I hit the GenerateDataKey endpoint (https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html). It contains both the plaintext and encrypted version of the new data key I want to encrypt with.

Then I have my local encrypt function which takes that hash and returns a new hash, including both the encrypted ciphertext and encrypted data key. I'd store both of these for later use.

How can I ensure the plaintext key has been scrubbed from memory?

(defn kms-generated-key
  []
  ; ... leaving out AWS API request code, but it gives this...
  {:CiphertextBlob "...", ; java.io.BufferedInputStream - this is an encrypted version of the new data key 
   :Plaintext "...",  ; java.io.BufferedInputStream - this is the plaintext version of the new data key
   :KeyId "arn:aws:..."})

(defn encrypt
  [secret-text]
  (let [{data-key :Plaintext
         encrypted-data-key :CiphertextBlob} kms-generated-key]
    {:ciphertext (encrypt-locally-using-data-key data-key secret-text) 
     :encrypted-data-key encrypted-data-key}))

edit: I only need to do this in clojure running on the JVM, I'm not looking for anything generic across clojurescript / the CLR runtime.

spike
  • 9,794
  • 9
  • 54
  • 85
  • AFAIK, there is no way to ensure that with any certainty. You can make it eligible for garbage collection, and call `System/gc` to lightly suggest that a collection happen, but you can't explicitly have it removed/"scrubbed" from memory. – Carcigenicate Jul 24 '19 at 22:18
  • Highly related: https://stackoverflow.com/questions/1481178/how-to-force-garbage-collection-in-java – Carcigenicate Jul 24 '19 at 22:19
  • @Carcigenicate thanks! I'd avoided mentioning java GC explicitly since I thought the meat here would be ensuring the variable was eligible for garbage collection, or that I would need to do some trick to directly allocate memory. I'm going to add the JVM tag though. – spike Jul 24 '19 at 22:25
  • Oh, so you just want to ensure that it's eligible for removal, not that it's actually removed right away? – Carcigenicate Jul 24 '19 at 22:27
  • @Carcigenicate I'd be interested in any of what my options are. I could imagine (but I'm sure this isn't exhaustive) anything from 1) just ensuring it'll get removed on the next GC run (is just removing the variable from scope enough here, or does clojure get in the way?), 2) ensuring it'll be removed and then forcing a GC run, or 3) some unsafe trick to directly manage memory like I would in C – spike Jul 24 '19 at 22:31
  • Also, just generally I'm learning more about amazon KMS, and I read "Use the plaintext data key (returned in the Plaintext field of the response) to encrypt data locally, then erase the plaintext data key from memory." in the amazon docs, and I'm wondering what a Clojure expert would do with that (which might be "don't worry, just wait for the variable to get collected automatically"). – spike Jul 24 '19 at 22:43
  • I think there is no point in trying the GC to run. Even if memory is garbage collected, the data is still in the RAM as long as the memory is not reused. Garbage collection just frees the memory allocation, but not the contents of the memory. For handling keys, memory should be used, that can be overwritten after usage, it doesn't matter so much when this memory is actually freed. – Matthias Wimmer Jul 25 '19 at 11:35

1 Answers1

1

I can think of cases where I would like to overwrite a plain text key after use. But in those cases I would not have delivered the key in plain though some arbitrary interfaces.

You have just received the key in plain text from a service, and you don't have any way of knowing what kind of buffers and Immutable String objects it have been through before you received it. To truly remove it from memory, you would need to have access to all these buffers and String objects and ensure they are purged etc.

Completely removing the value from memory is a lost cause with the design they present.

Ebbe M. Pedersen
  • 7,250
  • 3
  • 27
  • 47
  • If you had a mutable data structure, you could overwrite with all zeros before releasing the variable to be GC'd. With a `BufferedInputStream`, the most you can do is to call `close()` before releasing it. Other than that you are at the mercy of the Java GC system to clean up unused/unwanted objects like a `String`. – Alan Thompson Jul 29 '19 at 17:38