| .. | ||
| array_ref | ||
| array_view | ||
| ldt | ||
| ldt_np_adv | ||
| ldt_np_adv_ffi | ||
| ldt_np_adv_ffi_fuzz | ||
| ldt_np_c_sample | ||
| ldt_tbc | ||
| np_hkdf | ||
| rand_ext | ||
| test_helper | ||
| xts_aes | ||
| CMakeLists.txt | ||
| README.md | ||
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
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
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 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
cdto a crate's directorycargo fuzz listto list available fuzzerscargo 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-androidrustup target add aarch64-linux-android --toolchain nightly
-
Install the v22 NDK that still links against
libgccthe way rust's stdlib expects.- Newer NDKs use
libunwindinstead, 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'
- Newer NDKs use
-
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-clangexport 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
aescrate to use intrinsics on aarch64cargo +nightly build --workspace --all-targets --target aarch64-linux-androidcargo +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-dirin.cargo/config.tomlinitially, 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/
- Use whatever directory you configured as the
-
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
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 . 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).