Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update JavaThemis Secure Cell API (#634)
* New API of Secure Cell Introduce new, interface-based API of Secure Cell. Current API has a number of issues described in RFC 3.9, notably the run-time mode setting and not-quite-secure support of String inputs which interferes with passphrase API. That's why we introduce a new interface which should rectify these issues. The users will deal with *interfaces* of the base SecureCell class: SecureCell.Seal, TokenProtect, ContextImprint. They will take into account differences in inputs and outputs of these modes. They also allow to introduce passphrase API which actually has the same API after the initialization. Using interfaces as opposed to classes allows us to hide unnecessary implementation details and do not expose the users to a number of classes that they don't actually need to interact with. This is also a nice point to start paying more attention to JavaDocs, with better descriptions of APIs and versioning. * Implement new Secure Cell API Add implementation of SecureCell interfaces. These are package-private classes constructed by static factory methods of the base class. They provide improved API with the similar behavior. The differences include naming and the fact that encryption code path no longer uses checked SecureCellException, instead wrapping it into unchecked RuntimeException. This is because encryption code path is unlikely to fail due to business errors as opposed to programming errors, so there is no need to enforce immediate error checking with checked exception. This is not true for decryption path. Note that native methods do not throw exceptions on their own right now. Instead they indicate errors by returning "null". This would be nice to get right later. * Nullability annotations Mark new interface methods with @NotNull and @nullable annotations where appropriate. This improves IDE experience and Kotlin integration. Contracts enable even more warnings in IDE. For example, all Secure Cell methods are pure (i.e., do not change the state of the cell itself). This allows IDE to warn about unused results of Secure Cell calls. Since we do not support Java 6 & 7, we can go with annotation library that requires Java 8+. Jetbrains have a compatbility version which supports earlier JVMs. * Test for new Secure Cell API Port Swift test suite to Java to check the new API. There are also tests for compatibility between the new and old API. These tests have uncovered a couple of warts in Themis Core implementation. We'll deal with them later. * Target Java 7 since that's what Android uses We require Java 8 for building with embedded Gradle wrapper, however Android still targets Java 7 by default at the moment. It is possible to build for Java 8, but that changes the requirements to JVM. We'd like to avoid cutting support unless we don't really need it. Make it explicit that we're building for Java 7 for Android, and build desktop Java code for Java 7 too. We use Java 7 features in the code so we cannot build with Java 6. That train is now gone. Also, change the annotation library to use the compatibility version which supports Java 7. * Use JUnit 3.x pattern to test for exceptions Unfortunately, we cannot use "assertThrows" which is so convenient. First of all, we can't use lambdas from Java 8. However, even if we use Runnable instead, JUnit wrapper on Android uses older JUnit which does not have "assertThrows" support in any form. Thus we fall back to ridiculously ugly, but working approach recommended by JUnit authors [1]. [1]: https://github.com/junit-team/junit4/wiki/Exception-testing Maybe when we bump the requirements to Java 8+ we could use better testing library API. But not today. * Ignore tests that crash Android runners These new tests are a pinata of crashes. They have discovered a serious bug in JNI code which crashes the process on Android if a corrupted Secure Cell is decrypted. Disable these tests for now so that we can proceed with other updates. They will be reenabled later, once the bug is fixed. * Polyfill base64 decoding It turns out that not all Android API levels support java.util.Base64 which appeared in Java 8. Since we build for Java 1.7, it's kinda wise to not rely on that API. Android has its own API for decoding base64, but we cannot use that for desktop Java. So choose neither and provide a polyfill with is API-compatible with java.util.Base64, implemented using an obscure Java API for processing XML which include base64 support as well. * Use Apache Commons for polyfill after all Unfortunately, DatatypeConverter is not available on Android too, so we have to use an external library. * Use older version of Common Codec library Unfortunately, we cannot use the latest version of the codec library because some Android systems (e.g., API 24) already include an older version of some of the Commons' classes. They are loaded before our dependencies fetched by Gradle and break the party. Investigation of Android source code shows that they're using what appears to be version 1.2 of the library (the current version is 1.14). Okay, so that limits us to the API provided by 1.2. Fine *sigh*
- Loading branch information