Node.js implementation of the KMS Envelope Encryption for AWS S3
The cipher algorithm to use when encrypting the object. Find the list by looking at crypto.getCiphers(). Optional, will be ignored if KmsKeyId is missing.
The character encoding of the file to be uploaded to S3, to be used when encrypting (and thus decrypting) the object. Optional, will be ignored if KmsKeyId is missing.
Optionally call this method with a value > 0 in order to persist the object in an in-memory cache. This can be used to avoid repetitively loading objects from S3 and decrypting via KMS in functions that are frequently executed. The argument is the number of milliseconds for which the S3 object should remain in the cache before becoming stale. Keep in mind that this limit will only be met as long as the function remains in memory in Lambda (i.e. does not follow a cold-start of the function). Obviously, using a cache introduces the risk of the in-memory version getting out of sync with the object in S3; be sure to balance performance against a reasonable TTL that will allow the function to absorb edits to the object in a timely manner.
You can read about KMS envelope encryption above, but here's the summary:
- Create a KMS key (it is assumed that you have already done this)
- Use the key from #1 to generate a KMS Data Key
- Use the KMS Data Key's Plaintext to encrypt your file
- Put the file into S3 with the KMS Data Key's CiphertextBlob in the object's Metadata
- Also include the cipher algorithm and decrypted encoding in the object's Metadata
- Get the object
- Get the CiphertextBlob from the object's Metadata
- Decrypt the CiphertextBlob using the KMS library (don't need the original KMS KeyId)
- Use the decrypted key plus the cipher algorithm and decrypted encoding (from the Metadata) to decrypt the object content
Since you sometimes need to manually upload encrypted objects to S3 manually (i.e. not using this library), there is a bash script included in the /bin folder that performs the "To encrypt" steps above: s3-put-encrypted.
I decided to keep the callback structure in line with the AWS SDK, to most closely match that API - even though I prefer Promises. If you'd like to use this library as Promises, it's up to you promisify it (as would would the AWS SDK).
I may be wrong, but it seems like the Java SDK for the S3 Encryption Client doesn't use a salt. This library matches that decision, mostly because the crypto Cipher/Decipher classes don't support a salt. It might be possible to support a salt using a different part of the crypto library, but it would require a major reworking of the flow because the KMS Data Key is base64 but openssl functions that use a salt require hex.
Copyright 2016 Gilt Groupe, Inc.
Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0