-
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: JavaThemis #635
Conversation
Add a new mode -- MODE_SEAL_PASSPHRASE -- to support Seal encryption mode secured by passphrase. We do not introduce new API to JNI library to keep ABI compatibility. Since the cost of doing JNI call is already that high, it does not win us anything to use static mode-setting. It makes sense to refactor Java API, but changing this JNI API does not affect the users so it will be mostly a waste. Note that Java constant is package-private. We don't want users to use it with the old API because it will be extremely confusing. The old API will accept strings, but it will encode them in UTF-16 by default which is not what the new passphrase API does. Therefore we keep the constant private. The old constants are getting deprecated too later.
Add a new package-private class SecureCellSealWithPassphrase which implements SecureCell.Seal interface, but with passphrases instead of symmetric keys. The new class can be instantiated with SecureCell#SealWithPassphrase methods that accept a variety of inputs. Normally the String interface should be used to get compatible behavior. Other interfaces can be used if you need some non-UTF-8 encoding for the passphrase, or if you're doing something weird. We need to store the passphrase bytes somewhere. A new helper class -- PassphraseBytes -- is added for that. It extends KeyBytes to implement IKey interface and holds the sensitive data for us. It also hosts the encodinng conversion routine. We cannot use the standard String#getBytes because it replaces unknow characters with ?, leading to unexpected and not really portable behavior.
Once again, for the most part this is rewrite of Swift test suite into Java. However, it has been augmented with some Java-specific tests to verify that we handle the old 'passphrase-like' API in a sane way.
Whew, this PR is ready for review now. |
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.
lgtm
@Test | ||
public void defaultEncoding() throws SecureCellException { | ||
// Passphrases are encoded in UTF-8 by default. | ||
String 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.
cipher!
try { | ||
// It is an error if the passphrase cannot be represented in the requested charset | ||
// without data loss. | ||
SecureCell.SealWithPassphrase("пароль", StandardCharsets.US_ASCII); |
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.
so here we test that this method will fail if receive inconsistent string and encoding?
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.
so here we test that this method will fail if receive inconsistent string and encoding?
Yeah, that's the idea behind this test.
PassphraseBytes#encodePassphrase
is not directly tested, but here we ensure that it's actually used, not String#getBytes
(which would have turned "пароль"
into "??????"
here). Encoding conversion happy path is indirectly verified by other passphrase tests.
With preparatory changes in #634, this PR adds actual passphrase API as described in RFC 3.9.
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 Kotlin:
And the same API in Java:
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:
Unicode considerations
Note that passphrase API uses UTF-8 by default for compatibility with other platforms. If you need to use a different encoding, there are variety of interfaces to allow that:
SecureCell#SealWithPassphrase(String)
— use UTF-8, the defaultSecureCell#SealWithPassphrase(String, Charset)
— use the specified charsetSecureCell#SealWithPassphrase(byte[])
— in case you already have it encodedTechnical notes
There are no deviations from RFC 3.9 with respect to passphrase API.
We introduce a new helper –
PassphraseBytes
– and extend the JNI API to support passphrases.Checklist
Benchmark results are attached(no JVM benches)Example projects and code samples are up-to-date(later)