242 lines
8.2 KiB
Markdown
242 lines
8.2 KiB
Markdown
# What is this?
|
|
|
|
Implementations of XTS and LDT for Nearby Presence "v0" advertisements.
|
|
|
|
See the appendix below for more details on XTS and LDT.
|
|
|
|
## Project structure
|
|
*Note all new crates follow the convention of using underscore `_` instead of hyphen `-` in crate names
|
|
|
|
### `ldt`
|
|
|
|
An implementation
|
|
of [`LDT`](https://luca-giuzzi.unibs.it/corsi/Support/papers-cryptography/1619-2007-NIST-Submission.pdf)
|
|
which can use `xts-aes` as its tweakable block cipher.
|
|
|
|
### `ldt_tbc`
|
|
|
|
The Tweakable Block Cipher traits for use in LDT. These traits have implementations in the `xts_aes`
|
|
|
|
### `ldt_np_adv`
|
|
|
|
Higher-level wrapper around the core LDT algorithm that does key derivation and
|
|
payload validation the way Nearby Presence advertisements need.
|
|
|
|
### `ldt_np_adv_ffi`
|
|
|
|
C API for rust library, currently exposes C/C++ clients the needed API's to use the NP specific LDT rust implementation.
|
|
For an example of how to integrate with these API's see program in `ldt_np_c_sample`
|
|
|
|
### `ldt_np_c_sample`
|
|
|
|
Sample c program which provides its own OpenSSL based AES implementation to encrypt data through the LDT rust implementation
|
|
An example of how to interface with the `ldt_np_adv_ffi` API's
|
|
|
|
### `np_hkdf`
|
|
|
|
The Key Derivation functions used for creating keys used by nearby presence from a key_seed
|
|
|
|
### `xts_aes`
|
|
|
|
An implementation
|
|
of [`XTS-AES`](https://luca-giuzzi.unibs.it/corsi/Support/papers-cryptography/1619-2007-NIST-Submission.pdf)
|
|
|
|
|
|
## Setup for MacOS local development
|
|
|
|
Dependencies:
|
|
|
|
```
|
|
brew install protobuf rapidjson google-benchmark
|
|
```
|
|
|
|
We depend on OpenSSL of version at least 3.0.5 being installed on your machine to build the fuzzers, for macOS run:
|
|
|
|
```
|
|
brew install openssl@3
|
|
```
|
|
|
|
Your build system may still be picking up an older version so you will have to symlink to the brew installed version:
|
|
```
|
|
brew link --force openssl
|
|
```
|
|
|
|
The in-box version of Clang which comes from XCode developer tools does not have a fuzzer runtime so we will have to use our own
|
|
```
|
|
brew install llvm
|
|
```
|
|
then to override the default version it needs to come before it in $PATH. first find your path:
|
|
```
|
|
$(brew --prefix llvm)/bin
|
|
```
|
|
then add this to the beginning of your path
|
|
```
|
|
echo 'export PATH="/opt/homebrew/opt/llvm/bin:$PATH"' >> ~/.bash_profile
|
|
export PATH="/opt/homebrew/opt/llvm/bin:$PATH"
|
|
```
|
|
verify success with:
|
|
```
|
|
clang --version
|
|
```
|
|
it should display the path to the homebrew version and not the xcode version.
|
|
|
|
Some other dependencies you may need include:
|
|
```
|
|
brew install ninja bindgen
|
|
```
|
|
|
|
## Examples
|
|
|
|
Examples use [clap](https://docs.rs/clap/latest/clap/) for nice CLIs, so try
|
|
running with `--help` to see all args.
|
|
|
|
*Note:* the examples are in the `ldt` crate, so `cd` into that first.
|
|
|
|
### `ldt_prp`
|
|
|
|
Confirm that LDT is, in fact, behaving as a PRP. That is, flipping one bit in
|
|
the ciphertext is on average going to flip half of the bits in the decrypted
|
|
plaintext, and that a change to the first `n` bytes of plaintext is increasingly
|
|
likely to be detected as `n` increases.
|
|
|
|
```
|
|
cargo run --release --example ldt_prp -- \
|
|
--trials 1000000 \
|
|
--check-leading-bytes 16
|
|
```
|
|
|
|
### `ldt_benchmark`
|
|
|
|
For interactive exploration of LDT performance looking for a needle in a
|
|
haystack of ciphertexts.
|
|
|
|
```
|
|
cargo run --release --example ldt_benchmark -- \
|
|
--trials 500 \
|
|
--keys 1000
|
|
```
|
|
|
|
### `ldt_np_c_sample`
|
|
From the root directory run the following commands to build and run the C sample.
|
|
|
|
```
|
|
mkdir -p cmake-build && cd cmake-build
|
|
cmake ..
|
|
make
|
|
./ldt_np_c_sample/sample
|
|
```
|
|
|
|
### `ldt_np_c_sample/tests`
|
|
Test cases for the ldt_np_adv_ffi C API which are built alongside the sample, use the following commands to run the tests, from root of repo:
|
|
|
|
```
|
|
mkdir -p cmake-build && cd cmake-build
|
|
cmake .. -DENABLE_TESTS=TRUE
|
|
make
|
|
cd ldt_np_c_sample/tests && ctest
|
|
```
|
|
you can then view the output of the tests in `ldt_np_c_sample/tests/Testing/Temporary/LastTest.log`
|
|
|
|
To run the benchmarks:
|
|
|
|
`ldt_np_c_sample/tests/benchmarks`
|
|
|
|
## Fuzzing
|
|
|
|
To build all the fuzzers, run `scripts/build-fuzzers.sh`.
|
|
|
|
### Rust
|
|
|
|
Crates with fuzzers: `ldt`, `ldt_np_adv`, `xts_aes`
|
|
|
|
- `cd` to a crate's directory
|
|
- `cargo fuzz list` to list available fuzzers
|
|
- `cargo fuzz run [fuzzer name]` to run a fuzzer
|
|
|
|
### C
|
|
|
|
Build w/ cmake as per `ldt_np_c_sample` instructions. Fuzzers will be in `np_ffi_fuzz` in the build directory.
|
|
|
|
## Cross-compilation for Android
|
|
|
|
- Add the 64bit ARM target to the stable and nightly toolchains:
|
|
- `rustup target add aarch64-linux-android`
|
|
- `rustup target add aarch64-linux-android --toolchain nightly`
|
|
|
|
- Install the v22 NDK that still links against `libgcc` the way rust's stdlib
|
|
expects.
|
|
- Newer NDKs use `libunwind` instead, which can be used just fine if you
|
|
build your own rust stdlib, but for our purposes there's no problem with
|
|
just using NDK 22
|
|
- `./sdkmanager --install platform-tools 'ndk;22.0.7026061'`
|
|
|
|
- Configure the linker used for the ARMv8 Android target to be the NDK's linker.
|
|
- `export CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER=$ANDROID_HOME/ndk/22.0.7026061/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android30-clang`
|
|
- `export PKG_CONFIG_SYSROOT_DIR=$ANDROID_HOME/ndk/22.0.7026061/toolchains/llvm/prebuilt/linux-x86_64/sysroot`
|
|
|
|
- See if everything builds, using the nightly toolchain for the moment to
|
|
convince the `aes` crate to use intrinsics on aarch64
|
|
- `cargo +nightly build --workspace --all-targets --target aarch64-linux-android`
|
|
- `cargo +nightly bench --workspace --no-run --target aarch64-linux-android`
|
|
|
|
- Prepare a place for the benchmark to be on the phone
|
|
|
|
- `adb shell`
|
|
- then
|
|
- `mkdir -p /data/local/tmp/np && cd /data/local/tmp/np`
|
|
- Leave the shell on the phone open so you can use it to run the benchmark.
|
|
|
|
- Find the benchmark binary in the build products
|
|
|
|
- Use whatever directory you configured as the `target-dir` in
|
|
`.cargo/config.toml` initially, and look for the file without the
|
|
trailing `.d`.
|
|
- `find TARGET_DIR -name 'ldt_scan*' | grep android`
|
|
- Copy the file to the phone
|
|
- `adb push FILE_FOUND_ABOVE /data/local/tmp/np/`
|
|
|
|
- In your `adb shell`, run the benchmark
|
|
|
|
- `./ldt_scan-... --bench`
|
|
### Building min-sized release cross-compiled for Android
|
|
- Copy and paste the following into your `~/.cargo/config.toml`, replacing with a path to your NDK and Host OS
|
|
```
|
|
[target.aarch64-linux-android]
|
|
# Replace this with a path to your ndk version and the prebuilt toolchain for your Host OS
|
|
linker = "Library/Android/sdk/ndk/23.2.8568313/toolchains/llvm/prebuilt/darwin-x86_64/bin/aarch64-linux-android21-clang"
|
|
```
|
|
- then run:
|
|
`cargo +nightly build -Z build-std=core,alloc -Z build-std-features=panic_immediate_abort --target aarch64-linux-android --profile release-min-size`
|
|
|
|
## Appendix
|
|
|
|
### XTS
|
|
|
|
XTS-AES has a NIST
|
|
spec: [The XTS-AES Tweakable Block Cipher - An Extract from IEEE Std 1619-2007](https://luca-giuzzi.unibs.it/corsi/Support/papers-cryptography/1619-2007-NIST-Submission.pdf)
|
|
|
|
XTS is a scheme for turning a block cipher (AES in this case) into a _tweakable_
|
|
block cipher. Tweakable block ciphers incorporate a _tweak_ which is cheaper to
|
|
change than the key, with the assumption being that the tweak will change with
|
|
each block or sequence of blocks. XTS-AES in particular is used in disk
|
|
encryption, where the sector number or the like might be incorporated into the
|
|
tweak to prevent the same data in different places on the disk being encrypted
|
|
into the same ciphertext.
|
|
|
|
### LDT
|
|
|
|
LDT is the current state of the art in length
|
|
doublers: [Efficient Length Doubling From Tweakable Block Ciphers](https://eprint.iacr.org/2017/841.pdf)
|
|
. It builds on top of a tweakable block cipher, which is why we also have an XTS
|
|
implementation.
|
|
|
|
A length doubler is a way of adapting a block cipher to act as a secure PRP (
|
|
pseudo random permutation) on data of lengths in `[block size, 2 * block size)`.
|
|
For comparison, block ciphers act as PRPs on one block at a time rather than the
|
|
whole message. Wide block modes would also work, but have higher overhead.
|
|
|
|
We use a length doubler in Nearby Presence so that changing any ciphertext bit
|
|
should flip each bit in the decrypted plaintext with 50% probability for each
|
|
bit, making it possible to detect changes anywhere because it is very unlikely
|
|
for none of the bit flips to affect the metadata key (which has a known digest).
|