-
Notifications
You must be signed in to change notification settings - Fork 144
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Secure Cell passphrase API: GoThemis #625
Conversation
Introduce a new constructor "SealWithPassphrase" which returns a different instance of Secure Cell that works with passphrases instead of symmetric keys, using appropriate Themis Core API. Note that we do not convert the string encoding here. Go's "string" type is expected to contain UTF-8 data (consistent with what other wrappers use). However, it can contain arbitrary byte sequences too. We do not interpret them in any way (e.g., as []rune or whatever) and just use the bytes as is.
// | ||
// https://docs.cossacklabs.com/pages/secure-cell-cryptosystem/#seal-mode | ||
type SecureCellSealPassphrase struct { | ||
passphrase string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, now I see, that it looks inefficient and we should provide a way to convert passphrase to key to allow cache this computation and not calculate key every time...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah. Here (and in other wrappers) we keep the original passphrase and pass it to C functions that actually perform KDF on every individual encryption or decryption.
It is straightforward, API-wise, to prederive key for encryption and cache it. However, it is not obvious how to handle decryption path which requires not only the passphrase but KDF parameters and salt as well, which both can be different for each message.
Our hope is that users would rarely need passphrase API to encrypt or decrypt massive amounts of data so some inefficiency is okay. If you are only going to use this API to encrypt a master key and then decrypt it relatively rarely then it's okay to pay KDF costs (~200 ms) every time you use this API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
imho we can perform kdf and correctly pass context to encryption function in our wrappers, cache generated key and re-use it. Add semi-private (exportable as C code, but not documented anywhere and used only by our wrappers instead users) functions. One, which perform kdf on passphrase and export kdf context + new key. And second, is function for encryption which accept kdf context and symmetric key, and put context to correct place. Then we can use it in our wrappers and store in object symmetric key instead passphrase.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this idea has been explored (RFC 2, “Detached key derivation”). However, it introduces a lot of open questions:
- API, ABI, data formats need to be backwards compatible
- decryption path seems to be optimizable only with user assistance
- making KDF parameters visible is not “simple” for users
- reusing KDF parameters for multiple messages may have security implications
Immediate benefits include improved performance when encrypting data with the same KDF parameters and a later option to configure KDF for the users.
Given our expectations, this will not improve main user story for passphrase API which we expect to be used relatively rare to decrypt some master secret or a single configuration. It is expected that passphrase API will not be used to decrypt a lot of data chunks (e.g., an passphrased AcraStructs for each individual database cell). With these assumptions caching KDF results is not going to win much performance.
We can introduce optimizations later while keeping high-level API unchanged. The idea is to flesh out passphrase API, get some user input, and then maybe optimize Themis Core requests we do to implement that API.
With preparatory changes in #624, this PR adds actual passphrase API as described in RFC 3.7 (with corrections).
User notes
Passphrase-based interface of Secure Cell allows you to use short and memorable passphrases to secure your data. While symmetric keys are more secure, they are also longer and much harder for humans to remember.
Here is how you can use passphrases with Secure Cell in Go:
Passphrase API accepts passphrases as relatively short strings, suitable for human memory. Master key API uses randomly generated, long binary keys, which are more suitable for machines to remember. However, they are also much more efficient and generally more secure due to considerable length. You should prefer to use keys over passphrases if there are no humans involved. The interface is almost the same:
Technical notes
The only deviation from RFC 3.7 is that the “associated context” argument is now required (syntactically). Go does not support method overloading so it’s not possible to omit it when calling Secure Cell methods. If you do not wish to use additional associated context for encryption, pass
nil
or empty slice as context.Checklist
Benchmark results are attached(no specific benchmarks for Go)